@delt/claude-jev-advisor 0.2.0 → 0.4.0
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/README.md +53 -26
- package/dist/cli.js +313 -126
- package/dist/context-hook.js +30 -17
- package/dist/rm-hook.js +986 -110
- package/dist/statusline.js +28 -15
- package/mod/.claude-plugin/plugin.json +2 -2
- package/mod/hooks/register.js +138 -16
- package/package.json +4 -3
package/dist/statusline.js
CHANGED
|
@@ -18,6 +18,7 @@ var DEFAULT_CONFIG = {
|
|
|
18
18
|
lang: "ko",
|
|
19
19
|
keyFile: null,
|
|
20
20
|
display: "mod",
|
|
21
|
+
shortcut: null,
|
|
21
22
|
context: { enabled: true, minTokens: 25e4, compactMinTokens: 25e4, redRemainingPct: 20, unitDoneYes: 0.6, phaseDoneYes: 0.6 },
|
|
22
23
|
rm: { enabled: true, jev: true, throwawayYes: 0.8, maxDirFiles: 50 }
|
|
23
24
|
};
|
|
@@ -45,6 +46,7 @@ function normalizeConfig(raw) {
|
|
|
45
46
|
lang: typeof r.lang === "string" && LANGS.includes(r.lang) ? r.lang : DEFAULT_CONFIG.lang,
|
|
46
47
|
keyFile: typeof r.keyFile === "string" && r.keyFile !== "" ? r.keyFile : null,
|
|
47
48
|
display: typeof r.display === "string" && DISPLAYS.includes(r.display) ? r.display : DEFAULT_CONFIG.display,
|
|
49
|
+
shortcut: typeof r.shortcut === "string" && r.shortcut !== "" ? r.shortcut : null,
|
|
48
50
|
context: mergeSection(DEFAULT_CONFIG.context, r.version === CONFIG_VERSION ? r.context : withoutLegacyDefaults(r.context)),
|
|
49
51
|
rm: mergeSection(DEFAULT_CONFIG.rm, r.rm)
|
|
50
52
|
};
|
|
@@ -73,18 +75,20 @@ import path3 from "path";
|
|
|
73
75
|
|
|
74
76
|
// src/display/line.ts
|
|
75
77
|
var STALE_SIZE_RATIO = 0.7;
|
|
76
|
-
var
|
|
78
|
+
var QUESTIONS = {
|
|
77
79
|
ko: {
|
|
78
|
-
clear: "\uC0C8\uB86D\uAC8C \uC2DC\uC791\uD558\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?
|
|
79
|
-
compact: "\uC9C0\uAE08\uAE4C\uC9C0 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?
|
|
80
|
-
compactLater: "\uC791\uC5C5\uC774 \uB05D\uB098\uBA74 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?
|
|
80
|
+
clear: "\uC0C8\uB86D\uAC8C \uC2DC\uC791\uD558\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?",
|
|
81
|
+
compact: "\uC9C0\uAE08\uAE4C\uC9C0 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?",
|
|
82
|
+
compactLater: "\uC791\uC5C5\uC774 \uB05D\uB098\uBA74 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?"
|
|
81
83
|
},
|
|
82
84
|
en: {
|
|
83
|
-
clear: "Start fresh?
|
|
84
|
-
compact: "Wrap up what you have and continue?
|
|
85
|
-
compactLater: "When this work is done, wrap up and continue?
|
|
85
|
+
clear: "Start fresh?",
|
|
86
|
+
compact: "Wrap up what you have and continue?",
|
|
87
|
+
compactLater: "When this work is done, wrap up and continue?"
|
|
86
88
|
}
|
|
87
89
|
};
|
|
90
|
+
var COMMANDS = { clear: "/clear", compact: "/compact", compactLater: "/compact" };
|
|
91
|
+
var phrase = (lang, advice) => `${QUESTIONS[lang][advice]} ${COMMANDS[advice]}`;
|
|
88
92
|
function isRecord2(value) {
|
|
89
93
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
90
94
|
}
|
|
@@ -99,20 +103,29 @@ function adviceKind(size, judgment, config) {
|
|
|
99
103
|
if (judgment.clear) return "clear";
|
|
100
104
|
return size >= config.context.compactMinTokens ? "compact" : null;
|
|
101
105
|
}
|
|
102
|
-
function
|
|
106
|
+
function increaseSuffix(increase) {
|
|
107
|
+
if (increase === null || increase === void 0) return "";
|
|
108
|
+
const k = Math.round(increase / 1e3);
|
|
109
|
+
return k > 0 ? ` +${k}k` : "";
|
|
110
|
+
}
|
|
111
|
+
function redRemaining(size, threshold, config) {
|
|
112
|
+
if (threshold === null || threshold <= 0 || size < threshold * (1 - config.context.redRemainingPct / 100)) return null;
|
|
113
|
+
return remainingPct(size, threshold);
|
|
114
|
+
}
|
|
115
|
+
function adviceLine({ size, threshold, judgment, config, increase }) {
|
|
103
116
|
if (size === null) return "";
|
|
104
|
-
const k = formatSize(size)
|
|
105
|
-
const phrases = PHRASES[config.lang];
|
|
117
|
+
const k = `${formatSize(size)}${increaseSuffix(increase)}`;
|
|
106
118
|
const counted = size >= config.context.minTokens ? judgment : null;
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
const red = redRemaining(size, threshold, config);
|
|
120
|
+
if (red !== null) {
|
|
121
|
+
const head = `\u{1F534} ${k} ${red}%`;
|
|
109
122
|
if (!counted) return head;
|
|
110
|
-
if (counted.phase === "working") return `${head} \xB7 ${
|
|
111
|
-
return `${head} \xB7 ${counted.clear ?
|
|
123
|
+
if (counted.phase === "working") return `${head} \xB7 ${phrase(config.lang, "compactLater")}`;
|
|
124
|
+
return `${head} \xB7 ${phrase(config.lang, counted.clear ? "clear" : "compact")}`;
|
|
112
125
|
}
|
|
113
126
|
if (!counted) return k;
|
|
114
127
|
const kind = adviceKind(size, counted, config);
|
|
115
|
-
return kind ? `\u{1F7E1} ${k} ${
|
|
128
|
+
return kind ? `\u{1F7E1} ${k} ${phrase(config.lang, kind)}` : `\u{1F7E2} ${k}`;
|
|
116
129
|
}
|
|
117
130
|
function usableJudgment(state, liveSize, turnStartedAt) {
|
|
118
131
|
if (!state || !state.judgment || state.at < turnStartedAt) return null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jev-advisor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Bottom-row compact/clear advice from @delt/claude-jev-advisor (unofficial)",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Bottom-row compact/clear advice and an advice button from @delt/claude-jev-advisor (unofficial)",
|
|
5
5
|
"author": { "name": "delt96" },
|
|
6
6
|
"userConfig": {
|
|
7
7
|
"dataDir": {
|
package/mod/hooks/register.js
CHANGED
|
@@ -4,6 +4,7 @@ var DEFAULT_CONFIG = {
|
|
|
4
4
|
lang: "ko",
|
|
5
5
|
keyFile: null,
|
|
6
6
|
display: "mod",
|
|
7
|
+
shortcut: null,
|
|
7
8
|
context: { enabled: true, minTokens: 25e4, compactMinTokens: 25e4, redRemainingPct: 20, unitDoneYes: 0.6, phaseDoneYes: 0.6 },
|
|
8
9
|
rm: { enabled: true, jev: true, throwawayYes: 0.8, maxDirFiles: 50 }
|
|
9
10
|
};
|
|
@@ -31,6 +32,7 @@ function normalizeConfig(raw) {
|
|
|
31
32
|
lang: typeof r.lang === "string" && LANGS.includes(r.lang) ? r.lang : DEFAULT_CONFIG.lang,
|
|
32
33
|
keyFile: typeof r.keyFile === "string" && r.keyFile !== "" ? r.keyFile : null,
|
|
33
34
|
display: typeof r.display === "string" && DISPLAYS.includes(r.display) ? r.display : DEFAULT_CONFIG.display,
|
|
35
|
+
shortcut: typeof r.shortcut === "string" && r.shortcut !== "" ? r.shortcut : null,
|
|
34
36
|
context: mergeSection(DEFAULT_CONFIG.context, r.version === CONFIG_VERSION ? r.context : withoutLegacyDefaults(r.context)),
|
|
35
37
|
rm: mergeSection(DEFAULT_CONFIG.rm, r.rm)
|
|
36
38
|
};
|
|
@@ -38,21 +40,26 @@ function normalizeConfig(raw) {
|
|
|
38
40
|
|
|
39
41
|
// src/display/line.ts
|
|
40
42
|
var STALE_SIZE_RATIO = 0.7;
|
|
41
|
-
var
|
|
43
|
+
var QUESTIONS = {
|
|
42
44
|
ko: {
|
|
43
|
-
clear: "\uC0C8\uB86D\uAC8C \uC2DC\uC791\uD558\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?
|
|
44
|
-
compact: "\uC9C0\uAE08\uAE4C\uC9C0 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?
|
|
45
|
-
compactLater: "\uC791\uC5C5\uC774 \uB05D\uB098\uBA74 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?
|
|
45
|
+
clear: "\uC0C8\uB86D\uAC8C \uC2DC\uC791\uD558\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?",
|
|
46
|
+
compact: "\uC9C0\uAE08\uAE4C\uC9C0 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?",
|
|
47
|
+
compactLater: "\uC791\uC5C5\uC774 \uB05D\uB098\uBA74 \uC815\uB9AC\uD558\uACE0 \uC774\uC5B4\uAC00\uB294 \uAC74 \uC5B4\uB5A0\uC138\uC694?"
|
|
46
48
|
},
|
|
47
49
|
en: {
|
|
48
|
-
clear: "Start fresh?
|
|
49
|
-
compact: "Wrap up what you have and continue?
|
|
50
|
-
compactLater: "When this work is done, wrap up and continue?
|
|
50
|
+
clear: "Start fresh?",
|
|
51
|
+
compact: "Wrap up what you have and continue?",
|
|
52
|
+
compactLater: "When this work is done, wrap up and continue?"
|
|
51
53
|
}
|
|
52
54
|
};
|
|
55
|
+
var COMMANDS = { clear: "/clear", compact: "/compact", compactLater: "/compact" };
|
|
56
|
+
var phrase = (lang, advice) => `${QUESTIONS[lang][advice]} ${COMMANDS[advice]}`;
|
|
53
57
|
function isRecord2(value) {
|
|
54
58
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
55
59
|
}
|
|
60
|
+
function adviceQuestion(kind, lang) {
|
|
61
|
+
return QUESTIONS[lang][kind];
|
|
62
|
+
}
|
|
56
63
|
function formatSize(tokens) {
|
|
57
64
|
return `${Math.round(tokens / 1e3)}k`;
|
|
58
65
|
}
|
|
@@ -64,20 +71,42 @@ function adviceKind(size, judgment, config) {
|
|
|
64
71
|
if (judgment.clear) return "clear";
|
|
65
72
|
return size >= config.context.compactMinTokens ? "compact" : null;
|
|
66
73
|
}
|
|
67
|
-
function
|
|
74
|
+
function increaseSuffix(increase) {
|
|
75
|
+
if (increase === null || increase === void 0) return "";
|
|
76
|
+
const k = Math.round(increase / 1e3);
|
|
77
|
+
return k > 0 ? ` +${k}k` : "";
|
|
78
|
+
}
|
|
79
|
+
function redRemaining(size, threshold, config) {
|
|
80
|
+
if (threshold === null || threshold <= 0 || size < threshold * (1 - config.context.redRemainingPct / 100)) return null;
|
|
81
|
+
return remainingPct(size, threshold);
|
|
82
|
+
}
|
|
83
|
+
function adviceLine({ size, threshold, judgment, config, increase }) {
|
|
68
84
|
if (size === null) return "";
|
|
69
|
-
const k = formatSize(size)
|
|
70
|
-
const phrases = PHRASES[config.lang];
|
|
85
|
+
const k = `${formatSize(size)}${increaseSuffix(increase)}`;
|
|
71
86
|
const counted = size >= config.context.minTokens ? judgment : null;
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
const red = redRemaining(size, threshold, config);
|
|
88
|
+
if (red !== null) {
|
|
89
|
+
const head = `\u{1F534} ${k} ${red}%`;
|
|
74
90
|
if (!counted) return head;
|
|
75
|
-
if (counted.phase === "working") return `${head} \xB7 ${
|
|
76
|
-
return `${head} \xB7 ${counted.clear ?
|
|
91
|
+
if (counted.phase === "working") return `${head} \xB7 ${phrase(config.lang, "compactLater")}`;
|
|
92
|
+
return `${head} \xB7 ${phrase(config.lang, counted.clear ? "clear" : "compact")}`;
|
|
77
93
|
}
|
|
78
94
|
if (!counted) return k;
|
|
79
95
|
const kind = adviceKind(size, counted, config);
|
|
80
|
-
return kind ? `\u{1F7E1} ${k} ${
|
|
96
|
+
return kind ? `\u{1F7E1} ${k} ${phrase(config.lang, kind)}` : `\u{1F7E2} ${k}`;
|
|
97
|
+
}
|
|
98
|
+
function bandAdvice({ size, threshold, judgment, config }) {
|
|
99
|
+
if (size === null) return null;
|
|
100
|
+
const counted = size >= config.context.minTokens ? judgment : null;
|
|
101
|
+
if (!counted || counted.phase === "working") return null;
|
|
102
|
+
const red = redRemaining(size, threshold, config);
|
|
103
|
+
if (red !== null) return { kind: counted.clear ? "clear" : "compact", remainingPct: red };
|
|
104
|
+
const kind = adviceKind(size, counted, config);
|
|
105
|
+
return kind ? { kind, remainingPct: null } : null;
|
|
106
|
+
}
|
|
107
|
+
function modTail(input) {
|
|
108
|
+
if (input.size === null) return "";
|
|
109
|
+
return bandAdvice(input) ? `${formatSize(input.size)}${increaseSuffix(input.increase)}` : adviceLine(input);
|
|
81
110
|
}
|
|
82
111
|
function usableJudgment(state, liveSize2, turnStartedAt) {
|
|
83
112
|
if (!state || !state.judgment || state.at < turnStartedAt) return null;
|
|
@@ -91,6 +120,43 @@ function parseState(raw) {
|
|
|
91
120
|
return { sessionId: raw.sessionId, at: raw.at, size: typeof raw.size === "number" ? raw.size : null, judgment };
|
|
92
121
|
}
|
|
93
122
|
|
|
123
|
+
// src/display/shortcut.ts
|
|
124
|
+
var SHORTCUT_ACTION = "diff:back";
|
|
125
|
+
|
|
126
|
+
// src/mod/band.ts
|
|
127
|
+
var ICONS = { compact: "\u{1F4E6}", clear: "\u{1F9F9}" };
|
|
128
|
+
function drawBand(ui, { advice, config, onPress }) {
|
|
129
|
+
const { Box, Text, Button } = ui;
|
|
130
|
+
const head = advice.remainingPct === null ? "\u{1F7E1}" : `\u{1F534} ${advice.remainingPct}%`;
|
|
131
|
+
const controls = [
|
|
132
|
+
h(Button, {
|
|
133
|
+
key: `jev-${advice.kind}`,
|
|
134
|
+
label: `${ICONS[advice.kind]} /${advice.kind}`,
|
|
135
|
+
variant: "primary",
|
|
136
|
+
autoFocus: true,
|
|
137
|
+
hover: { bold: true },
|
|
138
|
+
onPress,
|
|
139
|
+
...config.shortcut ? { action: SHORTCUT_ACTION } : {}
|
|
140
|
+
})
|
|
141
|
+
];
|
|
142
|
+
if (config.shortcut) controls.push(h(Text, { dimColor: true }, config.shortcut));
|
|
143
|
+
return h(
|
|
144
|
+
Box,
|
|
145
|
+
{ flexDirection: "row", flexWrap: "wrap", columnGap: 2, paddingTop: 1 },
|
|
146
|
+
h(
|
|
147
|
+
Box,
|
|
148
|
+
{ flexDirection: "row", gap: 1, minWidth: 0, flexShrink: 1 },
|
|
149
|
+
h(Box, { flexShrink: 0 }, h(Text, { bold: advice.remainingPct !== null }, head)),
|
|
150
|
+
h(
|
|
151
|
+
Box,
|
|
152
|
+
{ minWidth: 0, flexShrink: 1 },
|
|
153
|
+
h(Text, { wrap: "truncate-end" }, adviceQuestion(advice.kind, config.lang))
|
|
154
|
+
)
|
|
155
|
+
),
|
|
156
|
+
h(Box, { key: `jev-${advice.kind}-control`, flexDirection: "row", gap: 1, flexShrink: 0 }, ...controls)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
94
160
|
// src/mod/register.ts
|
|
95
161
|
var REFRESH_MS = 2e3;
|
|
96
162
|
async function readJson($, file) {
|
|
@@ -130,13 +196,36 @@ async function liveSize($) {
|
|
|
130
196
|
return null;
|
|
131
197
|
}
|
|
132
198
|
}
|
|
199
|
+
function reason(err) {
|
|
200
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
201
|
+
return message.replace(/^[^:]+: \$\.[\w]+(?:\.[\w]+)*: /, "");
|
|
202
|
+
}
|
|
203
|
+
async function press($, kind) {
|
|
204
|
+
try {
|
|
205
|
+
$.ui.invalidate("ui.render");
|
|
206
|
+
if (kind === "compact") {
|
|
207
|
+
const result = await $.session.compact();
|
|
208
|
+
if (result?.skip) $.ui.toast("/compact: skipped by a hook");
|
|
209
|
+
} else {
|
|
210
|
+
await $.command.run({ command: "clear" });
|
|
211
|
+
}
|
|
212
|
+
} catch (err) {
|
|
213
|
+
try {
|
|
214
|
+
$.ui.toast(`/${kind}: ${reason(err)}`);
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
133
219
|
function register(on, options) {
|
|
134
220
|
const dataDir = typeof options.dataDir === "string" ? options.dataDir.replace(/[\\/]+$/, "") : "";
|
|
135
221
|
let config = null;
|
|
136
222
|
let state = null;
|
|
137
223
|
let threshold = null;
|
|
138
224
|
let turnStartedAt = 0;
|
|
225
|
+
let baseline = null;
|
|
139
226
|
let seen = "";
|
|
227
|
+
let handledAt = -Infinity;
|
|
228
|
+
const judgmentFor = (size) => state && state.at <= handledAt ? null : usableJudgment(state, size, turnStartedAt);
|
|
140
229
|
on("session.start", async ($, e, next) => {
|
|
141
230
|
const result = await next(e);
|
|
142
231
|
if (!dataDir || e.isInteractive === false) return result;
|
|
@@ -159,8 +248,10 @@ function register(on, options) {
|
|
|
159
248
|
return result;
|
|
160
249
|
});
|
|
161
250
|
on("turn.start", async ($, e, next) => {
|
|
251
|
+
baseline = null;
|
|
162
252
|
try {
|
|
163
253
|
turnStartedAt = await $.clock.now();
|
|
254
|
+
baseline = await liveSize($);
|
|
164
255
|
$.ui.invalidate("ui.render");
|
|
165
256
|
} catch {
|
|
166
257
|
}
|
|
@@ -171,19 +262,50 @@ function register(on, options) {
|
|
|
171
262
|
threshold = await autoCompactThreshold($);
|
|
172
263
|
return result;
|
|
173
264
|
});
|
|
265
|
+
on("session.end", async ($, e, next) => {
|
|
266
|
+
baseline = null;
|
|
267
|
+
state = null;
|
|
268
|
+
seen = "";
|
|
269
|
+
try {
|
|
270
|
+
$.ui.invalidate("ui.render");
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
return next(e);
|
|
274
|
+
});
|
|
174
275
|
on("ui.render", { component: "PromptHint" }, async ($, e, next) => {
|
|
175
276
|
let tail = "";
|
|
176
277
|
try {
|
|
177
278
|
const current = config;
|
|
178
279
|
if (current && current.context.enabled && current.display === "mod") {
|
|
179
280
|
const size = await liveSize($);
|
|
180
|
-
|
|
281
|
+
const increase = baseline !== null && size !== null ? size - baseline : null;
|
|
282
|
+
tail = modTail({ size, threshold, judgment: judgmentFor(size), config: current, increase });
|
|
181
283
|
}
|
|
182
284
|
} catch {
|
|
183
285
|
tail = "";
|
|
184
286
|
}
|
|
185
287
|
return tail ? next({ ...e, props: { ...e.props, tail } }) : next(e);
|
|
186
288
|
});
|
|
289
|
+
on("ui.render", { component: "AbovePrompt" }, async ($, e, next) => {
|
|
290
|
+
let band = null;
|
|
291
|
+
try {
|
|
292
|
+
const current = config;
|
|
293
|
+
const props = e.props ?? {};
|
|
294
|
+
if (current && current.context.enabled && current.display === "mod" && props.isWorking !== true && props.hasSurvey !== true) {
|
|
295
|
+
const size = await liveSize($);
|
|
296
|
+
const advice = bandAdvice({ size, threshold, judgment: judgmentFor(size), config: current });
|
|
297
|
+
const at = state?.at;
|
|
298
|
+
if (advice && at !== void 0) band = drawBand($.ui.resolve(e), { advice, config: current, onPress: () => {
|
|
299
|
+
if (at <= handledAt) return;
|
|
300
|
+
handledAt = at;
|
|
301
|
+
void press($, advice.kind);
|
|
302
|
+
} });
|
|
303
|
+
}
|
|
304
|
+
} catch {
|
|
305
|
+
band = null;
|
|
306
|
+
}
|
|
307
|
+
return band ?? next(e);
|
|
308
|
+
});
|
|
187
309
|
}
|
|
188
310
|
export {
|
|
189
311
|
register
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delt/claude-jev-advisor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Unofficial Claude Code helpers using TypeSafe Jev: compact/clear advice and an rm guard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
-
"mod",
|
|
11
|
+
"mod/.claude-plugin/plugin.json",
|
|
12
|
+
"mod/hooks",
|
|
12
13
|
"README.md"
|
|
13
14
|
],
|
|
14
15
|
"engines": {
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
"scripts": {
|
|
18
19
|
"build": "tsup",
|
|
19
20
|
"typecheck": "tsc --noEmit",
|
|
20
|
-
"test": "node --import tsx --import ./test/isolate-home.ts --test --test-timeout=
|
|
21
|
+
"test": "node --import tsx --import ./test/isolate-home.ts --test --test-timeout=120000 \"test/**/*.test.ts\"",
|
|
21
22
|
"prepack": "npm run build"
|
|
22
23
|
},
|
|
23
24
|
"keywords": [
|