@myhpmp/cli 1.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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +156 -0
  3. package/README.md +156 -0
  4. package/dist/adapter/claude-adapter.d.ts +9 -0
  5. package/dist/adapter/claude-adapter.js +36 -0
  6. package/dist/adapter/claude-adapter.js.map +1 -0
  7. package/dist/adapter/codex-adapter.d.ts +14 -0
  8. package/dist/adapter/codex-adapter.js +84 -0
  9. package/dist/adapter/codex-adapter.js.map +1 -0
  10. package/dist/adapter/index.d.ts +6 -0
  11. package/dist/adapter/index.js +18 -0
  12. package/dist/adapter/index.js.map +1 -0
  13. package/dist/adapter/provider.d.ts +23 -0
  14. package/dist/adapter/provider.js +6 -0
  15. package/dist/adapter/provider.js.map +1 -0
  16. package/dist/auth/auth-manager.d.ts +15 -0
  17. package/dist/auth/auth-manager.js +34 -0
  18. package/dist/auth/auth-manager.js.map +1 -0
  19. package/dist/auth/oauth.d.ts +6 -0
  20. package/dist/auth/oauth.js +113 -0
  21. package/dist/auth/oauth.js.map +1 -0
  22. package/dist/cli.d.ts +4 -0
  23. package/dist/cli.js +46 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/commands/init.d.ts +1 -0
  26. package/dist/commands/init.js +116 -0
  27. package/dist/commands/init.js.map +1 -0
  28. package/dist/commands/locale.d.ts +1 -0
  29. package/dist/commands/locale.js +40 -0
  30. package/dist/commands/locale.js.map +1 -0
  31. package/dist/commands/setup.d.ts +1 -0
  32. package/dist/commands/setup.js +137 -0
  33. package/dist/commands/setup.js.map +1 -0
  34. package/dist/commands/statusline-toggle.d.ts +1 -0
  35. package/dist/commands/statusline-toggle.js +61 -0
  36. package/dist/commands/statusline-toggle.js.map +1 -0
  37. package/dist/commands/sync.d.ts +1 -0
  38. package/dist/commands/sync.js +29 -0
  39. package/dist/commands/sync.js.map +1 -0
  40. package/dist/commands/usage.d.ts +1 -0
  41. package/dist/commands/usage.js +56 -0
  42. package/dist/commands/usage.js.map +1 -0
  43. package/dist/config.d.ts +2 -0
  44. package/dist/config.js +35 -0
  45. package/dist/config.js.map +1 -0
  46. package/dist/core/exp-calculator.d.ts +1 -0
  47. package/dist/core/exp-calculator.js +3 -0
  48. package/dist/core/exp-calculator.js.map +1 -0
  49. package/dist/core/level-system.d.ts +2 -0
  50. package/dist/core/level-system.js +3 -0
  51. package/dist/core/level-system.js.map +1 -0
  52. package/dist/core/stats-aggregator.d.ts +5 -0
  53. package/dist/core/stats-aggregator.js +35 -0
  54. package/dist/core/stats-aggregator.js.map +1 -0
  55. package/dist/data/auto-sync.d.ts +8 -0
  56. package/dist/data/auto-sync.js +75 -0
  57. package/dist/data/auto-sync.js.map +1 -0
  58. package/dist/data/claude-usage.d.ts +13 -0
  59. package/dist/data/claude-usage.js +82 -0
  60. package/dist/data/claude-usage.js.map +1 -0
  61. package/dist/data/exp-logger.d.ts +1 -0
  62. package/dist/data/exp-logger.js +43 -0
  63. package/dist/data/exp-logger.js.map +1 -0
  64. package/dist/data/local-store.d.ts +16 -0
  65. package/dist/data/local-store.js +41 -0
  66. package/dist/data/local-store.js.map +1 -0
  67. package/dist/data/pending-exp.d.ts +8 -0
  68. package/dist/data/pending-exp.js +42 -0
  69. package/dist/data/pending-exp.js.map +1 -0
  70. package/dist/data/providers/db-interface.d.ts +11 -0
  71. package/dist/data/providers/db-interface.js +2 -0
  72. package/dist/data/providers/db-interface.js.map +1 -0
  73. package/dist/data/providers/supabase.d.ts +16 -0
  74. package/dist/data/providers/supabase.js +84 -0
  75. package/dist/data/providers/supabase.js.map +1 -0
  76. package/dist/data/sync-engine.d.ts +15 -0
  77. package/dist/data/sync-engine.js +67 -0
  78. package/dist/data/sync-engine.js.map +1 -0
  79. package/dist/display/detail-view.d.ts +23 -0
  80. package/dist/display/detail-view.js +36 -0
  81. package/dist/display/detail-view.js.map +1 -0
  82. package/dist/display/status-line.d.ts +12 -0
  83. package/dist/display/status-line.js +17 -0
  84. package/dist/display/status-line.js.map +1 -0
  85. package/dist/hooks/claude/post-tool-use.d.ts +1 -0
  86. package/dist/hooks/claude/post-tool-use.js +82 -0
  87. package/dist/hooks/claude/post-tool-use.js.map +1 -0
  88. package/dist/hooks/claude/session-end.d.ts +1 -0
  89. package/dist/hooks/claude/session-end.js +23 -0
  90. package/dist/hooks/claude/session-end.js.map +1 -0
  91. package/dist/hooks/claude/status-line-updater.d.ts +1 -0
  92. package/dist/hooks/claude/status-line-updater.js +48 -0
  93. package/dist/hooks/claude/status-line-updater.js.map +1 -0
  94. package/dist/hooks/codex/session-end.d.ts +1 -0
  95. package/dist/hooks/codex/session-end.js +40 -0
  96. package/dist/hooks/codex/session-end.js.map +1 -0
  97. package/dist/hooks/common/session-start.d.ts +1 -0
  98. package/dist/hooks/common/session-start.js +34 -0
  99. package/dist/hooks/common/session-start.js.map +1 -0
  100. package/dist/i18n/en.d.ts +26 -0
  101. package/dist/i18n/en.js +26 -0
  102. package/dist/i18n/en.js.map +1 -0
  103. package/dist/i18n/index.d.ts +7 -0
  104. package/dist/i18n/index.js +30 -0
  105. package/dist/i18n/index.js.map +1 -0
  106. package/dist/i18n/ko.d.ts +26 -0
  107. package/dist/i18n/ko.js +26 -0
  108. package/dist/i18n/ko.js.map +1 -0
  109. package/dist/index.d.ts +1 -0
  110. package/dist/index.js +2 -0
  111. package/dist/index.js.map +1 -0
  112. package/dist/statusline.d.ts +2 -0
  113. package/dist/statusline.js +103 -0
  114. package/dist/statusline.js.map +1 -0
  115. package/package.json +55 -0
