getprismo 0.1.54 → 0.1.55
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/lib/prismo-dev/cli.js +33 -1
- package/lib/prismo-dev/help.js +4 -0
- package/lib/prismo-dev/sessions-report.js +196 -0
- package/lib/prismo-dev-scan.js +16 -0
- package/package.json +1 -1
package/lib/prismo-dev/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ const { printHelp, printCommandHelp } = require("./help");
|
|
|
3
3
|
|
|
4
4
|
const VALID_COMMANDS = new Set([
|
|
5
5
|
"dev", "init", "doctor", "firewall", "benchmark", "shield", "mcp",
|
|
6
|
-
"connect", "sync", "status", "disconnect", "agent", "connector", "setup", "scan", "digest",
|
|
6
|
+
"connect", "sync", "status", "disconnect", "agent", "connector", "setup", "scan", "digest", "sessions", "report",
|
|
7
7
|
"optimize", "context", "cc", "cursor", "receipt", "instructions",
|
|
8
8
|
"timeline", "replay", "boundaries", "usage", "guard", "watch", "demo", "repair",
|
|
9
9
|
"enforce", "bridge", "hook", "protect",
|
|
@@ -69,6 +69,10 @@ function createCli(deps) {
|
|
|
69
69
|
runDisconnect,
|
|
70
70
|
runStatus,
|
|
71
71
|
runSync,
|
|
72
|
+
buildSessionsView,
|
|
73
|
+
renderSessionsTerminal,
|
|
74
|
+
buildLocalReport,
|
|
75
|
+
renderLocalReportTerminal,
|
|
72
76
|
renderGuardTerminal,
|
|
73
77
|
runGuard,
|
|
74
78
|
REPAIR_CAUSES,
|
|
@@ -474,6 +478,34 @@ function createCli(deps) {
|
|
|
474
478
|
return;
|
|
475
479
|
}
|
|
476
480
|
|
|
481
|
+
if (command === "sessions") {
|
|
482
|
+
const json = rest.includes("--json");
|
|
483
|
+
const limitIndex = rest.indexOf("--limit");
|
|
484
|
+
const toolIndex = rest.indexOf("--tool");
|
|
485
|
+
const target = getPositionals(rest, new Set(["--limit", "--tool"]))[0] || process.cwd();
|
|
486
|
+
const view = buildSessionsView(target, {
|
|
487
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 10),
|
|
488
|
+
tool: toolIndex >= 0 ? rest[toolIndex + 1] : "all",
|
|
489
|
+
allRepos: rest.includes("--all-repos"),
|
|
490
|
+
});
|
|
491
|
+
if (json) console.log(JSON.stringify(view, null, 2));
|
|
492
|
+
else console.log(renderSessionsTerminal(view));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (command === "report") {
|
|
497
|
+
const json = rest.includes("--json");
|
|
498
|
+
const limitIndex = rest.indexOf("--limit");
|
|
499
|
+
const target = getPositionals(rest, new Set(["--limit"]))[0] || process.cwd();
|
|
500
|
+
const report = buildLocalReport(target, {
|
|
501
|
+
limit: parsePositiveInt(limitIndex >= 0 ? rest[limitIndex + 1] : null, 10),
|
|
502
|
+
allRepos: rest.includes("--all-repos"),
|
|
503
|
+
});
|
|
504
|
+
if (json) console.log(JSON.stringify(report, null, 2));
|
|
505
|
+
else console.log(renderLocalReportTerminal(report));
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
477
509
|
if (command === "digest") {
|
|
478
510
|
const json = rest.includes("--json");
|
|
479
511
|
const daysIndex = rest.indexOf("--days");
|
package/lib/prismo-dev/help.js
CHANGED
|
@@ -17,6 +17,8 @@ Usage:
|
|
|
17
17
|
prismo bridge [--json] [path]
|
|
18
18
|
prismo sync [--json] [--dry-run] [--watch] [--all-repos] [--interval N] [--limit N] [--tool all|codex|claude|cursor] [path]
|
|
19
19
|
prismo status [--json]
|
|
20
|
+
prismo sessions [--json] [--all-repos] [--limit N] [--tool all|codex|claude|cursor] [path]
|
|
21
|
+
prismo report [--json] [--all-repos] [--limit N] [path]
|
|
20
22
|
prismo digest [--json] [--days N]
|
|
21
23
|
prismo disconnect [--json]
|
|
22
24
|
prismo agent [--json] [--once] [--watch] [--interval N] [--sync-interval N] [--limit N] [--mode MODE] [path]
|
|
@@ -54,6 +56,8 @@ Commands:
|
|
|
54
56
|
bridge Explain optional agent bridge mode and live interception levels.
|
|
55
57
|
sync Send safe aggregate local agent telemetry to Prismo; use --watch for background-style sync.
|
|
56
58
|
status Show local PrismoDev connection and last sync state.
|
|
59
|
+
sessions List recent local agent sessions with tokens, waste, risk, and top cause (add --all-repos for every repo).
|
|
60
|
+
report Local waste snapshot: observed/wasted tokens, top causes, repeated reads/commands, and the next action. No connection needed.
|
|
57
61
|
digest Print the launch report: verified saved tokens/dollars first, with live prevention labeled estimated.
|
|
58
62
|
disconnect Remove the local PrismoDev cloud connection.
|
|
59
63
|
agent Claim and execute safe workspace actions queued from Prismo Cloud.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
module.exports = function createSessionsReport(deps) {
|
|
2
|
+
const {
|
|
3
|
+
path,
|
|
4
|
+
getUsageSummary,
|
|
5
|
+
estimateWaste,
|
|
6
|
+
formatTokenCount,
|
|
7
|
+
} = deps;
|
|
8
|
+
|
|
9
|
+
const CAUSE_LABELS = {
|
|
10
|
+
"tool-output-flood": "Tool-output floods",
|
|
11
|
+
"repeated-file-reads": "Repeated file reads",
|
|
12
|
+
"generated-artifacts": "Generated artifacts",
|
|
13
|
+
"context-loop": "Context loops",
|
|
14
|
+
"long-session-buildup": "Long-session buildup",
|
|
15
|
+
"low-signal": "No strong waste signal",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const NEXT_ACTION = {
|
|
19
|
+
"tool-output-flood": "Run noisy commands through `prismo shield -- <command>` so output stays out of context.",
|
|
20
|
+
"repeated-file-reads": "Run `prismo repair repeated-file-reads`, then start sessions from .prismo context packs.",
|
|
21
|
+
"generated-artifacts": "Run `prismo repair generated-artifacts` to ignore build output and artifacts.",
|
|
22
|
+
"context-loop": "Run `prismo repair context-loop` and stop retrying failing commands.",
|
|
23
|
+
"long-session-buildup": "Split work at task boundaries; start fresh sessions from `prismo context`.",
|
|
24
|
+
"low-signal": "Nothing urgent. Run `prismo doctor` for a baseline.",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function repoBasename(session, fallbackRoot) {
|
|
28
|
+
const cwd = session && session.cwd ? session.cwd : fallbackRoot;
|
|
29
|
+
try {
|
|
30
|
+
return path.basename(path.resolve(cwd || process.cwd()));
|
|
31
|
+
} catch {
|
|
32
|
+
return "unknown";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function collect(rootDir, options = {}) {
|
|
37
|
+
const root = path.resolve(rootDir || process.cwd());
|
|
38
|
+
const summary = getUsageSummary({
|
|
39
|
+
cwd: root,
|
|
40
|
+
tool: options.tool || "all",
|
|
41
|
+
limit: options.limit || 10,
|
|
42
|
+
allRepos: Boolean(options.allRepos),
|
|
43
|
+
});
|
|
44
|
+
const sessions = (summary.sessions || []).map((session) => {
|
|
45
|
+
const waste = estimateWaste(session);
|
|
46
|
+
return {
|
|
47
|
+
tool: session.tool || "unknown",
|
|
48
|
+
repo: repoBasename(session, root),
|
|
49
|
+
title: session.title || null,
|
|
50
|
+
model: session.model || null,
|
|
51
|
+
updatedAt: session.updatedAt || session.startedAt || null,
|
|
52
|
+
risk: session.contextRisk || "Unknown",
|
|
53
|
+
tokens: Number(waste.tokens || 0),
|
|
54
|
+
wastedTokens: Number(waste.wastedTokens || 0),
|
|
55
|
+
wastePercent: Number(waste.wastePercent || 0),
|
|
56
|
+
topCause: waste.topCause || "low-signal",
|
|
57
|
+
repeatedCommands: session.repeatedCommands || [],
|
|
58
|
+
repeatedPaths: session.repeatedPathMentions || [],
|
|
59
|
+
loopSuspicion: Boolean(session.loopSuspicion),
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
return { root, sessions, generatedAt: new Date().toISOString() };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function buildSessionsView(rootDir, options = {}) {
|
|
66
|
+
const { root, sessions, generatedAt } = collect(rootDir, options);
|
|
67
|
+
const totals = sessions.reduce((acc, s) => {
|
|
68
|
+
acc.sessions += 1;
|
|
69
|
+
acc.tokens += s.tokens;
|
|
70
|
+
acc.wastedTokens += s.wastedTokens;
|
|
71
|
+
return acc;
|
|
72
|
+
}, { sessions: 0, tokens: 0, wastedTokens: 0 });
|
|
73
|
+
totals.wastePercent = totals.tokens > 0 ? Math.round((totals.wastedTokens / totals.tokens) * 100) : 0;
|
|
74
|
+
return {
|
|
75
|
+
schemaVersion: 1,
|
|
76
|
+
command: "sessions",
|
|
77
|
+
scannedPath: root,
|
|
78
|
+
allRepos: Boolean(options.allRepos),
|
|
79
|
+
sessions: sessions.sort((a, b) => String(b.updatedAt || "").localeCompare(String(a.updatedAt || ""))),
|
|
80
|
+
totals,
|
|
81
|
+
generatedAt,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function renderSessionsTerminal(view) {
|
|
86
|
+
const lines = [];
|
|
87
|
+
lines.push("");
|
|
88
|
+
lines.push("PrismoDev Sessions");
|
|
89
|
+
lines.push("");
|
|
90
|
+
if (!view.sessions.length) {
|
|
91
|
+
lines.push("No recent local agent sessions found.");
|
|
92
|
+
lines.push(view.allRepos ? "" : "Tip: add --all-repos to look across every repo on this machine.");
|
|
93
|
+
return lines.join("\n").trimEnd();
|
|
94
|
+
}
|
|
95
|
+
for (const s of view.sessions) {
|
|
96
|
+
const when = s.updatedAt ? new Date(s.updatedAt).toLocaleString() : "unknown time";
|
|
97
|
+
lines.push(`${s.tool.padEnd(12)} ${s.repo} · ${when}`);
|
|
98
|
+
lines.push(` ${formatTokenCount(s.tokens)} tokens | ~${formatTokenCount(s.wastedTokens)} wasted (${s.wastePercent}%) | ${s.risk} risk | ${CAUSE_LABELS[s.topCause] || s.topCause}`);
|
|
99
|
+
}
|
|
100
|
+
lines.push("");
|
|
101
|
+
lines.push(`Totals: ${view.totals.sessions} session(s) · ${formatTokenCount(view.totals.tokens)} tokens · ~${formatTokenCount(view.totals.wastedTokens)} likely wasted (${view.totals.wastePercent}%)`);
|
|
102
|
+
return lines.join("\n");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildLocalReport(rootDir, options = {}) {
|
|
106
|
+
const { root, sessions, generatedAt } = collect(rootDir, { ...options, allRepos: options.allRepos });
|
|
107
|
+
const observed = sessions.reduce((sum, s) => sum + s.tokens, 0);
|
|
108
|
+
const wasted = sessions.reduce((sum, s) => sum + s.wastedTokens, 0);
|
|
109
|
+
|
|
110
|
+
const causeTotals = new Map();
|
|
111
|
+
for (const s of sessions) {
|
|
112
|
+
if (s.topCause === "low-signal") continue;
|
|
113
|
+
causeTotals.set(s.topCause, (causeTotals.get(s.topCause) || 0) + s.wastedTokens);
|
|
114
|
+
}
|
|
115
|
+
const topCauses = Array.from(causeTotals, ([cause, tokens]) => ({
|
|
116
|
+
cause,
|
|
117
|
+
label: CAUSE_LABELS[cause] || cause,
|
|
118
|
+
tokens,
|
|
119
|
+
})).sort((a, b) => b.tokens - a.tokens).slice(0, 5);
|
|
120
|
+
|
|
121
|
+
const repeatedReads = aggregate(sessions, (s) => s.repeatedPaths).slice(0, 5);
|
|
122
|
+
const repeatedCommands = aggregate(sessions, (s) => s.repeatedCommands).slice(0, 5);
|
|
123
|
+
const loopSessions = sessions.filter((s) => s.loopSuspicion).length;
|
|
124
|
+
const primaryCause = topCauses[0] ? topCauses[0].cause : "low-signal";
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
schemaVersion: 1,
|
|
128
|
+
command: "report",
|
|
129
|
+
scannedPath: root,
|
|
130
|
+
allRepos: Boolean(options.allRepos),
|
|
131
|
+
sessions: sessions.length,
|
|
132
|
+
observedTokens: observed,
|
|
133
|
+
wastedTokens: wasted,
|
|
134
|
+
wastePercent: observed > 0 ? Math.round((wasted / observed) * 100) : 0,
|
|
135
|
+
topCauses,
|
|
136
|
+
repeatedReads,
|
|
137
|
+
repeatedCommands,
|
|
138
|
+
loopSessions,
|
|
139
|
+
nextAction: NEXT_ACTION[primaryCause] || NEXT_ACTION["low-signal"],
|
|
140
|
+
note: "Local estimate from your own session logs. Connect with `prismo connect` for verified, dollar-denominated savings.",
|
|
141
|
+
generatedAt,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function aggregate(sessions, pick) {
|
|
146
|
+
const totals = new Map();
|
|
147
|
+
for (const s of sessions) {
|
|
148
|
+
for (const item of pick(s) || []) {
|
|
149
|
+
if (!item || !item.value) continue;
|
|
150
|
+
totals.set(item.value, (totals.get(item.value) || 0) + Number(item.count || 0));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return Array.from(totals, ([value, count]) => ({ value, count })).sort((a, b) => b.count - a.count);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function renderLocalReportTerminal(report) {
|
|
157
|
+
const lines = [];
|
|
158
|
+
lines.push("");
|
|
159
|
+
lines.push("PrismoDev Report");
|
|
160
|
+
lines.push("");
|
|
161
|
+
if (!report.sessions) {
|
|
162
|
+
lines.push("No recent local agent sessions found.");
|
|
163
|
+
lines.push(report.allRepos ? "" : "Tip: add --all-repos to look across every repo on this machine.");
|
|
164
|
+
return lines.join("\n").trimEnd();
|
|
165
|
+
}
|
|
166
|
+
lines.push(`Observed: ${formatTokenCount(report.observedTokens)} tokens across ${report.sessions} session(s)`);
|
|
167
|
+
lines.push(`Likely wasted: ${formatTokenCount(report.wastedTokens)} (${report.wastePercent}%)`);
|
|
168
|
+
if (report.loopSessions) lines.push(`Loop-suspect sessions: ${report.loopSessions}`);
|
|
169
|
+
if (report.topCauses.length) {
|
|
170
|
+
lines.push("");
|
|
171
|
+
lines.push("Top causes:");
|
|
172
|
+
report.topCauses.forEach((c) => lines.push(`- ${c.label}: ~${formatTokenCount(c.tokens)} tokens`));
|
|
173
|
+
}
|
|
174
|
+
if (report.repeatedReads.length) {
|
|
175
|
+
lines.push("");
|
|
176
|
+
lines.push("Most repeated reads:");
|
|
177
|
+
report.repeatedReads.forEach((r) => lines.push(`- ${r.value} (${r.count}x)`));
|
|
178
|
+
}
|
|
179
|
+
if (report.repeatedCommands.length) {
|
|
180
|
+
lines.push("");
|
|
181
|
+
lines.push("Most repeated commands:");
|
|
182
|
+
report.repeatedCommands.forEach((r) => lines.push(`- ${r.value} (${r.count}x)`));
|
|
183
|
+
}
|
|
184
|
+
lines.push("");
|
|
185
|
+
lines.push(`Next: ${report.nextAction}`);
|
|
186
|
+
lines.push(report.note);
|
|
187
|
+
return lines.join("\n");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
buildSessionsView,
|
|
192
|
+
renderSessionsTerminal,
|
|
193
|
+
buildLocalReport,
|
|
194
|
+
renderLocalReportTerminal,
|
|
195
|
+
};
|
|
196
|
+
};
|
package/lib/prismo-dev-scan.js
CHANGED
|
@@ -355,6 +355,18 @@ const {
|
|
|
355
355
|
runFirewall,
|
|
356
356
|
});
|
|
357
357
|
|
|
358
|
+
const {
|
|
359
|
+
buildSessionsView,
|
|
360
|
+
renderSessionsTerminal,
|
|
361
|
+
buildLocalReport,
|
|
362
|
+
renderLocalReportTerminal,
|
|
363
|
+
} = require("./prismo-dev/sessions-report")({
|
|
364
|
+
path,
|
|
365
|
+
getUsageSummary,
|
|
366
|
+
estimateWaste,
|
|
367
|
+
formatTokenCount,
|
|
368
|
+
});
|
|
369
|
+
|
|
358
370
|
const repairPlanner = require("./prismo-dev/repair-planner")({
|
|
359
371
|
fs,
|
|
360
372
|
path,
|
|
@@ -510,6 +522,10 @@ const { runCli } = require("./prismo-dev/cli")({
|
|
|
510
522
|
runDisconnect,
|
|
511
523
|
runStatus,
|
|
512
524
|
runSync,
|
|
525
|
+
buildSessionsView,
|
|
526
|
+
renderSessionsTerminal,
|
|
527
|
+
buildLocalReport,
|
|
528
|
+
renderLocalReportTerminal,
|
|
513
529
|
renderGuardTerminal,
|
|
514
530
|
runGuard,
|
|
515
531
|
REPAIR_CAUSES,
|
package/package.json
CHANGED