@jetcrab/pi-desk-usage 1.1.0 → 1.1.1-dev
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/l4-usage-files.d.ts +1 -0
- package/dist/l4-usage-files.js +24 -0
- package/dist/usage-runtime.js +28 -13
- package/package.json +1 -1
package/dist/l4-usage-files.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ import type { UsageFileDescriptor } from './usage-scan.js';
|
|
|
2
2
|
export declare function pathKey(value: string): string;
|
|
3
3
|
export declare function nestedParentSessionId(filePath: string): string | null;
|
|
4
4
|
export declare function descriptor(path: string, nestedSubagent: boolean): Promise<UsageFileDescriptor | null>;
|
|
5
|
+
export declare function listSessionCandidates(root: string, cwd: string, sessionId: string): Promise<UsageFileDescriptor[]>;
|
|
5
6
|
export declare function listStandardSessionFiles(root: string): Promise<UsageFileDescriptor[]>;
|
package/dist/l4-usage-files.js
CHANGED
|
@@ -42,6 +42,30 @@ export async function descriptor(path, nestedSubagent) {
|
|
|
42
42
|
function isSessionJsonlFile(name) {
|
|
43
43
|
return name.endsWith('.jsonl') && !name.includes('.jsonl.');
|
|
44
44
|
}
|
|
45
|
+
export async function listSessionCandidates(root, cwd, sessionId) {
|
|
46
|
+
const directoryName = `--${resolve(cwd)
|
|
47
|
+
.replace(/^[/\\]/, '')
|
|
48
|
+
.replace(/[/\\:]/g, '-')}--`;
|
|
49
|
+
const suffix = `_${sessionId}.jsonl`.toLowerCase();
|
|
50
|
+
const files = [];
|
|
51
|
+
for (const directory of [join(root, directoryName), root]) {
|
|
52
|
+
let entries;
|
|
53
|
+
try {
|
|
54
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
if (!entry.isFile() || !entry.name.toLowerCase().endsWith(suffix))
|
|
61
|
+
continue;
|
|
62
|
+
const file = await descriptor(join(directory, entry.name), false);
|
|
63
|
+
if (file)
|
|
64
|
+
files.push(file);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return files;
|
|
68
|
+
}
|
|
45
69
|
async function nestedSessionFiles(directory) {
|
|
46
70
|
let entries;
|
|
47
71
|
try {
|
package/dist/usage-runtime.js
CHANGED
|
@@ -6,7 +6,7 @@ import { PluginMethodError } from '@jetcrab/pi-desk-sdk/session';
|
|
|
6
6
|
import { usageBucketRanges, usageBucketIndex, zonedHourStart } from './l4-usage-calendar.js';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { addTotals, aggregateEventModels, emptyStructureCounts, emptyTotals, hasUsage, promptTokens, totalEvents } from './l4-usage-aggregate.js';
|
|
9
|
-
import { descriptor, listStandardSessionFiles, nestedParentSessionId, pathKey } from './l4-usage-files.js';
|
|
9
|
+
import { descriptor, listSessionCandidates, listStandardSessionFiles, nestedParentSessionId, pathKey } from './l4-usage-files.js';
|
|
10
10
|
import { createUsageActivities, createUsageTimeline } from './usage-timeline.js';
|
|
11
11
|
const HOUR_MS = 60 * 60 * 1000;
|
|
12
12
|
const HALF_HOUR_MS = HOUR_MS / 2;
|
|
@@ -396,10 +396,7 @@ export class UsageRuntime {
|
|
|
396
396
|
});
|
|
397
397
|
}
|
|
398
398
|
async loadSessionDetails(workSession, signal) {
|
|
399
|
-
const main = await this.loadSessionById(workSession.source.sessionId, signal);
|
|
400
|
-
if (pathKey(main.file.cwd) !== pathKey(workSession.cwd)) {
|
|
401
|
-
throw new PluginMethodError(409, '工作会话目录与 Pi Session 不一致');
|
|
402
|
-
}
|
|
399
|
+
const main = await this.loadSessionById(workSession.source.sessionId, workSession.cwd, signal);
|
|
403
400
|
const parent = main.file.parentSessionPath
|
|
404
401
|
? await this.loadExactFile(main.file.parentSessionPath, false, signal)
|
|
405
402
|
: null;
|
|
@@ -517,21 +514,39 @@ export class UsageRuntime {
|
|
|
517
514
|
throw new PluginMethodError(409, '工作会话来源已变化');
|
|
518
515
|
return { source: workSession.source, cwd: workSession.cwd };
|
|
519
516
|
}
|
|
520
|
-
async loadSessionById(sessionId, signal) {
|
|
521
|
-
const
|
|
517
|
+
async loadSessionById(sessionId, cwd, signal) {
|
|
518
|
+
const cwdKey = pathKey(cwd);
|
|
519
|
+
const matches = (entry) => entry !== undefined &&
|
|
520
|
+
!entry.descriptor.nestedSubagent &&
|
|
521
|
+
entry.file.sessionId === sessionId &&
|
|
522
|
+
pathKey(entry.file.cwd) === cwdKey;
|
|
523
|
+
const cached = [...this.cache.values()].find(matches);
|
|
522
524
|
if (cached) {
|
|
525
|
+
const key = pathKey(cached.file.path);
|
|
523
526
|
const current = await descriptor(cached.file.path, false);
|
|
527
|
+
if (!current || signature(current) !== signature(cached.descriptor)) {
|
|
528
|
+
this.cache.delete(key);
|
|
529
|
+
}
|
|
524
530
|
if (current)
|
|
525
531
|
await this.loadChanged([current], signal);
|
|
526
|
-
const refreshed = this.cache.get(
|
|
527
|
-
if (refreshed)
|
|
532
|
+
const refreshed = this.cache.get(key);
|
|
533
|
+
if (matches(refreshed))
|
|
528
534
|
return refreshed;
|
|
529
535
|
}
|
|
530
|
-
const
|
|
531
|
-
const
|
|
532
|
-
|
|
536
|
+
const candidates = await listSessionCandidates(this.sessionsRoot, cwd, sessionId);
|
|
537
|
+
for (const candidate of candidates) {
|
|
538
|
+
const key = pathKey(candidate.path);
|
|
539
|
+
const previous = this.cache.get(key);
|
|
540
|
+
if (previous && signature(previous.descriptor) !== signature(candidate)) {
|
|
541
|
+
this.cache.delete(key);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
533
544
|
await this.loadChanged(candidates, signal);
|
|
534
|
-
const
|
|
545
|
+
const loaded = candidates.map((file) => this.cache.get(pathKey(file.path)));
|
|
546
|
+
const found = loaded.find(matches);
|
|
547
|
+
if (!found && loaded.some((entry) => entry?.file.sessionId === sessionId)) {
|
|
548
|
+
throw new PluginMethodError(409, '工作会话目录与 Pi Session 不一致');
|
|
549
|
+
}
|
|
535
550
|
if (!found)
|
|
536
551
|
throw new PluginMethodError(404, 'Pi Session 文件不存在');
|
|
537
552
|
return found;
|
package/package.json
CHANGED