@dungle-scrubs/tallow 0.8.28 → 0.9.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/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +2 -9
- package/dist/install.js.map +1 -1
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +20 -9
- package/dist/interactive-mode-patch.js.map +1 -1
- package/extensions/_icons/__tests__/icons.test.ts +0 -1
- package/extensions/_icons/index.ts +0 -2
- package/extensions/context-fork/__tests__/context-fork.test.ts +9 -0
- package/extensions/health/index.ts +1 -1
- package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +42 -0
- package/extensions/render-stabilizer/extension.json +5 -0
- package/extensions/render-stabilizer/index.ts +66 -0
- package/extensions/subagent-tool/__tests__/auto-cheap-model.test.ts +66 -6
- package/extensions/subagent-tool/__tests__/model-router-explicit-resolution.test.ts +79 -5
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +47 -0
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js +139 -5
- package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/src/tui.ts +142 -5
- package/package.json +1 -1
- package/schemas/settings.schema.json +0 -5
- package/extensions/plan-mode-tool/__tests__/e2e.mjs +0 -350
- package/extensions/plan-mode-tool/__tests__/index.test.ts +0 -213
- package/extensions/plan-mode-tool/__tests__/utils.test.ts +0 -381
- package/extensions/plan-mode-tool/extension.json +0 -22
- package/extensions/plan-mode-tool/index.ts +0 -583
- package/extensions/plan-mode-tool/utils.ts +0 -257
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure utility functions for plan mode.
|
|
3
|
-
* Extracted for testability — no extension API dependencies.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ── Natural language plan intent detection ──────────────────────────────
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Curated patterns that unambiguously express "enter planning mode".
|
|
10
|
-
* Each pattern uses word boundaries to avoid matching plan-as-noun usage
|
|
11
|
-
* (e.g. "make a plan for X") or questions about plan mode.
|
|
12
|
-
*/
|
|
13
|
-
export const PLAN_INTENT_PATTERNS: readonly RegExp[] = [
|
|
14
|
-
// Composite patterns first — avoids partial stripping of overlapping phrases
|
|
15
|
-
/\bthis\s+is\s+plan(ning)?(\s+only)?\b/i,
|
|
16
|
-
/\bplan[\s-]only\b/i,
|
|
17
|
-
/\bjust\s+plan\b/i,
|
|
18
|
-
/\bonly\s+plan\b/i,
|
|
19
|
-
/\bplan\s+mode\b(?!\s*(\?|do|work|mean))/i,
|
|
20
|
-
/\bplanning\s+mode\b(?!\s*(\?|do|work|mean))/i,
|
|
21
|
-
/\bdon['\u2019]?t\s+(implement|code|execute|make\s+changes)\b/i,
|
|
22
|
-
/\bdo\s+not\s+(implement|code|execute|make\s+changes)\b/i,
|
|
23
|
-
/\bno\s+(implementation|changes|coding)\s+(yet|first|for\s+now)\b/i,
|
|
24
|
-
/\bread[\s-]only\s+mode\b/i,
|
|
25
|
-
/\bplan\s+(first|before)\b/i,
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Detects whether user input contains a strong planning-intent directive.
|
|
30
|
-
*
|
|
31
|
-
* Only matches unambiguous directives like "plan only" or "don't implement".
|
|
32
|
-
* Does NOT match noun usage ("the plan is…") or questions ("what does plan mode do?").
|
|
33
|
-
*
|
|
34
|
-
* @param text - Raw user input
|
|
35
|
-
* @returns true when any plan-intent pattern matches
|
|
36
|
-
*/
|
|
37
|
-
export function detectPlanIntent(text: string): boolean {
|
|
38
|
-
return PLAN_INTENT_PATTERNS.some((pattern) => pattern.test(text));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Strips plan-intent phrases from user input, preserving the actual request.
|
|
43
|
-
*
|
|
44
|
-
* If stripping leaves an empty string (the entire message was just "plan only"),
|
|
45
|
-
* returns the original text so the model has something to work with.
|
|
46
|
-
*
|
|
47
|
-
* @param text - Raw user input
|
|
48
|
-
* @returns Cleaned text with plan-intent phrases removed, or original if nothing remains
|
|
49
|
-
*/
|
|
50
|
-
export function stripPlanIntent(text: string): string {
|
|
51
|
-
let stripped = text;
|
|
52
|
-
for (const pattern of PLAN_INTENT_PATTERNS) {
|
|
53
|
-
stripped = stripped.replace(pattern, "");
|
|
54
|
-
}
|
|
55
|
-
// Clean up artifacts: leading/trailing punctuation, double spaces, dangling commas
|
|
56
|
-
stripped = stripped
|
|
57
|
-
.replace(/^[\s,.\-—;:]+/, "")
|
|
58
|
-
.replace(/[\s,.\-—;:]+$/, "")
|
|
59
|
-
.replace(/\s{2,}/g, " ")
|
|
60
|
-
.trim();
|
|
61
|
-
return stripped || text;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ── Bash safety ─────────────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
/** Patterns for destructive commands that are blocked in plan mode */
|
|
67
|
-
const DESTRUCTIVE_PATTERNS = [
|
|
68
|
-
/\brm\b/i,
|
|
69
|
-
/\brmdir\b/i,
|
|
70
|
-
/\bmv\b/i,
|
|
71
|
-
/\bcp\b/i,
|
|
72
|
-
/\bmkdir\b/i,
|
|
73
|
-
/\btouch\b/i,
|
|
74
|
-
/\bchmod\b/i,
|
|
75
|
-
/\bchown\b/i,
|
|
76
|
-
/\bchgrp\b/i,
|
|
77
|
-
/\bln\b/i,
|
|
78
|
-
/\btee\b/i,
|
|
79
|
-
/\btruncate\b/i,
|
|
80
|
-
/\bdd\b/i,
|
|
81
|
-
/\bshred\b/i,
|
|
82
|
-
/(^|[^<])>(?!>)/,
|
|
83
|
-
/>>/,
|
|
84
|
-
/\bnpm\s+(install|uninstall|update|ci|link|publish)/i,
|
|
85
|
-
/\byarn\s+(add|remove|install|publish)/i,
|
|
86
|
-
/\bpnpm\s+(add|remove|install|publish)/i,
|
|
87
|
-
/\bpip\s+(install|uninstall)/i,
|
|
88
|
-
/\bapt(-get)?\s+(install|remove|purge|update|upgrade)/i,
|
|
89
|
-
/\bbrew\s+(install|uninstall|upgrade)/i,
|
|
90
|
-
/\bgit\s+(add|commit|push|pull|merge|rebase|reset|checkout|branch\s+-[dD]|stash|cherry-pick|revert|tag|init|clone)/i,
|
|
91
|
-
/\bsudo\b/i,
|
|
92
|
-
/\bsu\b/i,
|
|
93
|
-
/\bkill\b/i,
|
|
94
|
-
/\bpkill\b/i,
|
|
95
|
-
/\bkillall\b/i,
|
|
96
|
-
/\breboot\b/i,
|
|
97
|
-
/\bshutdown\b/i,
|
|
98
|
-
/\bsystemctl\s+(start|stop|restart|enable|disable)/i,
|
|
99
|
-
/\bservice\s+\S+\s+(start|stop|restart)/i,
|
|
100
|
-
/\b(vim?|nano|emacs|code|subl)\b/i,
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
/** Patterns for safe read-only commands allowed in plan mode */
|
|
104
|
-
const SAFE_PATTERNS = [
|
|
105
|
-
/^\s*cat\b/,
|
|
106
|
-
/^\s*head\b/,
|
|
107
|
-
/^\s*tail\b/,
|
|
108
|
-
/^\s*less\b/,
|
|
109
|
-
/^\s*more\b/,
|
|
110
|
-
/^\s*grep\b/,
|
|
111
|
-
/^\s*find\b/,
|
|
112
|
-
/^\s*ls\b/,
|
|
113
|
-
/^\s*pwd\b/,
|
|
114
|
-
/^\s*echo\b/,
|
|
115
|
-
/^\s*printf\b/,
|
|
116
|
-
/^\s*wc\b/,
|
|
117
|
-
/^\s*sort\b/,
|
|
118
|
-
/^\s*uniq\b/,
|
|
119
|
-
/^\s*diff\b/,
|
|
120
|
-
/^\s*file\b/,
|
|
121
|
-
/^\s*stat\b/,
|
|
122
|
-
/^\s*du\b/,
|
|
123
|
-
/^\s*df\b/,
|
|
124
|
-
/^\s*tree\b/,
|
|
125
|
-
/^\s*which\b/,
|
|
126
|
-
/^\s*whereis\b/,
|
|
127
|
-
/^\s*type\b/,
|
|
128
|
-
/^\s*env\b/,
|
|
129
|
-
/^\s*printenv\b/,
|
|
130
|
-
/^\s*uname\b/,
|
|
131
|
-
/^\s*whoami\b/,
|
|
132
|
-
/^\s*id\b/,
|
|
133
|
-
/^\s*date\b/,
|
|
134
|
-
/^\s*cal\b/,
|
|
135
|
-
/^\s*uptime\b/,
|
|
136
|
-
/^\s*ps\b/,
|
|
137
|
-
/^\s*top\b/,
|
|
138
|
-
/^\s*htop\b/,
|
|
139
|
-
/^\s*free\b/,
|
|
140
|
-
/^\s*git\s+(status|log|diff|show|branch|remote|config\s+--get)/i,
|
|
141
|
-
/^\s*git\s+ls-/i,
|
|
142
|
-
/^\s*npm\s+(list|ls|view|info|search|outdated|audit)/i,
|
|
143
|
-
/^\s*yarn\s+(list|info|why|audit)/i,
|
|
144
|
-
/^\s*node\s+--version/i,
|
|
145
|
-
/^\s*python\s+--version/i,
|
|
146
|
-
/^\s*curl\s/i,
|
|
147
|
-
/^\s*wget\s+-O\s*-/i,
|
|
148
|
-
/^\s*jq\b/,
|
|
149
|
-
/^\s*sed\s+-n/i,
|
|
150
|
-
/^\s*awk\b/,
|
|
151
|
-
/^\s*rg\b/,
|
|
152
|
-
/^\s*fd\b/,
|
|
153
|
-
/^\s*bat\b/,
|
|
154
|
-
/^\s*exa\b/,
|
|
155
|
-
];
|
|
156
|
-
|
|
157
|
-
/** Strict allowlist of tool names permitted while plan mode is enabled. */
|
|
158
|
-
export const PLAN_MODE_ALLOWED_TOOLS = [
|
|
159
|
-
"bash",
|
|
160
|
-
"find",
|
|
161
|
-
"grep",
|
|
162
|
-
"ls",
|
|
163
|
-
"plan_mode",
|
|
164
|
-
"questionnaire",
|
|
165
|
-
"read",
|
|
166
|
-
] as const;
|
|
167
|
-
|
|
168
|
-
/** Lookup set for plan-mode allowlisted tools. */
|
|
169
|
-
const PLAN_MODE_ALLOWED_TOOL_SET = new Set<string>(PLAN_MODE_ALLOWED_TOOLS);
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Checks whether a tool is allowlisted for plan mode.
|
|
173
|
-
*
|
|
174
|
-
* Plan mode is fail-closed: unknown tools are blocked by default.
|
|
175
|
-
*
|
|
176
|
-
* @param toolName - Tool name to evaluate
|
|
177
|
-
* @returns True when the tool is explicitly allowlisted
|
|
178
|
-
*/
|
|
179
|
-
export function isPlanModeToolAllowed(toolName: string): boolean {
|
|
180
|
-
return PLAN_MODE_ALLOWED_TOOL_SET.has(toolName);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Checks if a bash command is safe to run in plan mode.
|
|
185
|
-
* @param command - The bash command to check
|
|
186
|
-
* @returns true if the command is safe (read-only), false otherwise
|
|
187
|
-
*/
|
|
188
|
-
export function isSafeCommand(command: string): boolean {
|
|
189
|
-
const isDestructive = DESTRUCTIVE_PATTERNS.some((p) => p.test(command));
|
|
190
|
-
const isSafe = SAFE_PATTERNS.some((p) => p.test(command));
|
|
191
|
-
return !isDestructive && isSafe;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** Represents a single todo item in a plan */
|
|
195
|
-
export interface TodoItem {
|
|
196
|
-
step: number;
|
|
197
|
-
text: string;
|
|
198
|
-
completed: boolean;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Cleans up step text for display by removing markdown and truncating.
|
|
203
|
-
* @param text - The raw step text from the plan
|
|
204
|
-
* @returns Cleaned and truncated text suitable for display
|
|
205
|
-
*/
|
|
206
|
-
export function cleanStepText(text: string): string {
|
|
207
|
-
let cleaned = text
|
|
208
|
-
.replace(/\*{1,2}([^*]+)\*{1,2}/g, "$1")
|
|
209
|
-
.replace(/`([^`]+)`/g, "$1")
|
|
210
|
-
.replace(
|
|
211
|
-
/^(Use|Run|Execute|Create|Write|Read|Check|Verify|Update|Modify|Add|Remove|Delete|Install)\s+(the\s+)?/i,
|
|
212
|
-
""
|
|
213
|
-
)
|
|
214
|
-
.replace(/\s+/g, " ")
|
|
215
|
-
.trim();
|
|
216
|
-
|
|
217
|
-
if (cleaned.length > 0) {
|
|
218
|
-
cleaned = cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
|
|
219
|
-
}
|
|
220
|
-
if (cleaned.length > 50) {
|
|
221
|
-
cleaned = `${cleaned.slice(0, 47)}...`;
|
|
222
|
-
}
|
|
223
|
-
return cleaned;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Extracts numbered todo items from a plan section in a message.
|
|
228
|
-
* @param message - The message text to parse
|
|
229
|
-
* @returns Array of extracted todo items
|
|
230
|
-
*/
|
|
231
|
-
export function extractTodoItems(message: string): TodoItem[] {
|
|
232
|
-
const items: TodoItem[] = [];
|
|
233
|
-
const headerMatch = message.match(/\*{0,2}Plan:\*{0,2}\s*\n/i);
|
|
234
|
-
if (!headerMatch) return items;
|
|
235
|
-
|
|
236
|
-
const planSection = message.slice(message.indexOf(headerMatch[0]) + headerMatch[0].length);
|
|
237
|
-
const numberedPattern = /^\s*(\d+)[.)]\s+\*{0,2}([^*\n]+)/gm;
|
|
238
|
-
|
|
239
|
-
for (const match of planSection.matchAll(numberedPattern)) {
|
|
240
|
-
const text = match[2]
|
|
241
|
-
.trim()
|
|
242
|
-
.replace(/\*{1,2}$/, "")
|
|
243
|
-
.trim();
|
|
244
|
-
if (
|
|
245
|
-
text.length > 5 &&
|
|
246
|
-
!text.startsWith("`") &&
|
|
247
|
-
!text.startsWith("/") &&
|
|
248
|
-
!text.startsWith("-")
|
|
249
|
-
) {
|
|
250
|
-
const cleaned = cleanStepText(text);
|
|
251
|
-
if (cleaned.length > 3) {
|
|
252
|
-
items.push({ step: items.length + 1, text: cleaned, completed: false });
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return items;
|
|
257
|
-
}
|