ccjk 13.3.14 → 13.3.16

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.
@@ -648,6 +648,44 @@ class ContextPersistence {
648
648
  timestamp: row.timestamp
649
649
  }));
650
650
  }
651
+ /**
652
+ * Query compression metrics with optional filters
653
+ */
654
+ getCompressionMetrics(projectHash, options) {
655
+ let query = "SELECT * FROM compression_metrics WHERE 1=1";
656
+ const params = [];
657
+ if (projectHash) {
658
+ query += " AND project_hash = ?";
659
+ params.push(projectHash);
660
+ }
661
+ if (options?.startTime) {
662
+ query += " AND timestamp >= ?";
663
+ params.push(options.startTime);
664
+ }
665
+ if (options?.endTime) {
666
+ query += " AND timestamp <= ?";
667
+ params.push(options.endTime);
668
+ }
669
+ query += ` ORDER BY timestamp ${(options?.sortOrder || "desc").toUpperCase()}`;
670
+ if (options?.limit) {
671
+ query += " LIMIT ?";
672
+ params.push(options.limit);
673
+ }
674
+ const stmt = this.db.prepare(query);
675
+ const rows = stmt.all(...params);
676
+ return rows.map((row) => ({
677
+ id: row.id,
678
+ projectHash: row.project_hash,
679
+ contextId: row.context_id,
680
+ originalTokens: row.original_tokens,
681
+ compressedTokens: row.compressed_tokens,
682
+ compressionRatio: row.compression_ratio,
683
+ timeTakenMs: row.time_taken_ms,
684
+ algorithm: row.algorithm,
685
+ strategy: row.strategy,
686
+ timestamp: row.timestamp
687
+ }));
688
+ }
651
689
  /**
652
690
  * Clean up old compression metrics
653
691
  */
@@ -13,6 +13,7 @@ import require$$0 from 'fs';
13
13
  import { c as commonjsRequire } from '../shared/ccjk.COweQ1RR.mjs';
14
14
  import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
15
15
  import { b as CloudErrorFactory, C as CloudError } from '../shared/ccjk.D8ZLYSZZ.mjs';
16
+ import { s as showImpactReminder } from '../shared/ccjk.Bb9Mpi2O.mjs';
16
17
  import 'node:readline';
17
18
  import 'stream';
18
19
  import 'node:tty';
@@ -6442,6 +6443,9 @@ function displaySyncResult(result, lang) {
6442
6443
  }
6443
6444
  }
6444
6445
  }
6446
+ if (result.success && result.uploaded > 0) {
6447
+ showImpactReminder("publish");
6448
+ }
6445
6449
  console.log("");
6446
6450
  }