@@ -0,0 +1,84 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ export class SupabaseProvider {
3
+ client;
4
+ constructor(url, anonKey) {
5
+ this.client = createClient(url, anonKey);
6
+ }
7
+ getClient() {
8
+ return this.client;
9
+ }
10
+ async setSession(accessToken, refreshToken) {
11
+ const { error } = await this.client.auth.setSession({
12
+ access_token: accessToken,
13
+ refresh_token: refreshToken,
14
+ });
15
+ if (error)
16
+ throw new Error(`Failed to set session: ${error.message}`);
17
+ }
18
+ async refreshSession(refreshToken) {
19
+ const { data, error } = await this.client.auth.refreshSession({ refresh_token: refreshToken });
20
+ if (error || !data.session)
21
+ return null;
22
+ return {
23
+ accessToken: data.session.access_token,
24
+ refreshToken: data.session.refresh_token,
25
+ };
26
+ }
27
+ async loadUserStats(userId) {
28
+ const { data, error } = await this.client
29
+ .from('user_stats')
30
+ .select('*')
31
+ .eq('user_id', userId)
32
+ .single();
33
+ if (error || !data)
34
+ return null;
35
+ const totalExp = Number(data.total_exp) || 0;
36
+ const level = Number(data.level) || 1;
37
+ const totalSessions = Number(data.total_sessions) || 0;
38
+ const streakDays = Number(data.streak_days) || 0;
39
+ if (totalExp < 0 || level < 1 || totalSessions < 0 || streakDays < 0) {
40
+ throw new Error('Invalid data from remote: negative values detected');
41
+ }
42
+ return {
43
+ totalExp,
44
+ level,
45
+ totalSessions,
46
+ streakDays,
47
+ lastActiveDate: data.last_active_date ? String(data.last_active_date) : null,
48
+ weeklyExpBonusClaimed: Boolean(data.weekly_exp_bonus_claimed),
49
+ updatedAt: data.updated_at ? String(data.updated_at) : new Date().toISOString(),
50
+ };
51
+ }
52
+ async saveUserStats(userId, stats) {
53
+ const { error } = await this.client
54
+ .from('user_stats')
55
+ .upsert({
56
+ user_id: userId,
57
+ total_exp: stats.totalExp,
58
+ level: stats.level,
59
+ total_sessions: stats.totalSessions,
60
+ streak_days: stats.streakDays,
61
+ last_active_date: stats.lastActiveDate,
62
+ weekly_exp_bonus_claimed: stats.weeklyExpBonusClaimed,
63
+ updated_at: stats.updatedAt,
64
+ });
65
+ if (error)
66
+ throw new Error(`Supabase save failed: ${error.message}`);
67
+ }
68
+ async insertExpHistory(userId, entry) {
69
+ const row = {
70
+ user_id: userId,
71
+ amount: entry.amount,
72
+ reason: entry.reason,
73
+ };
74
+ if (entry.metadata) {
75
+ row.metadata = entry.metadata;
76
+ }
77
+ const { error } = await this.client
78
+ .from('exp_history')
79
+ .insert(row);
80
+ if (error)
81
+ throw new Error(`exp_history insert failed: ${error.message}`);
82
+ }
83
+ }
84
+ //# sourceMappingURL=supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../../src/data/providers/supabase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { LocalStore, UserStats } from './local-store.js';
2
+ import type { DbProvider } from './providers/db-interface.js';
3
+ export declare class SyncEngine {
4
+ private local;
5
+ private remote;
6
+ constructor(local: LocalStore, remote: DbProvider);
7
+ /** Flush pending exp queue to remote exp_history */
8
+ flushPendingExp(userId: string): Promise<void>;
9
+ /** Pull remote stats to local (server is always the source of truth) */
10
+ pull(userId: string): Promise<UserStats | null>;
11
+ /** Push metadata only (streakDays, totalSessions, lastActiveDate) — NOT totalExp */
12
+ pushMetadata(userId: string): Promise<void>;
13
+ /** Full sync: flush queue → push metadata → pull (server totalExp is truth) */
14
+ sync(userId: string): Promise<UserStats>;
15
+ }
@@ -0,0 +1,67 @@
1
+ import { getLevelInfo } from '../core/level-system.js';
2
+ import { loadQueue, saveQueue } from './pending-exp.js';
3
+ export class SyncEngine {
4
+ local;
5
+ remote;
6
+ constructor(local, remote) {
7
+ this.local = local;
8
+ this.remote = remote;
9
+ }
10
+ /** Flush pending exp queue to remote exp_history */
11
+ async flushPendingExp(userId) {
12
+ const queue = await loadQueue();
13
+ if (queue.length === 0)
14
+ return;
15
+ for (const entry of queue) {
16
+ try {
17
+ await this.remote.insertExpHistory(userId, {
18
+ amount: entry.amount,
19
+ reason: entry.reason,
20
+ });
21
+ }
22
+ catch {
23
+ // Rate limit or constraint violation — discard silently
24
+ // (duplicate streak_bonus, daily cap, etc.)
25
+ }
26
+ }
27
+ await saveQueue([]);
28
+ }
29
+ /** Pull remote stats to local (server is always the source of truth) */
30
+ async pull(userId) {
31
+ const remote = await this.remote.loadUserStats(userId);
32
+ if (remote) {
33
+ remote.level = getLevelInfo(remote.totalExp).level;
34
+ await this.local.save(remote);
35
+ }
36
+ return remote;
37
+ }
38
+ /** Push metadata only (streakDays, totalSessions, lastActiveDate) — NOT totalExp */
39
+ async pushMetadata(userId) {
40
+ const local = await this.local.load();
41
+ const remote = await this.remote.loadUserStats(userId);
42
+ if (!remote)
43
+ return;
44
+ // Only update metadata fields, preserve server-computed totalExp
45
+ await this.remote.saveUserStats(userId, {
46
+ ...remote,
47
+ streakDays: Math.max(local.streakDays, remote.streakDays),
48
+ totalSessions: Math.max(local.totalSessions, remote.totalSessions),
49
+ lastActiveDate: local.lastActiveDate && remote.lastActiveDate
50
+ ? local.lastActiveDate > remote.lastActiveDate ? local.lastActiveDate : remote.lastActiveDate
51
+ : local.lastActiveDate || remote.lastActiveDate,
52
+ weeklyExpBonusClaimed: local.weeklyExpBonusClaimed || remote.weeklyExpBonusClaimed,
53
+ updatedAt: new Date().toISOString(),
54
+ });
55
+ }
56
+ /** Full sync: flush queue → push metadata → pull (server totalExp is truth) */
57
+ async sync(userId) {
58
+ await this.flushPendingExp(userId);
59
+ await this.pushMetadata(userId);
60
+ const remote = await this.pull(userId);
61
+ if (remote)
62
+ return remote;
63
+ // No remote data — return local defaults
64
+ return this.local.load();
65
+ }
66
+ }
67
+ //# sourceMappingURL=sync-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-engine.js","sourceRoot":"","sources":["../../src/data/sync-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface DetailViewData {
2
+ titleEmoji: string;
3
+ titleName: string;
4
+ level: number;
5
+ stars: number;
6
+ hpPercent: number;
7
+ hpUsed: number;
8
+ hpTotal: number;
9
+ resetMinutes: number;
10
+ mpPercent: number;
11
+ mpUsed: number;
12
+ mpTotal: number;
13
+ ctxPercent: number;
14
+ ctxUsed: number;
15
+ ctxTotal: number;
16
+ expCurrent: number;
17
+ expNeeded: number;
18
+ nextLevel: number;
19
+ totalExp: number;
20
+ totalSessions: number;
21
+ streakDays: number;
22
+ }
23
+ export declare function renderDetailView(data: DetailViewData, locale: string): string;
@@ -0,0 +1,36 @@
1
+ import { formatTime } from '../core/stats-aggregator.js';
2
+ function progressBar(percent, width = 10) {
3
+ const clamped = Math.max(0, Math.min(100, percent));
4
+ const filled = Math.round((clamped / 100) * width);
5
+ const empty = width - filled;
6
+ return '█'.repeat(filled) + '░'.repeat(empty);
7
+ }
8
+ function formatTokens(n) {
9
+ if (n >= 1_000_000)
10
+ return `${(n / 1_000_000).toFixed(1)}M`;
11
+ if (n >= 1_000)
12
+ return `${(n / 1_000).toFixed(0)}K`;
13
+ return String(n);
14
+ }
15
+ export function renderDetailView(data, locale) {
16
+ const ko = locale === 'ko';
17
+ const starsStr = '★'.repeat(data.stars);
18
+ const time = formatTime(data.resetMinutes);
19
+ const dayUnit = ko ? '일' : 'd';
20
+ const sessionsUnit = ko ? '회' : 'sessions';
21
+ const sep = '━'.repeat(43);
22
+ const header = `🎮 ${data.titleEmoji} ${data.titleName} Lv.${data.level} ${starsStr}`;
23
+ const streakLabel = `🔥 ${ko ? '연속' : 'Streak'}: ${data.streakDays}${dayUnit}`;
24
+ const lines = [
25
+ `${header} ${streakLabel}`,
26
+ sep,
27
+ `❤️ HP ${progressBar(data.hpPercent)} ${String(data.hpPercent).padStart(3)}% ⏱️ ${time}`,
28
+ `💙 MP ${progressBar(data.mpPercent)} ${String(data.mpPercent).padStart(3)}%`,
29
+ `🧠 CTX ${progressBar(data.ctxPercent)} ${String(data.ctxPercent).padStart(3)}% (${formatTokens(data.ctxUsed)} / ${formatTokens(data.ctxTotal)} context)`,
30
+ `⭐ EXP ${progressBar(Math.round((data.expCurrent / data.expNeeded) * 100))} ${String(Math.round((data.expCurrent / data.expNeeded) * 100)).padStart(3)}% (${data.expCurrent} / ${data.expNeeded} → Lv.${data.nextLevel})`,
31
+ sep,
32
+ `📊 ${ko ? '총 누적 EXP' : 'Total EXP'}: ${data.totalExp.toLocaleString()} | ${ko ? '총 세션' : 'Total Sessions'}: ${data.totalSessions} ${sessionsUnit}`,
33
+ ];
34
+ return lines.join('\n');
35
+ }
36
+ //# sourceMappingURL=detail-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detail-view.js","sourceRoot":"","sources":["../../src/display/detail-view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface StatusLineData {
2
+ titleEmoji: string;
3
+ titleName: string;
4
+ level: number;
5
+ stars: number;
6
+ hpPercent: number;
7
+ resetMinutes: number;
8
+ mpPercent: number;
9
+ ctxPercent: number;
10
+ streakDays: number;
11
+ }
12
+ export declare function renderStatusLine(data: StatusLineData, locale: string): string;
@@ -0,0 +1,17 @@
1
+ import { formatTime } from '../core/stats-aggregator.js';
2
+ export function renderStatusLine(data, locale) {
3
+ const starsStr = '★'.repeat(data.stars);
4
+ const time = formatTime(data.resetMinutes);
5
+ const dayUnit = locale === 'ko' ? '일' : 'd';
6
+ const hpPart = data.resetMinutes > 0
7
+ ? `❤️ ${data.hpPercent}% ⏱️${time}`
8
+ : `❤️ ${data.hpPercent}%`;
9
+ return [
10
+ `${data.titleEmoji} ${data.titleName} Lv.${data.level} ${starsStr}`,
11
+ hpPart,
12
+ `💙 ${data.mpPercent}%`,
13
+ `🧠 ${data.ctxPercent}%`,
14
+ `🔥${data.streakDays}${dayUnit}`,
15
+ ].join(' | ');
16
+ }
17
+ //# sourceMappingURL=status-line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-line.js","sourceRoot":"","sources":["../../src/display/status-line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAczD,MAAM,UAAU,gBAAgB,CAC9B,IAAoB,EACpB,MAAc;IAEd,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE5C,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC;QAClC,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,OAAO,IAAI,EAAE;QACnC,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,GAAG,CAAC;IAE5B,OAAO;QACL,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,OAAO,IAAI,CAAC,KAAK,IAAI,QAAQ,EAAE;QACnE,MAAM;QACN,MAAM,IAAI,CAAC,SAAS,GAAG;QACvB,MAAM,IAAI,CAAC,UAAU,GAAG;QACxB,KAAK,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE;KACjC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,82 @@
1
+ import { LocalStore } from '../../data/local-store.js';
2
+ import { calcTokenExp } from '../../core/exp-calculator.js';
3
+ import { getLevelInfo } from '../../core/level-system.js';
4
+ import { autoSyncIfDue } from '../../data/auto-sync.js';
5
+ import { logExp } from '../../data/exp-logger.js';
6
+ import fs from 'node:fs/promises';
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ const DATA_DIR = path.join(os.homedir(), '.myhpmp');
10
+ const MAX_INPUT_SIZE = 1_000_000; // 1MB
11
+ const LAST_TOKENS_PATH = path.join(DATA_DIR, 'last-tokens.json');
12
+ async function getLastTokenCount() {
13
+ try {
14
+ const raw = await fs.readFile(LAST_TOKENS_PATH, 'utf-8');
15
+ return Number(JSON.parse(raw).tokens) || 0;
16
+ }
17
+ catch {
18
+ return 0;
19
+ }
20
+ }
21
+ async function saveLastTokenCount(tokens) {
22
+ await fs.writeFile(LAST_TOKENS_PATH, JSON.stringify({ tokens }), 'utf-8');
23
+ }
24
+ async function main() {
25
+ let input = '';
26
+ for await (const chunk of process.stdin) {
27
+ input += chunk;
28
+ if (input.length > MAX_INPUT_SIZE)
29
+ return;
30
+ }
31
+ const hookData = JSON.parse(input);
32
+ const transcriptPath = hookData?.transcript_path;
33
+ if (!transcriptPath)
34
+ return;
35
+ // Read the last line of transcript to get current total tokens
36
+ let currentTotal = 0;
37
+ try {
38
+ const content = await fs.readFile(transcriptPath, 'utf-8');
39
+ const lines = content.trimEnd().split('\n');
40
+ // Search from end for last usage entry
41
+ for (let i = lines.length - 1; i >= 0; i--) {
42
+ try {
43
+ const entry = JSON.parse(lines[i]);
44
+ const usage = entry?.usage;
45
+ if (usage?.input_tokens !== undefined) {
46
+ currentTotal = (usage.input_tokens || 0) + (usage.output_tokens || 0);
47
+ break;
48
+ }
49
+ }
50
+ catch {
51
+ // Skip malformed lines
52
+ }
53
+ }
54
+ }
55
+ catch {
56
+ return;
57
+ }
58
+ if (currentTotal <= 0)
59
+ return;
60
+ const previousTotal = await getLastTokenCount();
61
+ await saveLastTokenCount(currentTotal);
62
+ // First call in session — no delta to calculate
63
+ if (previousTotal === 0)
64
+ return;
65
+ const deltaTokens = currentTotal - previousTotal;
66
+ if (deltaTokens <= 0)
67
+ return;
68
+ const exp = Math.min(calcTokenExp(deltaTokens), 1000);
69
+ if (exp <= 0)
70
+ return;
71
+ const store = new LocalStore(DATA_DIR);
72
+ const stats = await store.load();
73
+ stats.totalExp += exp;
74
+ stats.level = getLevelInfo(stats.totalExp).level;
75
+ stats.updatedAt = new Date().toISOString();
76
+ await store.save(stats);
77
+ await logExp(exp, 'token_usage', { tokens: deltaTokens, provider: 'claude' });
78
+ // Sync every 5 minutes
79
+ await autoSyncIfDue();
80
+ }
81
+ main().catch(console.error);
82
+ //# sourceMappingURL=post-tool-use.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-tool-use.js","sourceRoot":"","sources":["../../../src/hooks/claude/post-tool-use.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import { LocalStore } from '../../data/local-store.js';
2
+ import { calcSessionExp } from '../../core/exp-calculator.js';
3
+ import { getLevelInfo } from '../../core/level-system.js';
4
+ import { autoSync } from '../../data/auto-sync.js';
5
+ import { logExp } from '../../data/exp-logger.js';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ const DATA_DIR = path.join(os.homedir(), '.myhpmp');
9
+ async function main() {
10
+ const store = new LocalStore(DATA_DIR);
11
+ const stats = await store.load();
12
+ const sessionExp = calcSessionExp();
13
+ stats.totalSessions += 1;
14
+ stats.totalExp += sessionExp;
15
+ stats.level = getLevelInfo(stats.totalExp).level;
16
+ stats.updatedAt = new Date().toISOString();
17
+ await store.save(stats);
18
+ await logExp(sessionExp, 'session_complete', { provider: 'claude' });
19
+ // Push final session stats to remote
20
+ await autoSync();
21
+ }
22
+ main().catch(console.error);
23
+ //# sourceMappingURL=session-end.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../../src/hooks/claude/session-end.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAEpD,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAEjC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;IACzB,KAAK,CAAC,QAAQ,IAAI,UAAU,CAAC;IAC7B,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IACjD,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAExB,MAAM,MAAM,CAAC,UAAU,EAAE,kBAAkB,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAErE,qCAAqC;IACrC,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function getStatusLine(): Promise<string>;
@@ -0,0 +1,48 @@
1
+ import { LocalStore } from '../../data/local-store.js';
2
+ import { getLevelInfo, getTierForLevel, getStars, getTierEmoji, getTierTitle } from '../../core/level-system.js';
3
+ import { renderStatusLine } from '../../display/status-line.js';
4
+ import { detectLocale } from '../../i18n/index.js';
5
+ import { AuthManager } from '../../auth/auth-manager.js';
6
+ import { fetchClaudeUsage, utilizationToPercent, resetsAtToMinutes } from '../../data/claude-usage.js';
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ const DATA_DIR = path.join(os.homedir(), '.myhpmp');
10
+ export async function getStatusLine() {
11
+ const authManager = new AuthManager(DATA_DIR);
12
+ const store = new LocalStore(DATA_DIR);
13
+ const stats = await store.load();
14
+ let locale;
15
+ try {
16
+ const config = await authManager.loadConfig();
17
+ locale = config.locale ?? detectLocale();
18
+ }
19
+ catch {
20
+ locale = detectLocale();
21
+ }
22
+ const levelInfo = getLevelInfo(stats.totalExp);
23
+ const tier = getTierForLevel(levelInfo.level);
24
+ const titleEmoji = getTierEmoji(tier.tierIndex);
25
+ const titleName = getTierTitle(tier.tierIndex, locale);
26
+ // Fetch real Claude usage data
27
+ const usage = await fetchClaudeUsage();
28
+ const hpPercent = usage ? utilizationToPercent(usage.fiveHour.utilization) : 100;
29
+ const mpPercent = usage ? utilizationToPercent(usage.sevenDay.utilization) : 100;
30
+ const resetMinutes = usage ? resetsAtToMinutes(usage.fiveHour.resetsAt) : 0;
31
+ return renderStatusLine({
32
+ titleEmoji,
33
+ titleName,
34
+ level: levelInfo.level,
35
+ stars: getStars(levelInfo.level),
36
+ hpPercent,
37
+ resetMinutes,
38
+ mpPercent,
39
+ ctxPercent: 0,
40
+ streakDays: stats.streakDays,
41
+ }, locale);
42
+ }
43
+ async function main() {
44
+ const line = await getStatusLine();
45
+ console.log(line);
46
+ }
47
+ main().catch(console.error);
48
+ //# sourceMappingURL=status-line-updater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-line-updater.js","sourceRoot":"","sources":["../../../src/hooks/claude/status-line-updater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACjH,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACvG,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAEjC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,CAAC;QAC9C,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEvD,+BAA+B;IAC/B,MAAM,KAAK,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACjF,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACjF,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5E,OAAO,gBAAgB,CAAC;QACtB,UAAU;QACV,SAAS;QACT,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;QAChC,SAAS;QACT,YAAY;QACZ,SAAS;QACT,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,EAAE,MAAM,CAAC,CAAC;AACb,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Codex CLI session-end hook.
3
+ * Parses the latest session JSONL to get total tokens, then logs all EXP at once.
4
+ */
5
+ import { LocalStore } from '../../data/local-store.js';
6
+ import { calcTokenExp, calcSessionExp } from '../../core/exp-calculator.js';
7
+ import { getLevelInfo } from '../../core/level-system.js';
8
+ import { autoSync } from '../../data/auto-sync.js';
9
+ import { logExp } from '../../data/exp-logger.js';
10
+ import { CodexAdapter } from '../../adapter/codex-adapter.js';
11
+ import os from 'node:os';
12
+ import path from 'node:path';
13
+ const DATA_DIR = path.join(os.homedir(), '.myhpmp');
14
+ async function main() {
15
+ const store = new LocalStore(DATA_DIR);
16
+ const stats = await store.load();
17
+ // Session EXP
18
+ const sessionExp = calcSessionExp();
19
+ stats.totalSessions += 1;
20
+ stats.totalExp += sessionExp;
21
+ // Token EXP (parse Codex session JSONL)
22
+ const codex = new CodexAdapter();
23
+ const totalTokens = await codex.getSessionTokens();
24
+ const tokenExp = Math.min(calcTokenExp(totalTokens), 1000);
25
+ if (tokenExp > 0) {
26
+ stats.totalExp += tokenExp;
27
+ }
28
+ stats.level = getLevelInfo(stats.totalExp).level;
29
+ stats.updatedAt = new Date().toISOString();
30
+ await store.save(stats);
31
+ // Log EXP to history
32
+ await logExp(sessionExp, 'session_complete', { provider: 'codex' });
33
+ if (tokenExp > 0) {
34
+ await logExp(tokenExp, 'token_usage', { tokens: totalTokens, provider: 'codex' });
35
+ }
36
+ // Push to remote
37
+ await autoSync();
38
+ }
39
+ main().catch(console.error);
40
+ //# sourceMappingURL=session-end.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../../src/hooks/codex/session-end.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAEpD,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAEjC,cAAc;IACd,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;IACzB,KAAK,CAAC,QAAQ,IAAI,UAAU,CAAC;IAE7B,wCAAwC;IACxC,MAAM,KAAK,GAAG,IAAI,YAAY,EAAE,CAAC;IACjC,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;IAE3D,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IACjD,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAExB,qBAAqB;IACrB,MAAM,MAAM,CAAC,UAAU,EAAE,kBAAkB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACpE,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,iBAAiB;IACjB,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import { LocalStore } from '../../data/local-store.js';
2
+ import { computeStreak } from '../../core/stats-aggregator.js';
3
+ import { calcStreakBonus } from '../../core/exp-calculator.js';
4
+ import { getLevelInfo } from '../../core/level-system.js';
5
+ import { autoSync } from '../../data/auto-sync.js';
6
+ import { logExp } from '../../data/exp-logger.js';
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ const DATA_DIR = path.join(os.homedir(), '.myhpmp');
10
+ async function main() {
11
+ // Pull latest from remote first (in case another device updated)
12
+ await autoSync();
13
+ const store = new LocalStore(DATA_DIR);
14
+ const stats = await store.load();
15
+ const now = new Date();
16
+ const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
17
+ const newStreak = computeStreak(stats.streakDays, stats.lastActiveDate);
18
+ const streakExp = calcStreakBonus(newStreak);
19
+ stats.streakDays = newStreak;
20
+ stats.lastActiveDate = today;
21
+ stats.totalExp += streakExp;
22
+ stats.level = getLevelInfo(stats.totalExp).level;
23
+ stats.updatedAt = new Date().toISOString();
24
+ await store.save(stats);
25
+ // Detect provider from parent process or config dir
26
+ const provider = process.env.CODEX_HOME || process.env.CODEX_CONFIG_DIR ? 'codex' : 'claude';
27
+ if (streakExp > 0) {
28
+ await logExp(streakExp, 'streak_bonus', { provider });
29
+ }
30
+ // Push updated stats to remote
31
+ await autoSync();
32
+ }
33
+ main().catch(console.error);
34
+ //# sourceMappingURL=session-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../../src/hooks/common/session-start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAEpD,KAAK,UAAU,IAAI;IACjB,iEAAiE;IACjE,MAAM,QAAQ,EAAE,CAAC;IAEjB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAEjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IAC9H,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAE7C,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC;IAC7B,KAAK,CAAC,QAAQ,IAAI,SAAS,CAAC;IAC5B,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IACjD,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAExB,oDAAoD;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE7F,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,+BAA+B;IAC/B,MAAM,QAAQ,EAAE,CAAC;AACnB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ declare const _default: {
2
+ readonly status: {
3
+ readonly streak: "Streak";
4
+ readonly totalExp: "Total EXP";
5
+ readonly totalSessions: "Total Sessions";
6
+ readonly resetIn: "resets in";
7
+ readonly hp: "HP";
8
+ readonly mp: "MP";
9
+ readonly ctx: "CTX";
10
+ readonly exp: "EXP";
11
+ };
12
+ readonly unit: {
13
+ readonly days: "d";
14
+ readonly hours: "h";
15
+ readonly minutes: "m";
16
+ readonly tokens: "tokens";
17
+ readonly sessions: "sessions";
18
+ };
19
+ readonly exp: {
20
+ readonly tokenUsage: "Token Usage";
21
+ readonly sessionComplete: "Session Complete";
22
+ readonly streakBonus: "Streak Bonus";
23
+ readonly weeklyGoal: "Weekly Goal Achieved";
24
+ };
25
+ };
26
+ export default _default;
@@ -0,0 +1,26 @@
1
+ export default {
2
+ status: {
3
+ streak: 'Streak',
4
+ totalExp: 'Total EXP',
5
+ totalSessions: 'Total Sessions',
6
+ resetIn: 'resets in',
7
+ hp: 'HP',
8
+ mp: 'MP',
9
+ ctx: 'CTX',
10
+ exp: 'EXP',
11
+ },
12
+ unit: {
13
+ days: 'd',
14
+ hours: 'h',
15
+ minutes: 'm',
16
+ tokens: 'tokens',
17
+ sessions: 'sessions',
18
+ },
19
+ exp: {
20
+ tokenUsage: 'Token Usage',
21
+ sessionComplete: 'Session Complete',
22
+ streakBonus: 'Streak Bonus',
23
+ weeklyGoal: 'Weekly Goal Achieved',
24
+ },
25
+ };
26
+ //# sourceMappingURL=en.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"en.js","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,MAAM,EAAE;QACN,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,WAAW;QACrB,aAAa,EAAE,gBAAgB;QAC/B,OAAO,EAAE,WAAW;QACpB,EAAE,EAAE,IAAI;QACR,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,KAAK;QACV,GAAG,EAAE,KAAK;KACX;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,GAAG;QACV,OAAO,EAAE,GAAG;QACZ,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,UAAU;KACrB;IACD,GAAG,EAAE;QACH,UAAU,EAAE,aAAa;QACzB,eAAe,EAAE,kBAAkB;QACnC,WAAW,EAAE,cAAc;QAC3B,UAAU,EAAE,sBAAsB;KACnC;CACO,CAAC"}
@@ -0,0 +1,7 @@
1
+ type Locale = 'ko' | 'en';
2
+ export declare function detectLocale(): Locale;
3
+ export declare function createI18n(locale?: string): {
4
+ locale: Locale;
5
+ t(key: string): string;
6
+ };
7
+ export {};