@claudemini/shit-cli 1.1.0 → 1.1.1
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/report.js +113 -2
- package/lib/session.js +39 -4
- package/package.json +1 -1
package/lib/report.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Report generation module.
|
|
5
5
|
* Produces summary.json (v2, bot-readable), summary.txt (human-readable),
|
|
6
|
-
* prompts.txt, and metadata.json from session state + semantic data.
|
|
6
|
+
* prompts.txt, context.md, and metadata.json from session state + semantic data.
|
|
7
|
+
* Reference: Entire CLI's checkpoint format
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { writeFileSync } from 'fs';
|
|
@@ -21,6 +22,7 @@ export function generateReports(sessionDir, sessionId, state, intent, changes, c
|
|
|
21
22
|
writeSummaryTxt(sessionDir, sessionId, state, intent, changes, classification, durationMin);
|
|
22
23
|
writePromptsTxt(sessionDir, state);
|
|
23
24
|
writeMetadataJson(sessionDir, sessionId, state, intent, classification, durationMin);
|
|
25
|
+
writeContextMd(sessionDir, sessionId, state, intent, changes, durationMin);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
function writeSummaryJson(sessionDir, sessionId, state, intent, changes, classification, durationMin) {
|
|
@@ -61,7 +63,9 @@ function writeSummaryJson(sessionDir, sessionId, state, intent, changes, classif
|
|
|
61
63
|
config_changed: classification.reviewHints.configChanged,
|
|
62
64
|
migration_added: classification.reviewHints.migrationAdded,
|
|
63
65
|
},
|
|
64
|
-
prompts: state.prompts.map(p => typeof p === 'string' ? p : p.text),
|
|
66
|
+
prompts: state.prompts.map(p => typeof p === 'string' ? p : { time: p.time, text: p.text, type: p.type }),
|
|
67
|
+
transcript: state.transcript_path,
|
|
68
|
+
model: state.model,
|
|
65
69
|
scope: intent.scope,
|
|
66
70
|
};
|
|
67
71
|
writeFileSync(join(sessionDir, 'summary.json'), JSON.stringify(summary, null, 2));
|
|
@@ -181,5 +185,112 @@ function writeMetadataJson(sessionDir, sessionId, state, intent, classification,
|
|
|
181
185
|
errors: state.errors.length,
|
|
182
186
|
scope: intent.scope,
|
|
183
187
|
last_hook_type: state.last_hook_type,
|
|
188
|
+
// Enhanced metadata for Entire-style tracking
|
|
189
|
+
transcript_path: state.transcript_path || null,
|
|
190
|
+
model: state.model || null,
|
|
191
|
+
cwd: state.cwd || null,
|
|
184
192
|
}, null, 2));
|
|
185
193
|
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Write context.md - human-readable session context (Entire-style)
|
|
197
|
+
*/
|
|
198
|
+
function writeContextMd(sessionDir, sessionId, state, intent, changes, durationMin) {
|
|
199
|
+
const lines = [];
|
|
200
|
+
|
|
201
|
+
// Header
|
|
202
|
+
lines.push(`# Session Context: ${sessionId}`);
|
|
203
|
+
lines.push('');
|
|
204
|
+
lines.push(`**Started**: ${state.start_time ? new Date(state.start_time).toLocaleString() : 'unknown'}`);
|
|
205
|
+
lines.push(`**Ended**: ${state.last_time ? new Date(state.last_time).toLocaleString() : 'in progress'}`);
|
|
206
|
+
lines.push(`**Duration**: ${durationMin} minutes`);
|
|
207
|
+
lines.push(`**Model**: ${state.model || 'unknown'}`);
|
|
208
|
+
lines.push(`**Working Directory**: ${state.cwd || 'unknown'}`);
|
|
209
|
+
lines.push(`**Events**: ${state.event_count}`);
|
|
210
|
+
lines.push('');
|
|
211
|
+
|
|
212
|
+
// Transcript reference (Entire-style)
|
|
213
|
+
if (state.transcript_path) {
|
|
214
|
+
lines.push('## Transcript');
|
|
215
|
+
lines.push(`Full transcript available at: \`${state.transcript_path}\``);
|
|
216
|
+
lines.push('');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// User Prompts
|
|
220
|
+
if (state.prompts && state.prompts.length > 0) {
|
|
221
|
+
lines.push('## User Prompts');
|
|
222
|
+
lines.push('');
|
|
223
|
+
state.prompts.forEach((p, i) => {
|
|
224
|
+
const time = p.time ? new Date(p.time).toLocaleString() : '';
|
|
225
|
+
const text = typeof p === 'string' ? p : p.text;
|
|
226
|
+
const type = typeof p === 'object' && p.type ? ` [${p.type}]` : '';
|
|
227
|
+
|
|
228
|
+
lines.push(`### Prompt ${i + 1}${type}${time ? ` - ${time}` : ''}`);
|
|
229
|
+
lines.push('');
|
|
230
|
+
lines.push('```');
|
|
231
|
+
lines.push(text.slice(0, 2000));
|
|
232
|
+
lines.push('```');
|
|
233
|
+
lines.push('');
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Intent & Scope
|
|
238
|
+
if (intent.goal) {
|
|
239
|
+
lines.push('## Intent');
|
|
240
|
+
lines.push('');
|
|
241
|
+
lines.push(intent.goal);
|
|
242
|
+
lines.push('');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (intent.scope && intent.scope.length > 0) {
|
|
246
|
+
lines.push('## Scope');
|
|
247
|
+
lines.push('');
|
|
248
|
+
intent.scope.forEach(s => lines.push(`- ${s}`));
|
|
249
|
+
lines.push('');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Changes Summary
|
|
253
|
+
const modified = changes.files.filter(f => f.operations.some(op => op !== 'read'));
|
|
254
|
+
if (modified.length > 0) {
|
|
255
|
+
lines.push('## Files Changed');
|
|
256
|
+
lines.push('');
|
|
257
|
+
modified.slice(0, 30).forEach(f => {
|
|
258
|
+
const ops = f.operations.filter(op => op !== 'read').join(', ');
|
|
259
|
+
lines.push(`- \`${f.path}\` (${ops})`);
|
|
260
|
+
});
|
|
261
|
+
if (modified.length > 30) {
|
|
262
|
+
lines.push(`- ... and ${modified.length - 30} more files`);
|
|
263
|
+
}
|
|
264
|
+
lines.push('');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Tool Usage
|
|
268
|
+
if (Object.keys(state.tool_counts).length > 0) {
|
|
269
|
+
lines.push('## Tool Usage');
|
|
270
|
+
lines.push('');
|
|
271
|
+
Object.entries(state.tool_counts)
|
|
272
|
+
.sort((a, b) => b[1] - a[1])
|
|
273
|
+
.forEach(([tool, count]) => {
|
|
274
|
+
lines.push(`- ${tool}: ${count}`);
|
|
275
|
+
});
|
|
276
|
+
lines.push('');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Errors
|
|
280
|
+
if (state.errors.length > 0) {
|
|
281
|
+
lines.push('## Errors');
|
|
282
|
+
lines.push('');
|
|
283
|
+
state.errors.slice(0, 10).forEach(e => {
|
|
284
|
+
lines.push(`- **[${e.tool}]** ${(e.message || '').slice(0, 200)}`);
|
|
285
|
+
});
|
|
286
|
+
lines.push('');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Footer
|
|
290
|
+
lines.push('---');
|
|
291
|
+
lines.push('');
|
|
292
|
+
lines.push(`*Generated by shit-cli at ${new Date().toISOString()}*`);
|
|
293
|
+
lines.push(`*See \`events.jsonl\` for complete event history*`);
|
|
294
|
+
|
|
295
|
+
writeFileSync(join(sessionDir, 'context.md'), lines.join('\n') + '\n');
|
|
296
|
+
}
|
package/lib/session.js
CHANGED
|
@@ -22,6 +22,10 @@ const EMPTY_STATE = {
|
|
|
22
22
|
prompts: [],
|
|
23
23
|
last_hook_type: null,
|
|
24
24
|
shadow_branch: null,
|
|
25
|
+
// Enhanced fields for Entire-style tracking
|
|
26
|
+
transcript_path: null,
|
|
27
|
+
cwd: null,
|
|
28
|
+
model: null,
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
export function loadState(sessionDir) {
|
|
@@ -63,10 +67,41 @@ export function processEvent(state, event, hookType, projectRoot) {
|
|
|
63
67
|
const toolName = event.tool_name;
|
|
64
68
|
const input = event.tool_input || {};
|
|
65
69
|
|
|
66
|
-
// User prompts
|
|
67
|
-
if (hookType === 'user-prompt-submit') {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
// User prompts - support both camelCase and kebab-case
|
|
71
|
+
if (hookType === 'user-prompt-submit' || hookType === 'UserPromptSubmit') {
|
|
72
|
+
// Extract prompt from various possible fields
|
|
73
|
+
let prompt = '';
|
|
74
|
+
if (event.prompt) {
|
|
75
|
+
prompt = typeof event.prompt === 'string' ? event.prompt :
|
|
76
|
+
event.prompt.text || event.prompt.message || JSON.stringify(event.prompt).slice(0, 500);
|
|
77
|
+
} else if (event.message) {
|
|
78
|
+
prompt = typeof event.message === 'string' ? event.message :
|
|
79
|
+
event.message.text || JSON.stringify(event.message).slice(0, 500);
|
|
80
|
+
} else if (event.text) {
|
|
81
|
+
prompt = event.text;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (prompt) {
|
|
85
|
+
state.prompts.push({
|
|
86
|
+
time: now,
|
|
87
|
+
text: prompt.slice(0, 2000), // Limit prompt length
|
|
88
|
+
type: event.prompt_type || 'user'
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Record transcript path from SessionStart
|
|
95
|
+
if (hookType === 'session-start' || hookType === 'SessionStart') {
|
|
96
|
+
if (event.transcript_path) {
|
|
97
|
+
state.transcript_path = event.transcript_path;
|
|
98
|
+
}
|
|
99
|
+
if (event.cwd) {
|
|
100
|
+
state.cwd = event.cwd;
|
|
101
|
+
}
|
|
102
|
+
if (event.model) {
|
|
103
|
+
state.model = event.model;
|
|
104
|
+
}
|
|
70
105
|
return;
|
|
71
106
|
}
|
|
72
107
|
|