6447
6451
  function getPrivacyBadge(privacy) {
@@ -1,231 +1,12 @@
1
1
  import a from './index2.mjs';
2
2
  import { i18n } from './index5.mjs';
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
4
- import { homedir } from 'node:os';
5
- import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
3
+ import { g as getStatsStorage } from '../shared/ccjk.OTnevPNE.mjs';
6
4
  import '../shared/ccjk.BAGoDD49.mjs';
5
+ import 'node:fs';
7
6
  import 'node:process';
8
7
  import 'node:url';
9
-
10
- class StatsStorage {
11
- baseDir;
12
- recordsDir;
13
- dailyDir;
14
- constructor(baseDir) {
15
- this.baseDir = baseDir || join(homedir(), ".ccjk", "stats");
16
- this.recordsDir = join(this.baseDir, "records");
17
- this.dailyDir = join(this.baseDir, "daily");
18
- this.ensureDirectories();
19
- }
20
- /**
21
- * Ensure storage directories exist
22
- */
23
- ensureDirectories() {
24
- for (const dir of [this.baseDir, this.recordsDir, this.dailyDir]) {
25
- if (!existsSync(dir)) {
26
- mkdirSync(dir, { recursive: true });
27
- }
28
- }
29
- }
30
- /**
31
- * Get file path for a specific date
32
- */
33
- getRecordFilePath(date) {
34
- return join(this.recordsDir, `${date}.json`);
35
- }
36
- /**
37
- * Get daily stats file path for a specific date
38
- */
39
- getDailyStatsFilePath(date) {
40
- return join(this.dailyDir, `${date}.json`);
41
- }
42
- /**
43
- * Format date as YYYY-MM-DD
44
- */
45
- formatDate(timestamp) {
46
- const date = new Date(timestamp);
47
- const year = date.getFullYear();
48
- const month = String(date.getMonth() + 1).padStart(2, "0");
49
- const day = String(date.getDate()).padStart(2, "0");
50
- return `${year}-${month}-${day}`;
51
- }
52
- /**
53
- * Save a request record
54
- */
55
- saveRecord(record) {
56
- const date = this.formatDate(record.timestamp);
57
- const filePath = this.getRecordFilePath(date);
58
- let records = [];
59
- if (existsSync(filePath)) {
60
- try {
61
- const content = readFileSync(filePath, "utf-8");
62
- records = JSON.parse(content);
63
- } catch {
64
- records = [];
65
- }
66
- }
67
- records.push(record);
68
- writeFileSync(filePath, JSON.stringify(records, null, 2), "utf-8");
69
- }
70
- /**
71
- * Get records for a specific date
72
- */
73
- getRecordsByDate(date) {
74
- const filePath = this.getRecordFilePath(date);
75
- if (!existsSync(filePath)) {
76
- return [];
77
- }
78
- try {
79
- const content = readFileSync(filePath, "utf-8");
80
- return JSON.parse(content);
81
- } catch {
82
- return [];
83
- }
84
- }
85
- /**
86
- * Get records for a date range
87
- */
88
- getRecordsByDateRange(startDate, endDate) {
89
- const records = [];
90
- const start = new Date(startDate);
91
- const end = new Date(endDate);
92
- const d = new Date(start);
93
- while (d <= end) {
94
- const dateStr = this.formatDate(d.getTime());
95
- records.push(...this.getRecordsByDate(dateStr));
96
- d.setDate(d.getDate() + 1);
97
- }
98
- return records;
99
- }
100
- /**
101
- * Get all available record dates
102
- */
103
- getAvailableDates() {
104
- if (!existsSync(this.recordsDir)) {
105
- return [];
106
- }
107
- const files = readdirSync(this.recordsDir);
108
- return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", "")).sort();
109
- }
110
- /**
111
- * Save daily statistics
112
- */
113
- saveDailyStats(stats) {
114
- const filePath = this.getDailyStatsFilePath(stats.date);
115
- writeFileSync(filePath, JSON.stringify(stats, null, 2), "utf-8");
116
- }
117
- /**
118
- * Get daily statistics for a specific date
119
- */
120
- getDailyStats(date) {
121
- const filePath = this.getDailyStatsFilePath(date);
122
- if (!existsSync(filePath)) {
123
- return null;
124
- }
125
- try {
126
- const content = readFileSync(filePath, "utf-8");
127
- return JSON.parse(content);
128
- } catch {
129
- return null;
130
- }
131
- }
132
- /**
133
- * Get daily statistics for a date range
134
- */
135
- getDailyStatsByDateRange(startDate, endDate) {
136
- const stats = [];
137
- const start = new Date(startDate);
138
- const end = new Date(endDate);
139
- const d = new Date(start);
140
- while (d <= end) {
141
- const dateStr = this.formatDate(d.getTime());
142
- const dailyStats = this.getDailyStats(dateStr);
143
- if (dailyStats) {
144
- stats.push(dailyStats);
145
- }
146
- d.setDate(d.getDate() + 1);
147
- }
148
- return stats;
149
- }
150
- /**
151
- * Get all available daily stats dates
152
- */
153
- getAvailableDailyStatsDates() {
154
- if (!existsSync(this.dailyDir)) {
155
- return [];
156
- }
157
- const files = readdirSync(this.dailyDir);
158
- return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", "")).sort();
159
- }
160
- /**
161
- * Calculate date range for a period
162
- */
163
- getDateRangeForPeriod(period) {
164
- const now = /* @__PURE__ */ new Date();
165
- const endDate = this.formatDate(now.getTime());
166
- if (period === "all") {
167
- const dates = this.getAvailableDates();
168
- const startDate2 = dates.length > 0 ? dates[0] : endDate;
169
- return { startDate: startDate2, endDate };
170
- }
171
- const days = period === "1d" ? 1 : period === "7d" ? 7 : period === "30d" ? 30 : 90;
172
- const start = new Date(now);
173
- start.setDate(start.getDate() - days + 1);
174
- const startDate = this.formatDate(start.getTime());
175
- return { startDate, endDate };
176
- }
177
- /**
178
- * Clean up old records (older than specified days)
179
- */
180
- cleanupOldRecords(daysToKeep) {
181
- const cutoffDate = /* @__PURE__ */ new Date();
182
- cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
183
- const cutoffStr = this.formatDate(cutoffDate.getTime());
184
- const dates = this.getAvailableDates();
185
- let deletedCount = 0;
186
- for (const date of dates) {
187
- if (date < cutoffStr) {
188
- try {
189
- const recordFile = this.getRecordFilePath(date);
190
- const dailyFile = this.getDailyStatsFilePath(date);
191
- if (existsSync(recordFile)) {
192
- deletedCount++;
193
- }
194
- if (existsSync(dailyFile)) {
195
- }
196
- } catch {
197
- }
198
- }
199
- }
200
- return deletedCount;
201
- }
202
- /**
203
- * Get storage statistics
204
- */
205
- getStorageStats() {
206
- const recordDates = this.getAvailableDates();
207
- const dailyDates = this.getAvailableDailyStatsDates();
208
- let totalRecords = 0;
209
- for (const date of recordDates) {
210
- const records = this.getRecordsByDate(date);
211
- totalRecords += records.length;
212
- }
213
- return {
214
- totalRecordFiles: recordDates.length,
215
- totalDailyFiles: dailyDates.length,
216
- oldestDate: recordDates.length > 0 ? recordDates[0] : null,
217
- newestDate: recordDates.length > 0 ? recordDates[recordDates.length - 1] : null,
218
- totalRecords
219
- };
220
- }
221
- }
222
- let storageInstance = null;
223
- function getStatsStorage() {
224
- if (!storageInstance) {
225
- storageInstance = new StatsStorage();
226
- }
227
- return storageInstance;
228
- }
8
+ import '../shared/ccjk.bQ7Dh1g4.mjs';
9
+ import 'node:os';
229
10
 
230
11
  async function stats(options = {}) {
231
12
  const period = options.period || "7d";
package/dist/cli.mjs CHANGED
@@ -716,6 +716,27 @@ const COMMANDS = [
716
716
  };
717
717
  }
718
718
  },
