pi-repoprompt-cli 0.1.1 → 0.2.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/extensions/repoprompt-cli.ts +326 -27
- package/package.json +3 -2
|
@@ -4,6 +4,179 @@ import { Text } from "@mariozechner/pi-tui";
|
|
|
4
4
|
import { Type } from "@sinclair/typebox";
|
|
5
5
|
import * as Diff from "diff";
|
|
6
6
|
|
|
7
|
+
let parseBash: ((input: string) => any) | null = null;
|
|
8
|
+
let justBashLoadPromise: Promise<void> | null = null;
|
|
9
|
+
let justBashLoadDone = false;
|
|
10
|
+
|
|
11
|
+
async function ensureJustBashLoaded(): Promise<void> {
|
|
12
|
+
if (justBashLoadDone) return;
|
|
13
|
+
|
|
14
|
+
if (!justBashLoadPromise) {
|
|
15
|
+
justBashLoadPromise = import("just-bash")
|
|
16
|
+
.then((mod: any) => {
|
|
17
|
+
parseBash = typeof mod?.parse === "function" ? mod.parse : null;
|
|
18
|
+
})
|
|
19
|
+
.catch(() => {
|
|
20
|
+
parseBash = null;
|
|
21
|
+
})
|
|
22
|
+
.finally(() => {
|
|
23
|
+
justBashLoadDone = true;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await justBashLoadPromise;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let warnedAstUnavailable = false;
|
|
31
|
+
function maybeWarnAstUnavailable(ctx: any): void {
|
|
32
|
+
if (warnedAstUnavailable) return;
|
|
33
|
+
if (parseBash) return;
|
|
34
|
+
if (!ctx?.hasUI) return;
|
|
35
|
+
|
|
36
|
+
warnedAstUnavailable = true;
|
|
37
|
+
ctx.ui.notify(
|
|
38
|
+
"repoprompt-cli: just-bash >= 2 is not available; falling back to best-effort command parsing",
|
|
39
|
+
"warning",
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type BashInvocation = {
|
|
44
|
+
statementIndex: number;
|
|
45
|
+
pipelineIndex: number;
|
|
46
|
+
pipelineLength: number;
|
|
47
|
+
commandNameRaw: string;
|
|
48
|
+
commandName: string;
|
|
49
|
+
args: string[];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function commandBaseName(value: string): string {
|
|
53
|
+
const normalized = value.replace(/\\+/g, "/");
|
|
54
|
+
const idx = normalized.lastIndexOf("/");
|
|
55
|
+
const base = idx >= 0 ? normalized.slice(idx + 1) : normalized;
|
|
56
|
+
return base.toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function partToText(part: any): string {
|
|
60
|
+
if (!part || typeof part !== "object") return "";
|
|
61
|
+
|
|
62
|
+
switch (part.type) {
|
|
63
|
+
case "Literal":
|
|
64
|
+
case "SingleQuoted":
|
|
65
|
+
case "Escaped":
|
|
66
|
+
return typeof part.value === "string" ? part.value : "";
|
|
67
|
+
case "DoubleQuoted":
|
|
68
|
+
return Array.isArray(part.parts) ? part.parts.map(partToText).join("") : "";
|
|
69
|
+
case "Glob":
|
|
70
|
+
return typeof part.pattern === "string" ? part.pattern : "";
|
|
71
|
+
case "TildeExpansion":
|
|
72
|
+
return typeof part.user === "string" && part.user.length > 0 ? `~${part.user}` : "~";
|
|
73
|
+
case "ParameterExpansion":
|
|
74
|
+
return typeof part.parameter === "string" && part.parameter.length > 0
|
|
75
|
+
? "${" + part.parameter + "}"
|
|
76
|
+
: "${}";
|
|
77
|
+
case "CommandSubstitution":
|
|
78
|
+
return "$(...)";
|
|
79
|
+
case "ProcessSubstitution":
|
|
80
|
+
return part.direction === "output" ? ">(...)" : "<(...)";
|
|
81
|
+
case "ArithmeticExpansion":
|
|
82
|
+
return "$((...))";
|
|
83
|
+
default:
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function wordToText(word: any): string {
|
|
89
|
+
if (!word || typeof word !== "object" || !Array.isArray(word.parts)) return "";
|
|
90
|
+
return word.parts.map(partToText).join("");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function analyzeTopLevelBashScript(command: string): { parseError?: string; topLevelInvocations: BashInvocation[] } {
|
|
94
|
+
try {
|
|
95
|
+
if (!parseBash) {
|
|
96
|
+
return { parseError: "just-bash parse unavailable", topLevelInvocations: [] };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const ast: any = parseBash(command);
|
|
100
|
+
const topLevelInvocations: BashInvocation[] = [];
|
|
101
|
+
|
|
102
|
+
if (!ast || typeof ast !== "object" || !Array.isArray(ast.statements)) {
|
|
103
|
+
return { topLevelInvocations };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
ast.statements.forEach((statement: any, statementIndex: number) => {
|
|
107
|
+
if (!statement || typeof statement !== "object" || !Array.isArray(statement.pipelines)) return;
|
|
108
|
+
|
|
109
|
+
statement.pipelines.forEach((pipeline: any, pipelineIndex: number) => {
|
|
110
|
+
if (!pipeline || typeof pipeline !== "object" || !Array.isArray(pipeline.commands)) return;
|
|
111
|
+
|
|
112
|
+
const pipelineLength = pipeline.commands.length;
|
|
113
|
+
pipeline.commands.forEach((commandNode: any) => {
|
|
114
|
+
if (!commandNode || commandNode.type !== "SimpleCommand") return;
|
|
115
|
+
|
|
116
|
+
const commandNameRaw = wordToText(commandNode.name).trim();
|
|
117
|
+
if (!commandNameRaw) return;
|
|
118
|
+
|
|
119
|
+
const args = Array.isArray(commandNode.args)
|
|
120
|
+
? commandNode.args.map((arg: any) => wordToText(arg)).filter(Boolean)
|
|
121
|
+
: [];
|
|
122
|
+
|
|
123
|
+
topLevelInvocations.push({
|
|
124
|
+
statementIndex,
|
|
125
|
+
pipelineIndex,
|
|
126
|
+
pipelineLength,
|
|
127
|
+
commandNameRaw,
|
|
128
|
+
commandName: commandBaseName(commandNameRaw),
|
|
129
|
+
args,
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return { topLevelInvocations };
|
|
136
|
+
} catch (error: any) {
|
|
137
|
+
return {
|
|
138
|
+
parseError: error?.message ?? String(error),
|
|
139
|
+
topLevelInvocations: [],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function hasSemicolonOutsideQuotes(script: string): boolean {
|
|
145
|
+
let inSingleQuote = false;
|
|
146
|
+
let inDoubleQuote = false;
|
|
147
|
+
let escaped = false;
|
|
148
|
+
|
|
149
|
+
for (let i = 0; i < script.length; i += 1) {
|
|
150
|
+
const ch = script[i];
|
|
151
|
+
|
|
152
|
+
if (escaped) {
|
|
153
|
+
escaped = false;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (ch === "\\") {
|
|
158
|
+
escaped = true;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!inDoubleQuote && ch === "'") {
|
|
163
|
+
inSingleQuote = !inSingleQuote;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!inSingleQuote && ch === '"') {
|
|
168
|
+
inDoubleQuote = !inDoubleQuote;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!inSingleQuote && !inDoubleQuote && ch === ";") {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
7
180
|
/**
|
|
8
181
|
* RepoPrompt CLI ↔ Pi integration extension
|
|
9
182
|
*
|
|
@@ -19,6 +192,7 @@ import * as Diff from "diff";
|
|
|
19
192
|
* UX goals:
|
|
20
193
|
* - Persist binding across session reloads via `pi.appendEntry()` (does not enter LLM context)
|
|
21
194
|
* - Provide actionable error messages when blocked
|
|
195
|
+
* - For best command parsing (AST-based), install `just-bash` >= 2; otherwise it falls back to a legacy splitter
|
|
22
196
|
* - Syntax-highlight fenced code blocks in output (read, structure, etc.)
|
|
23
197
|
* - Word-level diff highlighting for edit output
|
|
24
198
|
*/
|
|
@@ -66,8 +240,13 @@ function truncateText(text: string, maxChars: number): { text: string; truncated
|
|
|
66
240
|
};
|
|
67
241
|
}
|
|
68
242
|
|
|
69
|
-
|
|
70
|
-
|
|
243
|
+
type ParsedCommandChain = {
|
|
244
|
+
commands: string[];
|
|
245
|
+
invocations: BashInvocation[];
|
|
246
|
+
hasSemicolonOutsideQuotes: boolean;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
function parseCommandChainLegacy(cmd: string): { commands: string[]; hasSemicolonOutsideQuotes: boolean } {
|
|
71
250
|
const commands: string[] = [];
|
|
72
251
|
let current = "";
|
|
73
252
|
let inSingleQuote = false;
|
|
@@ -81,7 +260,7 @@ function parseCommandChain(cmd: string): { commands: string[]; hasSemicolonOutsi
|
|
|
81
260
|
current = "";
|
|
82
261
|
};
|
|
83
262
|
|
|
84
|
-
for (let i = 0; i < cmd.length; i
|
|
263
|
+
for (let i = 0; i < cmd.length; i += 1) {
|
|
85
264
|
const ch = cmd[i];
|
|
86
265
|
|
|
87
266
|
if (escaped) {
|
|
@@ -102,7 +281,7 @@ function parseCommandChain(cmd: string): { commands: string[]; hasSemicolonOutsi
|
|
|
102
281
|
continue;
|
|
103
282
|
}
|
|
104
283
|
|
|
105
|
-
if (!inSingleQuote && ch === "
|
|
284
|
+
if (!inSingleQuote && ch === '"') {
|
|
106
285
|
inDoubleQuote = !inDoubleQuote;
|
|
107
286
|
current += ch;
|
|
108
287
|
continue;
|
|
@@ -129,21 +308,74 @@ function parseCommandChain(cmd: string): { commands: string[]; hasSemicolonOutsi
|
|
|
129
308
|
return { commands, hasSemicolonOutsideQuotes };
|
|
130
309
|
}
|
|
131
310
|
|
|
311
|
+
function renderInvocation(invocation: BashInvocation): string {
|
|
312
|
+
return [invocation.commandNameRaw, ...invocation.args].filter(Boolean).join(" ").trim();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function parseCommandChain(cmd: string): ParsedCommandChain {
|
|
316
|
+
const semicolonOutsideQuotes = hasSemicolonOutsideQuotes(cmd);
|
|
317
|
+
const analysis = analyzeTopLevelBashScript(cmd);
|
|
318
|
+
|
|
319
|
+
if (!analysis.parseError && analysis.topLevelInvocations.length > 0) {
|
|
320
|
+
const commands = analysis.topLevelInvocations
|
|
321
|
+
.map(renderInvocation)
|
|
322
|
+
.filter((command) => command.length > 0);
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
commands,
|
|
326
|
+
invocations: analysis.topLevelInvocations,
|
|
327
|
+
hasSemicolonOutsideQuotes: semicolonOutsideQuotes,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const legacy = parseCommandChainLegacy(cmd);
|
|
332
|
+
return {
|
|
333
|
+
commands: legacy.commands,
|
|
334
|
+
invocations: [],
|
|
335
|
+
hasSemicolonOutsideQuotes: legacy.hasSemicolonOutsideQuotes || semicolonOutsideQuotes,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
132
339
|
function looksLikeDeleteCommand(cmd: string): boolean {
|
|
133
|
-
|
|
134
|
-
|
|
340
|
+
const parsed = parseCommandChain(cmd);
|
|
341
|
+
|
|
342
|
+
if (parsed.invocations.length > 0) {
|
|
343
|
+
for (const invocation of parsed.invocations) {
|
|
344
|
+
const commandName = invocation.commandName;
|
|
345
|
+
const args = invocation.args.map((arg) => arg.toLowerCase());
|
|
346
|
+
|
|
347
|
+
if (commandName === "file" && args[0] === "delete") return true;
|
|
348
|
+
if (commandName === "workspace" && args[0] === "delete") return true;
|
|
349
|
+
|
|
350
|
+
if (commandName === "call") {
|
|
351
|
+
const normalized = args.join(" ");
|
|
352
|
+
if (
|
|
353
|
+
/\baction\s*=\s*delete\b/.test(normalized)
|
|
354
|
+
|| /"action"\s*:\s*"delete"/.test(normalized)
|
|
355
|
+
|| /'action'\s*:\s*'delete'/.test(normalized)
|
|
356
|
+
) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Fallback when parsing fails
|
|
365
|
+
for (const command of parsed.commands) {
|
|
135
366
|
const normalized = command.trim().toLowerCase();
|
|
136
367
|
if (normalized === "file delete" || normalized.startsWith("file delete ")) return true;
|
|
137
368
|
if (normalized === "workspace delete" || normalized.startsWith("workspace delete ")) return true;
|
|
138
369
|
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
370
|
+
if (
|
|
371
|
+
normalized.startsWith("call ")
|
|
372
|
+
&& (
|
|
373
|
+
/\baction\s*=\s*delete\b/.test(normalized)
|
|
374
|
+
|| /"action"\s*:\s*"delete"/.test(normalized)
|
|
375
|
+
|| /'action'\s*:\s*'delete'/.test(normalized)
|
|
376
|
+
)
|
|
377
|
+
) {
|
|
378
|
+
return true;
|
|
147
379
|
}
|
|
148
380
|
}
|
|
149
381
|
|
|
@@ -151,8 +383,26 @@ function looksLikeDeleteCommand(cmd: string): boolean {
|
|
|
151
383
|
}
|
|
152
384
|
|
|
153
385
|
function looksLikeWorkspaceSwitchInPlace(cmd: string): boolean {
|
|
154
|
-
|
|
155
|
-
|
|
386
|
+
const parsed = parseCommandChain(cmd);
|
|
387
|
+
|
|
388
|
+
if (parsed.invocations.length > 0) {
|
|
389
|
+
for (const invocation of parsed.invocations) {
|
|
390
|
+
if (invocation.commandName !== "workspace") continue;
|
|
391
|
+
|
|
392
|
+
const args = invocation.args.map((arg) => arg.toLowerCase());
|
|
393
|
+
const action = args[0] ?? "";
|
|
394
|
+
const hasNewWindow = args.includes("--new-window");
|
|
395
|
+
const hasSwitchFlag = args.includes("--switch");
|
|
396
|
+
|
|
397
|
+
if (action === "switch" && !hasNewWindow) return true;
|
|
398
|
+
if (action === "create" && hasSwitchFlag && !hasNewWindow) return true;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Fallback when parsing fails
|
|
405
|
+
for (const command of parsed.commands) {
|
|
156
406
|
const normalized = command.toLowerCase();
|
|
157
407
|
|
|
158
408
|
if (normalized.startsWith("workspace switch ") && !normalized.includes("--new-window")) return true;
|
|
@@ -166,15 +416,22 @@ function looksLikeWorkspaceSwitchInPlace(cmd: string): boolean {
|
|
|
166
416
|
}
|
|
167
417
|
|
|
168
418
|
function looksLikeEditCommand(cmd: string): boolean {
|
|
169
|
-
|
|
170
|
-
const normalized = command.trim().toLowerCase();
|
|
419
|
+
const parsed = parseCommandChain(cmd);
|
|
171
420
|
|
|
172
|
-
|
|
421
|
+
if (parsed.invocations.length > 0) {
|
|
422
|
+
return parsed.invocations.some((invocation) => {
|
|
423
|
+
if (invocation.commandName === "edit") return true;
|
|
424
|
+
if (invocation.commandName !== "call") return false;
|
|
173
425
|
|
|
174
|
-
|
|
426
|
+
return invocation.args.some((arg) => arg.toLowerCase().includes("apply_edits"));
|
|
427
|
+
});
|
|
175
428
|
}
|
|
176
429
|
|
|
177
|
-
return
|
|
430
|
+
return parsed.commands.some((command) => {
|
|
431
|
+
const normalized = command.trim().toLowerCase();
|
|
432
|
+
if (normalized === "edit" || normalized.startsWith("edit ")) return true;
|
|
433
|
+
return normalized.startsWith("call ") && normalized.includes("apply_edits");
|
|
434
|
+
});
|
|
178
435
|
}
|
|
179
436
|
|
|
180
437
|
function parseLeadingInt(text: string): number | undefined {
|
|
@@ -219,7 +476,31 @@ function looksLikeNoopEditOutput(output: string): boolean {
|
|
|
219
476
|
}
|
|
220
477
|
|
|
221
478
|
function isSafeSingleCommandToRunUnbound(cmd: string): boolean {
|
|
222
|
-
|
|
479
|
+
const parsed = parseCommandChain(cmd);
|
|
480
|
+
|
|
481
|
+
if (parsed.invocations.length > 0) {
|
|
482
|
+
if (parsed.invocations.length !== 1) return false;
|
|
483
|
+
const invocation = parsed.invocations[0];
|
|
484
|
+
const commandName = invocation.commandName;
|
|
485
|
+
const args = invocation.args.map((arg) => arg.toLowerCase());
|
|
486
|
+
|
|
487
|
+
if (commandName === "windows") return true;
|
|
488
|
+
if (commandName === "help") return true;
|
|
489
|
+
if (commandName === "refresh" && args.length === 0) return true;
|
|
490
|
+
if (commandName === "tabs" && args.length === 0) return true;
|
|
491
|
+
|
|
492
|
+
if (commandName === "workspace") {
|
|
493
|
+
const action = args[0] ?? "";
|
|
494
|
+
if (action === "list") return true;
|
|
495
|
+
if (action === "tabs") return true;
|
|
496
|
+
if (action === "switch" && args.includes("--new-window")) return true;
|
|
497
|
+
if (action === "create" && args.includes("--new-window")) return true;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Fallback when parsing fails
|
|
223
504
|
const normalized = cmd.trim().toLowerCase();
|
|
224
505
|
|
|
225
506
|
if (normalized === "windows" || normalized.startsWith("windows ")) return true;
|
|
@@ -240,8 +521,15 @@ function isSafeToRunUnbound(cmd: string): boolean {
|
|
|
240
521
|
// Allow `&&` chains, but only if *every* sub-command is safe before binding
|
|
241
522
|
const parsed = parseCommandChain(cmd);
|
|
242
523
|
if (parsed.hasSemicolonOutsideQuotes) return false;
|
|
243
|
-
if (parsed.commands.length === 0) return false;
|
|
244
524
|
|
|
525
|
+
if (parsed.invocations.length > 0) {
|
|
526
|
+
return parsed.invocations.every((invocation) => {
|
|
527
|
+
const commandText = renderInvocation(invocation);
|
|
528
|
+
return isSafeSingleCommandToRunUnbound(commandText);
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (parsed.commands.length === 0) return false;
|
|
245
533
|
return parsed.commands.every((command) => isSafeSingleCommandToRunUnbound(command));
|
|
246
534
|
}
|
|
247
535
|
|
|
@@ -536,11 +824,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
536
824
|
};
|
|
537
825
|
|
|
538
826
|
const reconstructBinding = (ctx: ExtensionContext) => {
|
|
539
|
-
// Prefer persisted binding (appendEntry)
|
|
827
|
+
// Prefer persisted binding (appendEntry) from the *current branch*, then fall back to prior rp_bind tool results
|
|
828
|
+
// Branch semantics: if the current branch has no binding state, stay unbound
|
|
829
|
+
boundWindowId = undefined;
|
|
830
|
+
boundTab = undefined;
|
|
831
|
+
|
|
540
832
|
let reconstructedWindowId: number | undefined;
|
|
541
833
|
let reconstructedTab: string | undefined;
|
|
542
834
|
|
|
543
|
-
for (const entry of ctx.sessionManager.
|
|
835
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
544
836
|
if (entry.type !== "custom" || entry.customType !== BINDING_CUSTOM_TYPE) continue;
|
|
545
837
|
|
|
546
838
|
const data = entry.data as { windowId?: unknown; tab?: unknown } | undefined;
|
|
@@ -571,6 +863,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
571
863
|
|
|
572
864
|
pi.on("session_start", async (_event, ctx) => reconstructBinding(ctx));
|
|
573
865
|
pi.on("session_switch", async (_event, ctx) => reconstructBinding(ctx));
|
|
866
|
+
// session_fork is the current event name; keep session_branch for backwards compatibility
|
|
867
|
+
pi.on("session_fork", async (_event, ctx) => reconstructBinding(ctx));
|
|
574
868
|
pi.on("session_branch", async (_event, ctx) => reconstructBinding(ctx));
|
|
575
869
|
pi.on("session_tree", async (_event, ctx) => reconstructBinding(ctx));
|
|
576
870
|
|
|
@@ -594,7 +888,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
594
888
|
description: "Bind rp_exec to a specific RepoPrompt window and compose tab",
|
|
595
889
|
parameters: BindParams,
|
|
596
890
|
|
|
597
|
-
async execute(_toolCallId, params, _signal, _onUpdate,
|
|
891
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
892
|
+
await ensureJustBashLoaded();
|
|
893
|
+
maybeWarnAstUnavailable(ctx);
|
|
598
894
|
persistBinding(params.windowId, params.tab);
|
|
599
895
|
|
|
600
896
|
return {
|
|
@@ -610,8 +906,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
610
906
|
description: "Run rp-cli in the bound RepoPrompt window/tab, with quiet defaults and output truncation",
|
|
611
907
|
parameters: ExecParams,
|
|
612
908
|
|
|
613
|
-
async execute(_toolCallId, params, signal, onUpdate,
|
|
909
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
614
910
|
// Routing: prefer call-time overrides, otherwise fall back to the last persisted binding
|
|
911
|
+
await ensureJustBashLoaded();
|
|
912
|
+
maybeWarnAstUnavailable(ctx);
|
|
913
|
+
|
|
615
914
|
const windowId = params.windowId ?? boundWindowId;
|
|
616
915
|
const tab = params.tab ?? boundTab;
|
|
617
916
|
const rawJson = params.rawJson ?? false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-repoprompt-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Integrates RepoPrompt with Pi via RepoPrompt's `rp-cli` executable",
|
|
5
5
|
"keywords": ["pi-package", "pi", "pi-coding-agent", "repoprompt"],
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"extensions": ["extensions/repoprompt-cli.ts"]
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"diff": "^7.0.0"
|
|
20
|
+
"diff": "^7.0.0",
|
|
21
|
+
"just-bash": "^2.10.0"
|
|
21
22
|
},
|
|
22
23
|
"peerDependencies": {
|
|
23
24
|
"@mariozechner/pi-coding-agent": ">=0.51.0",
|