@co0ontty/wand 1.1.1 → 1.1.2
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/config.js +4 -0
- package/dist/process-manager.js +10 -4
- package/dist/session-logger.d.ts +17 -3
- package/dist/session-logger.js +40 -4
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -14,6 +14,7 @@ export const defaultConfig = () => ({
|
|
|
14
14
|
defaultCwd: process.cwd(),
|
|
15
15
|
startupCommands: [],
|
|
16
16
|
allowedCommandPrefixes: [],
|
|
17
|
+
shortcutLogMaxBytes: 10 * 1024 * 1024,
|
|
17
18
|
commandPresets: [
|
|
18
19
|
{
|
|
19
20
|
label: "Claude",
|
|
@@ -87,6 +88,9 @@ function mergeWithDefaults(input) {
|
|
|
87
88
|
defaultCwd: typeof input.defaultCwd === "string" && input.defaultCwd.trim()
|
|
88
89
|
? input.defaultCwd
|
|
89
90
|
: defaults.defaultCwd,
|
|
91
|
+
shortcutLogMaxBytes: typeof input.shortcutLogMaxBytes === "number" && input.shortcutLogMaxBytes >= 0
|
|
92
|
+
? input.shortcutLogMaxBytes
|
|
93
|
+
: defaults.shortcutLogMaxBytes,
|
|
90
94
|
startupCommands: Array.isArray(input.startupCommands) ? input.startupCommands : defaults.startupCommands,
|
|
91
95
|
allowedCommandPrefixes: Array.isArray(input.allowedCommandPrefixes)
|
|
92
96
|
? input.allowedCommandPrefixes
|
package/dist/process-manager.js
CHANGED
|
@@ -731,7 +731,7 @@ export class ProcessManager extends EventEmitter {
|
|
|
731
731
|
super();
|
|
732
732
|
this.config = config;
|
|
733
733
|
this.storage = storage;
|
|
734
|
-
this.logger = new SessionLogger(configDir || path.join(process.env.HOME || process.cwd(), ".wand"));
|
|
734
|
+
this.logger = new SessionLogger(configDir || path.join(process.env.HOME || process.cwd(), ".wand"), config.shortcutLogMaxBytes);
|
|
735
735
|
// Initialize lifecycle manager
|
|
736
736
|
this.lifecycleManager = new SessionLifecycleManager({
|
|
737
737
|
onStateChange: (sessionId, oldState, newState) => {
|
|
@@ -1179,11 +1179,17 @@ export class ProcessManager extends EventEmitter {
|
|
|
1179
1179
|
inputLength: input.length,
|
|
1180
1180
|
view: view ?? "chat"
|
|
1181
1181
|
});
|
|
1182
|
-
// Log shortcut key interactions
|
|
1183
|
-
if (shortcutKey
|
|
1182
|
+
// Log shortcut key interactions for auto-confirm and mode analysis
|
|
1183
|
+
if (shortcutKey) {
|
|
1184
1184
|
const outputLines = record.output.split("\n");
|
|
1185
1185
|
const tailLines = outputLines.slice(-15).join("\n");
|
|
1186
|
-
|
|
1186
|
+
const ctx = {
|
|
1187
|
+
mode: record.mode,
|
|
1188
|
+
autoApprove: record.autoApprovePermissions,
|
|
1189
|
+
permissionBlocked: record.ptyPermissionBlocked || !!record.pendingEscalation,
|
|
1190
|
+
input,
|
|
1191
|
+
};
|
|
1192
|
+
this.logger.appendShortcutLog(id, shortcutKey, tailLines, ctx);
|
|
1187
1193
|
}
|
|
1188
1194
|
// Track user input via bridge for Chat mode
|
|
1189
1195
|
if (record.ptyBridge) {
|
package/dist/session-logger.d.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import type { ConversationTurn } from "./types.js";
|
|
1
|
+
import type { ConversationTurn, ExecutionMode } from "./types.js";
|
|
2
|
+
/** Context passed alongside a shortcut key interaction for richer logging */
|
|
3
|
+
export interface ShortcutLogContext {
|
|
4
|
+
/** Execution mode the session is running in (e.g. "managed", "full-access") */
|
|
5
|
+
mode: ExecutionMode;
|
|
6
|
+
/** Whether auto-approve is active for this session */
|
|
7
|
+
autoApprove: boolean;
|
|
8
|
+
/** Whether a permission prompt was blocking at the time of the keypress */
|
|
9
|
+
permissionBlocked: boolean;
|
|
10
|
+
/** The actual input string sent to PTY */
|
|
11
|
+
input: string;
|
|
12
|
+
}
|
|
2
13
|
/**
|
|
3
14
|
* SessionLogger saves raw session content to local files for debugging and analysis.
|
|
4
15
|
*
|
|
@@ -11,7 +22,8 @@ import type { ConversationTurn } from "./types.js";
|
|
|
11
22
|
export declare class SessionLogger {
|
|
12
23
|
private readonly baseDir;
|
|
13
24
|
private readonly dirs;
|
|
14
|
-
|
|
25
|
+
private readonly shortcutLogMaxBytes;
|
|
26
|
+
constructor(configDir: string, shortcutLogMaxBytes?: number);
|
|
15
27
|
private ensureDir;
|
|
16
28
|
/**
|
|
17
29
|
* Rotate PTY log files if the current one exceeds the size limit.
|
|
@@ -31,5 +43,7 @@ export declare class SessionLogger {
|
|
|
31
43
|
/** Delete all log files for a session */
|
|
32
44
|
deleteSession(sessionId: string): void;
|
|
33
45
|
/** Append a shortcut key interaction log entry (for analyzing auto-confirm gaps) */
|
|
34
|
-
appendShortcutLog(sessionId: string, shortcutKey: string, tailLines: string): void;
|
|
46
|
+
appendShortcutLog(sessionId: string, shortcutKey: string, tailLines: string, ctx?: ShortcutLogContext): void;
|
|
47
|
+
/** Truncate shortcut log by keeping only the most recent half of entries */
|
|
48
|
+
private truncateShortcutLog;
|
|
35
49
|
}
|
package/dist/session-logger.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, rmSync, appendFileSync, writeFileSync, existsSync, statSync, renameSync, unlinkSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, rmSync, appendFileSync, writeFileSync, readFileSync, existsSync, statSync, renameSync, unlinkSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
// ── Constants ──
|
|
@@ -6,6 +6,8 @@ import process from "node:process";
|
|
|
6
6
|
const PTY_LOG_MAX_SIZE = 50 * 1024 * 1024;
|
|
7
7
|
/** Maximum number of rotated log files to keep */
|
|
8
8
|
const PTY_LOG_MAX_ROTATIONS = 3;
|
|
9
|
+
/** Default max size for shortcut interaction logs per session (10 MB) */
|
|
10
|
+
const DEFAULT_SHORTCUT_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
9
11
|
/**
|
|
10
12
|
* SessionLogger saves raw session content to local files for debugging and analysis.
|
|
11
13
|
*
|
|
@@ -18,8 +20,10 @@ const PTY_LOG_MAX_ROTATIONS = 3;
|
|
|
18
20
|
export class SessionLogger {
|
|
19
21
|
baseDir;
|
|
20
22
|
dirs = new Map();
|
|
21
|
-
|
|
23
|
+
shortcutLogMaxBytes;
|
|
24
|
+
constructor(configDir, shortcutLogMaxBytes) {
|
|
22
25
|
this.baseDir = path.join(configDir, "sessions");
|
|
26
|
+
this.shortcutLogMaxBytes = shortcutLogMaxBytes ?? DEFAULT_SHORTCUT_LOG_MAX_BYTES;
|
|
23
27
|
try {
|
|
24
28
|
mkdirSync(this.baseDir, { recursive: true });
|
|
25
29
|
}
|
|
@@ -127,18 +131,50 @@ export class SessionLogger {
|
|
|
127
131
|
this.dirs.delete(sessionId);
|
|
128
132
|
}
|
|
129
133
|
/** Append a shortcut key interaction log entry (for analyzing auto-confirm gaps) */
|
|
130
|
-
appendShortcutLog(sessionId, shortcutKey, tailLines) {
|
|
134
|
+
appendShortcutLog(sessionId, shortcutKey, tailLines, ctx) {
|
|
135
|
+
if (this.shortcutLogMaxBytes <= 0)
|
|
136
|
+
return;
|
|
131
137
|
try {
|
|
132
138
|
const dir = this.ensureDir(sessionId);
|
|
139
|
+
const logPath = path.join(dir, "shortcut-interactions.jsonl");
|
|
133
140
|
const entry = JSON.stringify({
|
|
134
141
|
ts: new Date().toISOString(),
|
|
135
142
|
key: shortcutKey,
|
|
143
|
+
mode: ctx?.mode,
|
|
144
|
+
autoApprove: ctx?.autoApprove,
|
|
145
|
+
permissionBlocked: ctx?.permissionBlocked,
|
|
146
|
+
input: ctx?.input,
|
|
136
147
|
tail: tailLines,
|
|
137
148
|
}) + "\n";
|
|
138
|
-
|
|
149
|
+
// Check size and truncate if needed
|
|
150
|
+
if (existsSync(logPath)) {
|
|
151
|
+
const size = statSync(logPath).size;
|
|
152
|
+
if (size + entry.length > this.shortcutLogMaxBytes) {
|
|
153
|
+
this.truncateShortcutLog(logPath);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
appendFileSync(logPath, entry);
|
|
139
157
|
}
|
|
140
158
|
catch {
|
|
141
159
|
// Non-critical
|
|
142
160
|
}
|
|
143
161
|
}
|
|
162
|
+
/** Truncate shortcut log by keeping only the most recent half of entries */
|
|
163
|
+
truncateShortcutLog(logPath) {
|
|
164
|
+
try {
|
|
165
|
+
const content = readFileSync(logPath, "utf8");
|
|
166
|
+
const lines = content.split("\n").filter(Boolean);
|
|
167
|
+
// Keep the latter half
|
|
168
|
+
const keepFrom = Math.floor(lines.length / 2);
|
|
169
|
+
const trimmed = lines.slice(keepFrom).join("\n") + "\n";
|
|
170
|
+
writeFileSync(logPath, trimmed);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// If truncation fails, delete the file to prevent unbounded growth
|
|
174
|
+
try {
|
|
175
|
+
unlinkSync(logPath);
|
|
176
|
+
}
|
|
177
|
+
catch { /* ignore */ }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
144
180
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface WandConfig {
|
|
|
40
40
|
startupCommands: string[];
|
|
41
41
|
allowedCommandPrefixes: string[];
|
|
42
42
|
commandPresets: CommandPreset[];
|
|
43
|
+
/** Max total size (bytes) for shortcut interaction logs per session (default: 10 MB). Set 0 to disable logging. */
|
|
44
|
+
shortcutLogMaxBytes?: number;
|
|
43
45
|
}
|
|
44
46
|
export interface CommandRequest {
|
|
45
47
|
command: string;
|