719
+ {
720
+ name: "impact",
721
+ description: "Usage impact page with daily tokens, savings, and before/after trends",
722
+ aliases: ["gain"],
723
+ tier: "extended",
724
+ options: [
725
+ { flags: "--days <days>", description: "Number of days to include (7-90)" },
726
+ { flags: "--json", description: "Output as JSON" },
727
+ { flags: "--output <file>", description: "Custom HTML output path" }
728
+ ],
729
+ loader: async () => {
730
+ const { impactCommand } = await import('./chunks/impact.mjs');
731
+ return async (options) => {
732
+ await impactCommand({
733
+ json: options.json,
734
+ days: options.days ? Number(options.days) : void 0,
735
+ output: options.output
736
+ });
737
+ };
738
+ }
739
+ },
719
740
  {
720
741
  name: "stats [action]",
721
742
  description: "Usage statistics and analytics",
@@ -1824,6 +1845,54 @@ ${ansis.yellow("By Status:")}`);
1824
1845
  };
1825
1846
  }
1826
1847
  },
1848
+ {
1849
+ name: "brain-status",
1850
+ description: "Brain capability routing and telemetry stats",
1851
+ aliases: ["bs"],
1852
+ tier: "core",
1853
+ options: [
1854
+ { flags: "--detailed, -d", description: "Show detailed statistics" },
1855
+ { flags: "--json, -j", description: "Output as JSON" }
1856
+ ],
1857
+ loader: async () => {
1858
+ const { brainStatusCommand } = await import('./chunks/brain-status.mjs');
1859
+ return async (options) => {
1860
+ await brainStatusCommand({
1861
+ detailed: options.detailed,
1862
+ json: options.json
1863
+ });
1864
+ };
1865
+ }
1866
+ },
1867
+ {
1868
+ name: "brain-config",
1869
+ description: "Configure Brain capability routing system",
1870
+ aliases: ["bc"],
1871
+ tier: "core",
1872
+ options: [
1873
+ { flags: "--preference, -p <level>", description: "Set capability preference (1-5)" },
1874
+ { flags: "--threshold, -t <value>", description: "Set auto-subagent threshold (1-10)" },
1875
+ { flags: "--max-agents, -m <count>", description: "Set max parallel agents" },
1876
+ { flags: "--telemetry <on|off>", description: "Enable/disable telemetry" },
1877
+ { flags: "--reasoning <on|off>", description: "Enable/disable reasoning display" },
1878
+ { flags: "--show, -s", description: "Show current configuration" },
1879
+ { flags: "--reset", description: "Reset to default configuration" }
1880
+ ],
1881
+ loader: async () => {
1882
+ const { brainConfigCommand } = await import('./chunks/brain-config.mjs');
1883
+ return async (options) => {
1884
+ await brainConfigCommand({
1885
+ preference: options.preference ? parseFloat(options.preference) : void 0,
1886
+ threshold: options.threshold ? parseFloat(options.threshold) : void 0,
1887
+ maxAgents: options.maxAgents ? parseInt(options.maxAgents, 10) : void 0,
1888
+ telemetry: options.telemetry,
1889
+ reasoning: options.reasoning,
1890
+ show: options.show,
1891
+ reset: options.reset
1892
+ });
1893
+ };
1894
+ }
1895
+ },
1827
1896
  // ==================== Plugin Management ====================
1828
1897
  {
1829
1898
  name: "add <source>",
@@ -2121,6 +2190,7 @@ function customizeHelpLazy(_sections, version) {
2121
2190
  ` ${cyan("ccjk workflows")} ${gray("wf")} Manage workflows`,
2122
2191
  ` ${cyan("ccjk ccr")} CCR proxy management`,
2123
2192
  ` ${cyan("ccjk ccu")} Usage statistics`,
2193
+ ` ${cyan("ccjk impact")} Usage impact page`,
2124
2194
  ` ${cyan("ccjk completion")} Shell completion ${green("NEW")}`,
2125
2195
  ` ${cyan("ccjk uninstall")} Remove configurations`
2126
2196
  ].join("\n")
@@ -0,0 +1,19 @@
1
+ import a from '../chunks/index2.mjs';
2
+
3
+ const EVENT_LABELS = {
4
+ commit: "your changes",
5
+ publish: "your publish flow",
6
+ push: "your Git push",
7
+ sync: "your sync",
8
+ release: "your release"
9
+ };
10
+ function showImpactReminder(event) {
11
+ const label = EVENT_LABELS[event];
12
+ console.log("");
13
+ console.log(a.cyan("Impact tip:"));
14
+ console.log(a.dim(` After ${label}, check today's usage impact:`));
15
+ console.log(a.white(" ccjk impact"));
16
+ console.log(a.dim(" This helps you see today's token usage, savings, and trend changes immediately."));
17
+ }
18
+
19
+ export { showImpactReminder as s };