@nexrall/code-core 1.4.76 → 1.4.78
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/dist/agent/effortCap.d.ts +24 -0
- package/dist/agent/effortCap.d.ts.map +1 -0
- package/dist/agent/effortCap.js +66 -0
- package/dist/agent/goal.d.ts +55 -0
- package/dist/agent/goal.d.ts.map +1 -0
- package/dist/agent/goal.js +120 -0
- package/dist/agent/handoffBrief.d.ts +82 -0
- package/dist/agent/handoffBrief.d.ts.map +1 -0
- package/dist/agent/handoffBrief.js +121 -0
- package/dist/agent/hooks.d.ts +10 -2
- package/dist/agent/hooks.d.ts.map +1 -1
- package/dist/agent/hooks.js +9 -3
- package/dist/agent/modelCatalogue.d.ts +23 -0
- package/dist/agent/modelCatalogue.d.ts.map +1 -1
- package/dist/agent/modelCatalogue.js +28 -0
- package/dist/agent/outputStyles.d.ts +27 -0
- package/dist/agent/outputStyles.d.ts.map +1 -0
- package/dist/agent/outputStyles.js +174 -0
- package/dist/agent/skills.d.ts.map +1 -1
- package/dist/agent/skills.js +21 -1
- package/dist/api/billingLines.d.ts +11 -0
- package/dist/api/billingLines.d.ts.map +1 -0
- package/dist/api/billingLines.js +56 -0
- package/dist/api/client.d.ts +2 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/scheduleLines.d.ts +53 -0
- package/dist/api/scheduleLines.d.ts.map +1 -0
- package/dist/api/scheduleLines.js +150 -0
- package/dist/context/contextFiles.d.ts +81 -0
- package/dist/context/contextFiles.d.ts.map +1 -0
- package/dist/context/contextFiles.js +310 -0
- package/dist/diff/collect.d.ts +25 -0
- package/dist/diff/collect.d.ts.map +1 -0
- package/dist/diff/collect.js +169 -0
- package/dist/diff/diffView.d.ts +57 -0
- package/dist/diff/diffView.d.ts.map +1 -0
- package/dist/diff/diffView.js +231 -0
- package/dist/diff/reviewQueue.d.ts +53 -0
- package/dist/diff/reviewQueue.d.ts.map +1 -0
- package/dist/diff/reviewQueue.js +349 -0
- package/dist/events/recap.d.ts +54 -0
- package/dist/events/recap.d.ts.map +1 -0
- package/dist/events/recap.js +161 -0
- package/dist/events/sessionEvents.d.ts +54 -0
- package/dist/events/sessionEvents.d.ts.map +1 -0
- package/dist/events/sessionEvents.js +324 -0
- package/dist/events/sessionStats.d.ts +89 -0
- package/dist/events/sessionStats.d.ts.map +1 -0
- package/dist/events/sessionStats.js +264 -0
- package/dist/import/claudeImport.d.ts +44 -0
- package/dist/import/claudeImport.d.ts.map +1 -0
- package/dist/import/claudeImport.js +337 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -0
- package/dist/mcp/manager.d.ts +8 -0
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +64 -57
- package/dist/permissions/destructiveTokens.d.ts +1 -0
- package/dist/permissions/destructiveTokens.d.ts.map +1 -1
- package/dist/permissions/destructiveTokens.js +93 -0
- package/dist/permissions/rules.d.ts +12 -0
- package/dist/permissions/rules.d.ts.map +1 -1
- package/dist/permissions/rules.js +89 -7
- package/dist/plugins/configStore.d.ts +43 -0
- package/dist/plugins/configStore.d.ts.map +1 -0
- package/dist/plugins/configStore.js +253 -0
- package/dist/plugins/files.d.ts +10 -0
- package/dist/plugins/files.d.ts.map +1 -0
- package/dist/plugins/files.js +85 -0
- package/dist/plugins/index.d.ts +3 -22
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +30 -40
- package/dist/plugins/resolve.d.ts +18 -0
- package/dist/plugins/resolve.d.ts.map +1 -0
- package/dist/plugins/resolve.js +152 -0
- package/dist/plugins/userConfig.d.ts +90 -0
- package/dist/plugins/userConfig.d.ts.map +1 -0
- package/dist/plugins/userConfig.js +332 -0
- package/dist/plugins/validate.d.ts +14 -0
- package/dist/plugins/validate.d.ts.map +1 -0
- package/dist/plugins/validate.js +222 -0
- package/dist/project/projectCommands.d.ts +33 -0
- package/dist/project/projectCommands.d.ts.map +1 -0
- package/dist/project/projectCommands.js +246 -0
- package/dist/search/conversationTurns.d.ts +53 -0
- package/dist/search/conversationTurns.d.ts.map +1 -0
- package/dist/search/conversationTurns.js +170 -0
- package/dist/search/globalSearch.d.ts +144 -0
- package/dist/search/globalSearch.d.ts.map +1 -0
- package/dist/search/globalSearch.js +350 -0
- package/dist/share/sessionChannel.d.ts +136 -0
- package/dist/share/sessionChannel.d.ts.map +1 -0
- package/dist/share/sessionChannel.js +373 -0
- package/dist/share/sessionShare.d.ts +104 -0
- package/dist/share/sessionShare.d.ts.map +1 -0
- package/dist/share/sessionShare.js +336 -0
- package/dist/ui/configCmd.d.ts +48 -0
- package/dist/ui/configCmd.d.ts.map +1 -0
- package/dist/ui/configCmd.js +146 -0
- package/dist/ui/deployPanel.d.ts +91 -0
- package/dist/ui/deployPanel.d.ts.map +1 -0
- package/dist/ui/deployPanel.js +442 -0
- package/dist/ui/mergeAssistant.d.ts +120 -0
- package/dist/ui/mergeAssistant.d.ts.map +1 -0
- package/dist/ui/mergeAssistant.js +391 -0
- package/dist/ui/notify.d.ts +114 -0
- package/dist/ui/notify.d.ts.map +1 -0
- package/dist/ui/notify.js +235 -0
- package/dist/ui/promptSuggest.d.ts +56 -0
- package/dist/ui/promptSuggest.d.ts.map +1 -0
- package/dist/ui/promptSuggest.js +160 -0
- package/dist/ui/taskGraph.d.ts +44 -0
- package/dist/ui/taskGraph.d.ts.map +1 -0
- package/dist/ui/taskGraph.js +289 -0
- package/dist/util/addDir.d.ts +31 -0
- package/dist/util/addDir.d.ts.map +1 -0
- package/dist/util/addDir.js +124 -0
- package/dist/util/batch.d.ts +16 -0
- package/dist/util/batch.d.ts.map +1 -0
- package/dist/util/batch.js +92 -0
- package/dist/util/cellWidth.d.ts +12 -0
- package/dist/util/cellWidth.d.ts.map +1 -0
- package/dist/util/cellWidth.js +161 -0
- package/dist/util/duration.d.ts +8 -0
- package/dist/util/duration.d.ts.map +1 -0
- package/dist/util/duration.js +50 -0
- package/dist/util/loopJobs.d.ts +67 -0
- package/dist/util/loopJobs.d.ts.map +1 -0
- package/dist/util/loopJobs.js +169 -0
- package/dist/util/settingsFile.d.ts +14 -0
- package/dist/util/settingsFile.d.ts.map +1 -0
- package/dist/util/settingsFile.js +99 -0
- package/dist/util/toolLabel.d.ts +2 -0
- package/dist/util/toolLabel.d.ts.map +1 -0
- package/dist/util/toolLabel.js +17 -0
- package/dist/verify/failureTimeline.d.ts +100 -0
- package/dist/verify/failureTimeline.d.ts.map +1 -0
- package/dist/verify/failureTimeline.js +253 -0
- package/dist/verify/verification.d.ts +75 -0
- package/dist/verify/verification.d.ts.map +1 -0
- package/dist/verify/verification.js +315 -0
- package/package.json +5 -4
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Days shown in the sparkline window. */
|
|
2
|
+
export declare const STATS_DAYS = 14;
|
|
3
|
+
/** Newest event logs read per call — a heavy user can accumulate hundreds. */
|
|
4
|
+
export declare const MAX_EVENT_FILES = 100;
|
|
5
|
+
/** The two event types `/stats` reads, narrowed to the fields it needs. */
|
|
6
|
+
export interface UsageEventLite {
|
|
7
|
+
ts: number;
|
|
8
|
+
type: 'message.started' | 'message.completed';
|
|
9
|
+
/** message.started: the alias the CLI asked for. */
|
|
10
|
+
model?: string;
|
|
11
|
+
/** message.completed: total tokens of the turn, when reported. */
|
|
12
|
+
tokens?: number;
|
|
13
|
+
/** message.completed: USD, or null when the server reported none. */
|
|
14
|
+
cost?: number | null;
|
|
15
|
+
}
|
|
16
|
+
export interface DayUsage {
|
|
17
|
+
/** Local calendar day, YYYY-MM-DD. */
|
|
18
|
+
day: string;
|
|
19
|
+
requests: number;
|
|
20
|
+
tokens: number;
|
|
21
|
+
}
|
|
22
|
+
/** A counted name (`claude-sonnet-5-5` ×12) — structurally identical to the
|
|
23
|
+
* CLI's costPanel.Tally; kept local so core does not import from the CLI. */
|
|
24
|
+
export interface Tally {
|
|
25
|
+
name: string;
|
|
26
|
+
count: number;
|
|
27
|
+
}
|
|
28
|
+
export interface UsageStats {
|
|
29
|
+
requests: number;
|
|
30
|
+
tokens: number;
|
|
31
|
+
costUsd: number;
|
|
32
|
+
/** completed rows that carried a numeric cost. */
|
|
33
|
+
costReported: number;
|
|
34
|
+
/** completed rows with no cost — the panel says "n did not report" rather than adding $0. */
|
|
35
|
+
costMissing: number;
|
|
36
|
+
models: Tally[];
|
|
37
|
+
/** Every day that saw at least one event, ascending. */
|
|
38
|
+
days: DayUsage[];
|
|
39
|
+
busiest: DayUsage | null;
|
|
40
|
+
firstTs: number | null;
|
|
41
|
+
lastTs: number | null;
|
|
42
|
+
}
|
|
43
|
+
export interface StatsMeta {
|
|
44
|
+
savedSessions: number;
|
|
45
|
+
sessionsWithLogs: number;
|
|
46
|
+
/** How many of those logs were actually read this call (≤ MAX_EVENT_FILES). */
|
|
47
|
+
readFiles: number;
|
|
48
|
+
}
|
|
49
|
+
/** What the panel puts on its closing `this run` row — this process's own numbers. */
|
|
50
|
+
export interface ThisRun {
|
|
51
|
+
turns: number;
|
|
52
|
+
toolCalls: number;
|
|
53
|
+
ms: number;
|
|
54
|
+
tokens: number;
|
|
55
|
+
costUsd: number;
|
|
56
|
+
costReported: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** Local calendar day of a timestamp. Local, not UTC: "today" must mean the user's today. */
|
|
59
|
+
export declare function dayKey(ts: number): string;
|
|
60
|
+
/** `Oct 3` — no year: this is recent-activity data and a year costs 5 columns on every row. */
|
|
61
|
+
export declare function shortDate(ts: number): string;
|
|
62
|
+
/**
|
|
63
|
+
* The day keys of the last `n` local days ending at `now`, oldest first.
|
|
64
|
+
* Calendar arithmetic via setDate (not `now - i*86_400_000`): subtracting
|
|
65
|
+
* fixed MS across a DST change skips or repeats a local day.
|
|
66
|
+
*/
|
|
67
|
+
export declare function lastDays(now: number, n: number): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Narrow one raw JSONL row to the fields the panel reads, or drop it.
|
|
70
|
+
* Tolerant by design: a trimmed tail can cut the last line mid-JSON, and the
|
|
71
|
+
* format is versioned (`v`) — unknown shapes must disappear quietly, never
|
|
72
|
+
* throw in the middle of a /stats.
|
|
73
|
+
*/
|
|
74
|
+
export declare function liteEvent(row: unknown): UsageEventLite | null;
|
|
75
|
+
/** All the arithmetic of the panel; pure so every tally rule is unit-testable. */
|
|
76
|
+
export declare function aggregateUsage(events: UsageEventLite[]): UsageStats;
|
|
77
|
+
/** Eight-level block sparkline; zero maps to the floor glyph so gaps stay visible as a baseline. */
|
|
78
|
+
export declare function sparkline(values: number[]): string;
|
|
79
|
+
export interface LoadedUsage extends StatsMeta {
|
|
80
|
+
events: UsageEventLite[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Read the newest event logs and narrow them to UsageEventLite rows.
|
|
84
|
+
* Everything here is best-effort: a missing directory (fresh install), an
|
|
85
|
+
* unreadable file or a torn JSON line must degrade the panel, never fail the
|
|
86
|
+
* command — the numbers are a courtesy, the session is the job.
|
|
87
|
+
*/
|
|
88
|
+
export declare function loadUsageStats(env?: NodeJS.ProcessEnv): LoadedUsage;
|
|
89
|
+
//# sourceMappingURL=sessionStats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionStats.d.ts","sourceRoot":"","sources":["../../src/events/sessionStats.ts"],"names":[],"mappings":"AAyBA,0CAA0C;AAC1C,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,8EAA8E;AAC9E,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;IAC9C,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;6EAC6E;AAC7E,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,6FAA6F;IAC7F,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,wDAAwD;IACxD,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,sFAAsF;AACtF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,6FAA6F;AAC7F,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAIzC;AAED,+FAA+F;AAC/F,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAQzD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAgB7D;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,UAAU,CA0DnE;AAID,oGAAoG;AACpG,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAKlD;AAID,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CAmDhF"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Lives in core (split from the CLI's ui/sessionStats.ts, 2026-10-04): the VS
|
|
3
|
+
// Code panel aggregates the SAME event logs for /stats. The CLI module keeps
|
|
4
|
+
// only formatStatsPanel (the ANSI-coloured rendering).
|
|
5
|
+
// S17b — the `/stats` panel: usage ACROSS sessions, from the local §92 event
|
|
6
|
+
// logs (each session writes `<sessions-root>/events/<id>.jsonl`).
|
|
7
|
+
//
|
|
8
|
+
// WHY: `/cost` answers "what is THIS session spending"; Claude Code's /stats
|
|
9
|
+
// class of panel answers "how much have I been using this thing" — activity by
|
|
10
|
+
// day, totals, favourite model. Nothing else in the CLI shows history, and the
|
|
11
|
+
// event logs already carry every number (`message.started` → model,
|
|
12
|
+
// `message.completed` → tokens/cost/duration), so the panel is pure arithmetic
|
|
13
|
+
// over files we already wrote. No server, no new recording.
|
|
14
|
+
//
|
|
15
|
+
// Deliberate limits, stated because the numbers must not overpromise:
|
|
16
|
+
// - Logs are trimmed at 2MB/1000 events, so old huge sessions lose detail.
|
|
17
|
+
// - Only the newest MAX_EVENT_FILES logs are read; the panel says so when
|
|
18
|
+
// that cap actually bites.
|
|
19
|
+
// - Cost is only summed when the server reported it (same rule as /cost).
|
|
20
|
+
// Pure (no console, no Ink) so the aggregation is unit-testable — see
|
|
21
|
+
// test/sessionStats.test.mts.
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
39
|
+
var ownKeys = function(o) {
|
|
40
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
41
|
+
var ar = [];
|
|
42
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
43
|
+
return ar;
|
|
44
|
+
};
|
|
45
|
+
return ownKeys(o);
|
|
46
|
+
};
|
|
47
|
+
return function (mod) {
|
|
48
|
+
if (mod && mod.__esModule) return mod;
|
|
49
|
+
var result = {};
|
|
50
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
51
|
+
__setModuleDefault(result, mod);
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.MAX_EVENT_FILES = exports.STATS_DAYS = void 0;
|
|
57
|
+
exports.dayKey = dayKey;
|
|
58
|
+
exports.shortDate = shortDate;
|
|
59
|
+
exports.lastDays = lastDays;
|
|
60
|
+
exports.liteEvent = liteEvent;
|
|
61
|
+
exports.aggregateUsage = aggregateUsage;
|
|
62
|
+
exports.sparkline = sparkline;
|
|
63
|
+
exports.loadUsageStats = loadUsageStats;
|
|
64
|
+
const fs = __importStar(require("fs"));
|
|
65
|
+
const os = __importStar(require("os"));
|
|
66
|
+
const path = __importStar(require("path"));
|
|
67
|
+
/** Days shown in the sparkline window. */
|
|
68
|
+
exports.STATS_DAYS = 14;
|
|
69
|
+
/** Newest event logs read per call — a heavy user can accumulate hundreds. */
|
|
70
|
+
exports.MAX_EVENT_FILES = 100;
|
|
71
|
+
const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
72
|
+
/** Local calendar day of a timestamp. Local, not UTC: "today" must mean the user's today. */
|
|
73
|
+
function dayKey(ts) {
|
|
74
|
+
const d = new Date(ts);
|
|
75
|
+
const p = (n) => String(n).padStart(2, '0');
|
|
76
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
|
|
77
|
+
}
|
|
78
|
+
/** `Oct 3` — no year: this is recent-activity data and a year costs 5 columns on every row. */
|
|
79
|
+
function shortDate(ts) {
|
|
80
|
+
const d = new Date(ts);
|
|
81
|
+
return `${MONTHS[d.getMonth()]} ${d.getDate()}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The day keys of the last `n` local days ending at `now`, oldest first.
|
|
85
|
+
* Calendar arithmetic via setDate (not `now - i*86_400_000`): subtracting
|
|
86
|
+
* fixed MS across a DST change skips or repeats a local day.
|
|
87
|
+
*/
|
|
88
|
+
function lastDays(now, n) {
|
|
89
|
+
const out = [];
|
|
90
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
91
|
+
const d = new Date(now);
|
|
92
|
+
d.setDate(d.getDate() - i);
|
|
93
|
+
out.push(dayKey(d.getTime()));
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Narrow one raw JSONL row to the fields the panel reads, or drop it.
|
|
99
|
+
* Tolerant by design: a trimmed tail can cut the last line mid-JSON, and the
|
|
100
|
+
* format is versioned (`v`) — unknown shapes must disappear quietly, never
|
|
101
|
+
* throw in the middle of a /stats.
|
|
102
|
+
*/
|
|
103
|
+
function liteEvent(row) {
|
|
104
|
+
if (typeof row !== 'object' || row === null)
|
|
105
|
+
return null;
|
|
106
|
+
const r = row;
|
|
107
|
+
if (typeof r.ts !== 'number' || !Number.isFinite(r.ts))
|
|
108
|
+
return null;
|
|
109
|
+
if (r.type === 'message.started') {
|
|
110
|
+
return { ts: r.ts, type: 'message.started', model: typeof r.model === 'string' && r.model ? r.model : undefined };
|
|
111
|
+
}
|
|
112
|
+
if (r.type === 'message.completed') {
|
|
113
|
+
return {
|
|
114
|
+
ts: r.ts,
|
|
115
|
+
type: 'message.completed',
|
|
116
|
+
tokens: typeof r.tokens === 'number' && Number.isFinite(r.tokens) ? r.tokens : undefined,
|
|
117
|
+
cost: typeof r.cost === 'number' && Number.isFinite(r.cost) ? r.cost : null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/** All the arithmetic of the panel; pure so every tally rule is unit-testable. */
|
|
123
|
+
function aggregateUsage(events) {
|
|
124
|
+
const models = new Map();
|
|
125
|
+
const byDay = new Map();
|
|
126
|
+
let requests = 0;
|
|
127
|
+
let tokens = 0;
|
|
128
|
+
let costUsd = 0;
|
|
129
|
+
let costReported = 0;
|
|
130
|
+
let costMissing = 0;
|
|
131
|
+
let firstTs = null;
|
|
132
|
+
let lastTs = null;
|
|
133
|
+
for (const e of events) {
|
|
134
|
+
if (firstTs === null || e.ts < firstTs)
|
|
135
|
+
firstTs = e.ts;
|
|
136
|
+
if (lastTs === null || e.ts > lastTs)
|
|
137
|
+
lastTs = e.ts;
|
|
138
|
+
const day = dayKey(e.ts);
|
|
139
|
+
let d = byDay.get(day);
|
|
140
|
+
if (!d)
|
|
141
|
+
byDay.set(day, (d = { day, requests: 0, tokens: 0 }));
|
|
142
|
+
if (e.type === 'message.started') {
|
|
143
|
+
requests++;
|
|
144
|
+
d.requests++;
|
|
145
|
+
if (e.model)
|
|
146
|
+
models.set(e.model, (models.get(e.model) ?? 0) + 1);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const t = e.tokens ?? 0;
|
|
150
|
+
tokens += t;
|
|
151
|
+
d.tokens += t;
|
|
152
|
+
if (e.cost === null || e.cost === undefined)
|
|
153
|
+
costMissing++;
|
|
154
|
+
else {
|
|
155
|
+
costUsd += e.cost;
|
|
156
|
+
costReported++;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const days = [...byDay.values()].sort((a, b) => a.day.localeCompare(b.day));
|
|
161
|
+
let busiest = null;
|
|
162
|
+
for (const d of days) {
|
|
163
|
+
if (!busiest ||
|
|
164
|
+
d.tokens > busiest.tokens ||
|
|
165
|
+
(d.tokens === busiest.tokens && d.requests > busiest.requests) ||
|
|
166
|
+
// Full tie: the LATER day wins — "busiest" reads as "the most recent time it was this busy".
|
|
167
|
+
(d.tokens === busiest.tokens && d.requests === busiest.requests && d.day > busiest.day)) {
|
|
168
|
+
busiest = d;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
requests,
|
|
173
|
+
tokens,
|
|
174
|
+
costUsd,
|
|
175
|
+
costReported,
|
|
176
|
+
costMissing,
|
|
177
|
+
models: [...models.entries()]
|
|
178
|
+
.map(([name, count]) => ({ name, count }))
|
|
179
|
+
.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name)),
|
|
180
|
+
days,
|
|
181
|
+
busiest,
|
|
182
|
+
firstTs,
|
|
183
|
+
lastTs,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const SPARK_LEVELS = ['\u2581', '\u2582', '\u2583', '\u2584', '\u2585', '\u2586', '\u2587', '\u2588'];
|
|
187
|
+
/** Eight-level block sparkline; zero maps to the floor glyph so gaps stay visible as a baseline. */
|
|
188
|
+
function sparkline(values) {
|
|
189
|
+
if (!values.length)
|
|
190
|
+
return '';
|
|
191
|
+
const max = Math.max(...values);
|
|
192
|
+
if (max <= 0)
|
|
193
|
+
return SPARK_LEVELS[0].repeat(values.length);
|
|
194
|
+
return values.map((v) => SPARK_LEVELS[Math.min(7, Math.max(0, Math.floor((v / max) * 7)))]).join('');
|
|
195
|
+
}
|
|
196
|
+
function sessionsRoot(env) {
|
|
197
|
+
return env.NEXRALL_CLI_SESSIONS_DIR || path.join(os.homedir(), '.nexrall', 'cli-sessions');
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Read the newest event logs and narrow them to UsageEventLite rows.
|
|
201
|
+
* Everything here is best-effort: a missing directory (fresh install), an
|
|
202
|
+
* unreadable file or a torn JSON line must degrade the panel, never fail the
|
|
203
|
+
* command — the numbers are a courtesy, the session is the job.
|
|
204
|
+
*/
|
|
205
|
+
function loadUsageStats(env = process.env) {
|
|
206
|
+
const root = sessionsRoot(env);
|
|
207
|
+
const dir = path.join(root, 'events');
|
|
208
|
+
let names;
|
|
209
|
+
try {
|
|
210
|
+
names = fs.readdirSync(dir).filter((f) => f.endsWith('.jsonl'));
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
names = [];
|
|
214
|
+
}
|
|
215
|
+
const sessionsWithLogs = names.length;
|
|
216
|
+
// Newest first, by mtime — ids are hex so name order ≈ creation order, but
|
|
217
|
+
// a resumed session keeps its id and grows old, so mtime is the honest key.
|
|
218
|
+
const dated = names
|
|
219
|
+
.map((f) => {
|
|
220
|
+
let m = 0;
|
|
221
|
+
try {
|
|
222
|
+
m = fs.statSync(path.join(dir, f)).mtimeMs;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
/* keep 0 — sorted last */
|
|
226
|
+
}
|
|
227
|
+
return { f, m };
|
|
228
|
+
})
|
|
229
|
+
.sort((a, b) => b.m - a.m)
|
|
230
|
+
.slice(0, exports.MAX_EVENT_FILES);
|
|
231
|
+
const events = [];
|
|
232
|
+
for (const { f } of dated) {
|
|
233
|
+
let raw;
|
|
234
|
+
try {
|
|
235
|
+
raw = fs.readFileSync(path.join(dir, f), 'utf8');
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
for (const line of raw.split('\n')) {
|
|
241
|
+
if (!line.trim())
|
|
242
|
+
continue;
|
|
243
|
+
let obj;
|
|
244
|
+
try {
|
|
245
|
+
obj = JSON.parse(line);
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const lite = liteEvent(obj);
|
|
251
|
+
if (lite)
|
|
252
|
+
events.push(lite);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
let savedSessions;
|
|
256
|
+
try {
|
|
257
|
+
savedSessions = fs.readdirSync(root).filter((f) => f.endsWith('.json')).length;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
savedSessions = 0;
|
|
261
|
+
}
|
|
262
|
+
return { events, savedSessions, sessionsWithLogs, readFiles: dated.length };
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=sessionStats.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type ImportKind = 'command' | 'agent' | 'skill' | 'brief' | 'permissions' | 'hooks';
|
|
2
|
+
export interface PlanItem {
|
|
3
|
+
kind: ImportKind;
|
|
4
|
+
/** Source path (file or directory). */
|
|
5
|
+
from: string;
|
|
6
|
+
/** Destination path. For settings merges, the settings file. */
|
|
7
|
+
to: string;
|
|
8
|
+
status: 'copy' | 'merge' | 'skip-exists' | 'skip-empty';
|
|
9
|
+
/** One-line human detail (e.g. "3 allow rules"). */
|
|
10
|
+
note?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ImportPlan {
|
|
13
|
+
items: PlanItem[];
|
|
14
|
+
/** settings.json keys found in the source that nex deliberately does not import. */
|
|
15
|
+
ignoredSettings: string[];
|
|
16
|
+
/** Nothing to import was found at all. */
|
|
17
|
+
empty: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Renamed from `Scope` (2026-10-04) to avoid colliding with the search
|
|
20
|
+
* engine's Scope in core's index; same meaning, import-specific name. */
|
|
21
|
+
export type ImportScope = 'project' | 'user';
|
|
22
|
+
export interface Roots {
|
|
23
|
+
/** The Claude side: a directory containing `.claude/` and maybe CLAUDE.md. */
|
|
24
|
+
sourceBase: string;
|
|
25
|
+
/** The nex side: a directory that will contain `.nexrall/` and nexrall.md. */
|
|
26
|
+
destBase: string;
|
|
27
|
+
/** user scope reads/writes ~/.claude → ~/.nexrall and has no brief file. */
|
|
28
|
+
scope: ImportScope;
|
|
29
|
+
}
|
|
30
|
+
export declare function planImport(r: Roots): ImportPlan;
|
|
31
|
+
export interface ApplyResult {
|
|
32
|
+
done: PlanItem[];
|
|
33
|
+
failed: Array<{
|
|
34
|
+
item: PlanItem;
|
|
35
|
+
error: string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Carry out a plan. Idempotent: a second run finds everything already present and does nothing.
|
|
40
|
+
* Settings are merged additively — existing rules and hooks are kept, new ones appended.
|
|
41
|
+
*/
|
|
42
|
+
export declare function applyImport(plan: ImportPlan): ApplyResult;
|
|
43
|
+
export declare function formatPlan(plan: ImportPlan, apply: boolean, base: string): string[];
|
|
44
|
+
//# sourceMappingURL=claudeImport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeImport.d.ts","sourceRoot":"","sources":["../../src/import/claudeImport.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,GAAG,OAAO,CAAC;AAC3F,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,YAAY,CAAC;IACxD,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,oFAAoF;IACpF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,0CAA0C;IAC1C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;0EAC0E;AAC1E,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAoD7C,MAAM,WAAW,KAAK;IACpB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG,UAAU,CA2F/C;AAoBD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAmEzD;AAWD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BnF"}
|