invar-tools 1.15.0__py3-none-any.whl → 1.15.2__py3-none-any.whl
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.
- invar/shell/pi_tools.py +7 -0
- invar/templates/pi-tools/invar/index.ts +409 -22
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/METADATA +1 -1
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/RECORD +9 -9
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/WHEEL +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/entry_points.txt +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/licenses/LICENSE +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/licenses/LICENSE-GPL +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.2.dist-info}/licenses/NOTICE +0 -0
invar/shell/pi_tools.py
CHANGED
|
@@ -35,6 +35,12 @@ def install_pi_tools(
|
|
|
35
35
|
- invar_guard: Wrapper for invar guard command
|
|
36
36
|
- invar_sig: Wrapper for invar sig command
|
|
37
37
|
- invar_map: Wrapper for invar map command
|
|
38
|
+
- invar_doc_toc: Extract document structure
|
|
39
|
+
- invar_doc_read: Read specific section
|
|
40
|
+
- invar_doc_find: Find sections by pattern
|
|
41
|
+
- invar_doc_replace: Replace section content
|
|
42
|
+
- invar_doc_insert: Insert content relative to section
|
|
43
|
+
- invar_doc_delete: Delete section
|
|
38
44
|
"""
|
|
39
45
|
tools_dir = project_path / PI_TOOLS_DIR
|
|
40
46
|
tools_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -44,6 +50,7 @@ def install_pi_tools(
|
|
|
44
50
|
console.print(" ✓ invar_guard - Smart verification (static + doctests + symbolic)")
|
|
45
51
|
console.print(" ✓ invar_sig - Show function signatures and contracts")
|
|
46
52
|
console.print(" ✓ invar_map - Symbol map with reference counts")
|
|
53
|
+
console.print(" ✓ 6 doc tools - Structured markdown editing (toc, read, find, replace, insert, delete)")
|
|
47
54
|
console.print("")
|
|
48
55
|
|
|
49
56
|
template_path = get_pi_tools_template_path()
|
|
@@ -7,16 +7,24 @@
|
|
|
7
7
|
|
|
8
8
|
import { Type } from "@sinclair/typebox";
|
|
9
9
|
import type { CustomToolFactory } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import * as fs from "fs";
|
|
11
|
+
import * as path from "path";
|
|
10
12
|
|
|
11
13
|
const factory: CustomToolFactory = (pi) => {
|
|
12
|
-
// Helper to
|
|
13
|
-
async function
|
|
14
|
+
// Helper to resolve invar command (with uvx fallback)
|
|
15
|
+
async function resolveInvarCommand(): Promise<{ command: string; args: string[] }> {
|
|
16
|
+
// Try direct invar command first
|
|
14
17
|
try {
|
|
15
18
|
const result = await pi.exec("which", ["invar"]);
|
|
16
|
-
|
|
19
|
+
if (result.exitCode === 0) {
|
|
20
|
+
return { command: "invar", args: [] };
|
|
21
|
+
}
|
|
17
22
|
} catch {
|
|
18
|
-
|
|
23
|
+
// Fall through to uvx
|
|
19
24
|
}
|
|
25
|
+
|
|
26
|
+
// Fallback to uvx invar-tools
|
|
27
|
+
return { command: "uvx", args: ["invar-tools"] };
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
// Helper to validate path/target parameters (defense-in-depth)
|
|
@@ -58,12 +66,8 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
58
66
|
})),
|
|
59
67
|
}),
|
|
60
68
|
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
throw new Error("Invar not installed. Run: pip install invar-tools");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const args = ["guard"];
|
|
69
|
+
const cmd = await resolveInvarCommand();
|
|
70
|
+
const args = [...cmd.args, "guard"];
|
|
67
71
|
|
|
68
72
|
// Default is --changed (check modified files)
|
|
69
73
|
if (params.changed === false) {
|
|
@@ -80,7 +84,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
80
84
|
args.push("--strict");
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
const result = await pi.exec(
|
|
87
|
+
const result = await pi.exec(cmd.command, args, { cwd: pi.cwd, signal });
|
|
84
88
|
|
|
85
89
|
if (result.killed) {
|
|
86
90
|
throw new Error("Guard verification was cancelled");
|
|
@@ -111,16 +115,13 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
111
115
|
}),
|
|
112
116
|
}),
|
|
113
117
|
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
114
|
-
const
|
|
115
|
-
if (!installed) {
|
|
116
|
-
throw new Error("Invar not installed. Run: pip install invar-tools");
|
|
117
|
-
}
|
|
118
|
+
const cmd = await resolveInvarCommand();
|
|
118
119
|
|
|
119
120
|
if (!isValidPath(params.target)) {
|
|
120
121
|
throw new Error("Invalid target path: contains unsafe characters or path traversal");
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
const result = await pi.exec(
|
|
124
|
+
const result = await pi.exec(cmd.command, [...cmd.args, "sig", params.target], {
|
|
124
125
|
cwd: pi.cwd,
|
|
125
126
|
signal,
|
|
126
127
|
});
|
|
@@ -160,16 +161,13 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
160
161
|
})),
|
|
161
162
|
}),
|
|
162
163
|
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
163
|
-
const
|
|
164
|
-
if (!installed) {
|
|
165
|
-
throw new Error("Invar not installed. Run: pip install invar-tools");
|
|
166
|
-
}
|
|
164
|
+
const cmd = await resolveInvarCommand();
|
|
167
165
|
|
|
168
166
|
if (params.path && params.path !== "." && !isValidPath(params.path)) {
|
|
169
167
|
throw new Error("Invalid path: contains unsafe characters or path traversal");
|
|
170
168
|
}
|
|
171
169
|
|
|
172
|
-
const args = ["map"];
|
|
170
|
+
const args = [...cmd.args, "map"];
|
|
173
171
|
|
|
174
172
|
if (params.path && params.path !== ".") {
|
|
175
173
|
args.push(params.path);
|
|
@@ -179,7 +177,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
179
177
|
args.push("--top", params.top.toString());
|
|
180
178
|
}
|
|
181
179
|
|
|
182
|
-
const result = await pi.exec(
|
|
180
|
+
const result = await pi.exec(cmd.command, args, {
|
|
183
181
|
cwd: pi.cwd,
|
|
184
182
|
signal,
|
|
185
183
|
});
|
|
@@ -201,6 +199,395 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
201
199
|
};
|
|
202
200
|
},
|
|
203
201
|
},
|
|
202
|
+
|
|
203
|
+
// =========================================================================
|
|
204
|
+
// invar_doc_toc - Extract document structure (Table of Contents)
|
|
205
|
+
// =========================================================================
|
|
206
|
+
{
|
|
207
|
+
name: "invar_doc_toc",
|
|
208
|
+
label: "Invar Doc TOC",
|
|
209
|
+
description: "Extract document structure (Table of Contents) from markdown files. Shows headings hierarchy with line numbers and character counts. Use this INSTEAD of Read() to understand markdown structure.",
|
|
210
|
+
parameters: Type.Object({
|
|
211
|
+
file: Type.String({
|
|
212
|
+
description: "Path to markdown file",
|
|
213
|
+
}),
|
|
214
|
+
depth: Type.Optional(Type.Number({
|
|
215
|
+
description: "Maximum heading depth to include (1-6)",
|
|
216
|
+
default: 6,
|
|
217
|
+
minimum: 1,
|
|
218
|
+
maximum: 6,
|
|
219
|
+
})),
|
|
220
|
+
}),
|
|
221
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
222
|
+
const cmd = await resolveInvarCommand();
|
|
223
|
+
|
|
224
|
+
if (!isValidPath(params.file)) {
|
|
225
|
+
throw new Error("Invalid file path: contains unsafe characters or path traversal");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const args = [...cmd.args, "doc", "toc", params.file];
|
|
229
|
+
|
|
230
|
+
if (params.depth && params.depth !== 6) {
|
|
231
|
+
args.push("--depth", params.depth.toString());
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const result = await pi.exec(cmd.command, args, {
|
|
235
|
+
cwd: pi.cwd,
|
|
236
|
+
signal,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (result.killed) {
|
|
240
|
+
throw new Error("Doc toc command was cancelled");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (result.exitCode !== 0) {
|
|
244
|
+
throw new Error(`Failed to extract TOC: ${result.stderr}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
content: [{ type: "text", text: result.stdout }],
|
|
249
|
+
details: {
|
|
250
|
+
file: params.file,
|
|
251
|
+
depth: params.depth || 6,
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// =========================================================================
|
|
258
|
+
// invar_doc_read - Read a specific section from a document
|
|
259
|
+
// =========================================================================
|
|
260
|
+
{
|
|
261
|
+
name: "invar_doc_read",
|
|
262
|
+
label: "Invar Doc Read",
|
|
263
|
+
description: "Read a specific section from a markdown document. Supports multiple addressing formats: slug path, fuzzy match, index (#0/#1), or line anchor (@48). Use this INSTEAD of Read() with manual line counting.",
|
|
264
|
+
parameters: Type.Object({
|
|
265
|
+
file: Type.String({
|
|
266
|
+
description: "Path to markdown file",
|
|
267
|
+
}),
|
|
268
|
+
section: Type.String({
|
|
269
|
+
description: "Section path: slug ('requirements/auth'), fuzzy ('auth'), index ('#0/#1'), or line ('@48')",
|
|
270
|
+
}),
|
|
271
|
+
children: Type.Optional(Type.Boolean({
|
|
272
|
+
description: "Include child sections in output",
|
|
273
|
+
default: true,
|
|
274
|
+
})),
|
|
275
|
+
}),
|
|
276
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
277
|
+
const cmd = await resolveInvarCommand();
|
|
278
|
+
|
|
279
|
+
if (!isValidPath(params.file) || !isValidPath(params.section)) {
|
|
280
|
+
throw new Error("Invalid file or section path: contains unsafe characters or path traversal");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const args = [...cmd.args, "doc", "read", params.file, params.section, "--json"];
|
|
284
|
+
|
|
285
|
+
if (params.children === false) {
|
|
286
|
+
args.push("--no-children");
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const result = await pi.exec(cmd.command, args, {
|
|
290
|
+
cwd: pi.cwd,
|
|
291
|
+
signal,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (result.killed) {
|
|
295
|
+
throw new Error("Doc read command was cancelled");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (result.exitCode !== 0) {
|
|
299
|
+
throw new Error(`Failed to read section: ${result.stderr}`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
content: [{ type: "text", text: result.stdout }],
|
|
304
|
+
details: {
|
|
305
|
+
file: params.file,
|
|
306
|
+
section: params.section,
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
// =========================================================================
|
|
313
|
+
// invar_doc_find - Find sections matching a pattern
|
|
314
|
+
// =========================================================================
|
|
315
|
+
{
|
|
316
|
+
name: "invar_doc_find",
|
|
317
|
+
label: "Invar Doc Find",
|
|
318
|
+
description: "Find sections in markdown documents matching a pattern. Supports glob patterns for titles and optional content search. Use this INSTEAD of Grep in markdown files.",
|
|
319
|
+
parameters: Type.Object({
|
|
320
|
+
file: Type.String({
|
|
321
|
+
description: "Path to markdown file",
|
|
322
|
+
}),
|
|
323
|
+
pattern: Type.String({
|
|
324
|
+
description: "Title pattern (glob-style, e.g., '*auth*')",
|
|
325
|
+
}),
|
|
326
|
+
content: Type.Optional(Type.String({
|
|
327
|
+
description: "Optional content search pattern",
|
|
328
|
+
})),
|
|
329
|
+
level: Type.Optional(Type.Number({
|
|
330
|
+
description: "Filter by heading level (1-6)",
|
|
331
|
+
minimum: 1,
|
|
332
|
+
maximum: 6,
|
|
333
|
+
})),
|
|
334
|
+
}),
|
|
335
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
336
|
+
const cmd = await resolveInvarCommand();
|
|
337
|
+
|
|
338
|
+
if (!isValidPath(params.file)) {
|
|
339
|
+
throw new Error("Invalid file path: contains unsafe characters or path traversal");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const args = [...cmd.args, "doc", "find", params.pattern, params.file, "--json"];
|
|
343
|
+
|
|
344
|
+
if (params.content) {
|
|
345
|
+
args.push("--content", params.content);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (params.level) {
|
|
349
|
+
args.push("--level", params.level.toString());
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const result = await pi.exec(cmd.command, args, {
|
|
353
|
+
cwd: pi.cwd,
|
|
354
|
+
signal,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
if (result.killed) {
|
|
358
|
+
throw new Error("Doc find command was cancelled");
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (result.exitCode !== 0) {
|
|
362
|
+
throw new Error(`Failed to find sections: ${result.stderr}`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return {
|
|
366
|
+
content: [{ type: "text", text: result.stdout }],
|
|
367
|
+
details: {
|
|
368
|
+
file: params.file,
|
|
369
|
+
pattern: params.pattern,
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
// =========================================================================
|
|
376
|
+
// invar_doc_replace - Replace a section's content
|
|
377
|
+
// =========================================================================
|
|
378
|
+
{
|
|
379
|
+
name: "invar_doc_replace",
|
|
380
|
+
label: "Invar Doc Replace",
|
|
381
|
+
description: "Replace a section's content in a markdown document. Use this INSTEAD of Edit()/Write() for section replacement.",
|
|
382
|
+
parameters: Type.Object({
|
|
383
|
+
file: Type.String({
|
|
384
|
+
description: "Path to markdown file",
|
|
385
|
+
}),
|
|
386
|
+
section: Type.String({
|
|
387
|
+
description: "Section path to replace (slug, fuzzy, index, or line anchor)",
|
|
388
|
+
}),
|
|
389
|
+
content: Type.String({
|
|
390
|
+
description: "New content to replace the section with",
|
|
391
|
+
}),
|
|
392
|
+
keep_heading: Type.Optional(Type.Boolean({
|
|
393
|
+
description: "If true, preserve the original heading line",
|
|
394
|
+
default: true,
|
|
395
|
+
})),
|
|
396
|
+
}),
|
|
397
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
398
|
+
const cmd = await resolveInvarCommand();
|
|
399
|
+
|
|
400
|
+
if (!isValidPath(params.file) || !isValidPath(params.section)) {
|
|
401
|
+
throw new Error("Invalid file or section path: contains unsafe characters or path traversal");
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Write content to temporary file to avoid shell injection
|
|
405
|
+
const tmpFile = path.join(pi.cwd, `.invar-tmp-${Date.now()}.txt`);
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
fs.writeFileSync(tmpFile, params.content, "utf-8");
|
|
409
|
+
|
|
410
|
+
const args = [
|
|
411
|
+
...cmd.args,
|
|
412
|
+
"doc",
|
|
413
|
+
"replace",
|
|
414
|
+
params.file,
|
|
415
|
+
params.section,
|
|
416
|
+
"--content",
|
|
417
|
+
tmpFile,
|
|
418
|
+
];
|
|
419
|
+
|
|
420
|
+
if (params.keep_heading === false) {
|
|
421
|
+
args.push("--no-keep-heading");
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const result = await pi.exec(cmd.command, args, {
|
|
425
|
+
cwd: pi.cwd,
|
|
426
|
+
signal,
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
if (result.killed) {
|
|
430
|
+
throw new Error("Doc replace command was cancelled");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (result.exitCode !== 0) {
|
|
434
|
+
throw new Error(`Failed to replace section: ${result.stderr}`);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
content: [{ type: "text", text: result.stdout || "Section replaced successfully" }],
|
|
439
|
+
details: {
|
|
440
|
+
file: params.file,
|
|
441
|
+
section: params.section,
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
} finally {
|
|
445
|
+
// Clean up temp file
|
|
446
|
+
try {
|
|
447
|
+
fs.unlinkSync(tmpFile);
|
|
448
|
+
} catch {
|
|
449
|
+
// Ignore cleanup errors
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
// =========================================================================
|
|
456
|
+
// invar_doc_insert - Insert new content relative to a section
|
|
457
|
+
// =========================================================================
|
|
458
|
+
{
|
|
459
|
+
name: "invar_doc_insert",
|
|
460
|
+
label: "Invar Doc Insert",
|
|
461
|
+
description: "Insert new content relative to a section in a markdown document. Use this INSTEAD of Edit()/Write() for section insertion.",
|
|
462
|
+
parameters: Type.Object({
|
|
463
|
+
file: Type.String({
|
|
464
|
+
description: "Path to markdown file",
|
|
465
|
+
}),
|
|
466
|
+
anchor: Type.String({
|
|
467
|
+
description: "Section path for the anchor (slug, fuzzy, index, or line anchor)",
|
|
468
|
+
}),
|
|
469
|
+
content: Type.String({
|
|
470
|
+
description: "Content to insert (include heading if new section)",
|
|
471
|
+
}),
|
|
472
|
+
position: Type.Optional(Type.String({
|
|
473
|
+
description: "Where to insert: 'before', 'after', 'first_child', 'last_child'",
|
|
474
|
+
default: "after",
|
|
475
|
+
enum: ["before", "after", "first_child", "last_child"],
|
|
476
|
+
})),
|
|
477
|
+
}),
|
|
478
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
479
|
+
const cmd = await resolveInvarCommand();
|
|
480
|
+
|
|
481
|
+
if (!isValidPath(params.file) || !isValidPath(params.anchor)) {
|
|
482
|
+
throw new Error("Invalid file or anchor path: contains unsafe characters or path traversal");
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Write content to temporary file
|
|
486
|
+
const tmpFile = path.join(pi.cwd, `.invar-tmp-${Date.now()}.txt`);
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
fs.writeFileSync(tmpFile, params.content, "utf-8");
|
|
490
|
+
|
|
491
|
+
const args = [
|
|
492
|
+
...cmd.args,
|
|
493
|
+
"doc",
|
|
494
|
+
"insert",
|
|
495
|
+
params.file,
|
|
496
|
+
params.anchor,
|
|
497
|
+
"--content",
|
|
498
|
+
tmpFile,
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
if (params.position && params.position !== "after") {
|
|
502
|
+
args.push("--position", params.position);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const result = await pi.exec(cmd.command, args, {
|
|
506
|
+
cwd: pi.cwd,
|
|
507
|
+
signal,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
if (result.killed) {
|
|
511
|
+
throw new Error("Doc insert command was cancelled");
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (result.exitCode !== 0) {
|
|
515
|
+
throw new Error(`Failed to insert content: ${result.stderr}`);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return {
|
|
519
|
+
content: [{ type: "text", text: result.stdout || "Content inserted successfully" }],
|
|
520
|
+
details: {
|
|
521
|
+
file: params.file,
|
|
522
|
+
anchor: params.anchor,
|
|
523
|
+
position: params.position || "after",
|
|
524
|
+
},
|
|
525
|
+
};
|
|
526
|
+
} finally {
|
|
527
|
+
// Clean up temp file
|
|
528
|
+
try {
|
|
529
|
+
fs.unlinkSync(tmpFile);
|
|
530
|
+
} catch {
|
|
531
|
+
// Ignore cleanup errors
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
|
|
537
|
+
// =========================================================================
|
|
538
|
+
// invar_doc_delete - Delete a section from a document
|
|
539
|
+
// =========================================================================
|
|
540
|
+
{
|
|
541
|
+
name: "invar_doc_delete",
|
|
542
|
+
label: "Invar Doc Delete",
|
|
543
|
+
description: "Delete a section from a markdown document. Use this INSTEAD of Edit()/Write() for section deletion.",
|
|
544
|
+
parameters: Type.Object({
|
|
545
|
+
file: Type.String({
|
|
546
|
+
description: "Path to markdown file",
|
|
547
|
+
}),
|
|
548
|
+
section: Type.String({
|
|
549
|
+
description: "Section path to delete (slug, fuzzy, index, or line anchor)",
|
|
550
|
+
}),
|
|
551
|
+
children: Type.Optional(Type.Boolean({
|
|
552
|
+
description: "Include child sections in deletion",
|
|
553
|
+
default: true,
|
|
554
|
+
})),
|
|
555
|
+
}),
|
|
556
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
557
|
+
const cmd = await resolveInvarCommand();
|
|
558
|
+
|
|
559
|
+
if (!isValidPath(params.file) || !isValidPath(params.section)) {
|
|
560
|
+
throw new Error("Invalid file or section path: contains unsafe characters or path traversal");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const args = [...cmd.args, "doc", "delete", params.file, params.section];
|
|
564
|
+
|
|
565
|
+
if (params.children === false) {
|
|
566
|
+
args.push("--no-children");
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const result = await pi.exec(cmd.command, args, {
|
|
570
|
+
cwd: pi.cwd,
|
|
571
|
+
signal,
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
if (result.killed) {
|
|
575
|
+
throw new Error("Doc delete command was cancelled");
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (result.exitCode !== 0) {
|
|
579
|
+
throw new Error(`Failed to delete section: ${result.stderr}`);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return {
|
|
583
|
+
content: [{ type: "text", text: result.stdout || "Section deleted successfully" }],
|
|
584
|
+
details: {
|
|
585
|
+
file: params.file,
|
|
586
|
+
section: params.section,
|
|
587
|
+
},
|
|
588
|
+
};
|
|
589
|
+
},
|
|
590
|
+
},
|
|
204
591
|
];
|
|
205
592
|
};
|
|
206
593
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: invar-tools
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.2
|
|
4
4
|
Summary: AI-native software engineering tools with design-by-contract verification
|
|
5
5
|
Project-URL: Homepage, https://github.com/tefx/invar
|
|
6
6
|
Project-URL: Documentation, https://github.com/tefx/invar#readme
|
|
@@ -72,7 +72,7 @@ invar/shell/mcp_config.py,sha256=-hC7Y5BGuVs285b6gBARk7ZyzVxHwPgXSyt_GoN0jfs,458
|
|
|
72
72
|
invar/shell/mutation.py,sha256=Lfyk2b8j8-hxAq-iwAgQeOhr7Ci6c5tRF1TXe3CxQCs,8914
|
|
73
73
|
invar/shell/pattern_integration.py,sha256=pRcjfq3NvMW_tvQCnaXZnD1k5AVEWK8CYOE2jN6VTro,7842
|
|
74
74
|
invar/shell/pi_hooks.py,sha256=ulZc1sP8mTRJTBsjwFHQzUgg-h8ajRIMp7iF1Y4UUtw,6885
|
|
75
|
-
invar/shell/pi_tools.py,sha256=
|
|
75
|
+
invar/shell/pi_tools.py,sha256=a3ACDDXykFV8fUB5UpBmgMvppwkmLvT1k_BWm0IY47k,4068
|
|
76
76
|
invar/shell/property_tests.py,sha256=N9JreyH5PqR89oF5yLcX7ZAV-Koyg5BKo-J05-GUPsA,9109
|
|
77
77
|
invar/shell/py_refs.py,sha256=Vjz50lmt9prDBcBv4nkkODdiJ7_DKu5zO4UPZBjAfmM,4638
|
|
78
78
|
invar/shell/skill_manager.py,sha256=Mr7Mh9rxPSKSAOTJCAM5ZHiG5nfUf6KQVCuD4LBNHSI,12440
|
|
@@ -143,7 +143,7 @@ invar/templates/onboard/assessment.md.jinja,sha256=EzqF0VUcxJZG2bVJLxTOyQlAERRbh
|
|
|
143
143
|
invar/templates/onboard/roadmap.md.jinja,sha256=gmvZk4Hdwe0l3qSFV15QGcsr-OPMhsc6-1K9F2SFSIQ,3939
|
|
144
144
|
invar/templates/onboard/patterns/python.md,sha256=3wwucAcQz0DlggtpqYo-ZCnmrXgBQ0aBgUHN_EZ1VW0,8681
|
|
145
145
|
invar/templates/onboard/patterns/typescript.md,sha256=yOVfHtdAdjKkWNh66_dR7z2xEA4sggbIcCKthW-fqac,11983
|
|
146
|
-
invar/templates/pi-tools/invar/index.ts,sha256=
|
|
146
|
+
invar/templates/pi-tools/invar/index.ts,sha256=tl2SZsbfYcTq7Zpk5T9gFxRtCE_PaFYVWi_GNHiaKzY,19722
|
|
147
147
|
invar/templates/protocol/INVAR.md.jinja,sha256=t2ZIQZJvzDTJMrRw_ijUo6ScZmeNK0-nV-H7ztTIyQQ,1464
|
|
148
148
|
invar/templates/protocol/python/architecture-examples.md,sha256=O96LH9WFpk7G9MrhSbifLS5pyibTIDG-_EGFF7g3V4M,1175
|
|
149
149
|
invar/templates/protocol/python/contracts-syntax.md,sha256=Q6supTQ3tChVrlN7xhcdb3Q8VGIESxQLA-mQvrNIZmo,1162
|
|
@@ -181,10 +181,10 @@ invar/templates/skills/invar-reflect/template.md,sha256=Rr5hvbllvmd8jSLf_0ZjyKt6
|
|
|
181
181
|
invar/templates/skills/investigate/SKILL.md.jinja,sha256=cp6TBEixBYh1rLeeHOR1yqEnFqv1NZYePORMnavLkQI,3231
|
|
182
182
|
invar/templates/skills/propose/SKILL.md.jinja,sha256=6BuKiCqO1AEu3VtzMHy1QWGqr_xqG9eJlhbsKT4jev4,3463
|
|
183
183
|
invar/templates/skills/review/SKILL.md.jinja,sha256=ET5mbdSe_eKgJbi2LbgFC-z1aviKcHOBw7J5Q28fr4U,14105
|
|
184
|
-
invar_tools-1.15.
|
|
185
|
-
invar_tools-1.15.
|
|
186
|
-
invar_tools-1.15.
|
|
187
|
-
invar_tools-1.15.
|
|
188
|
-
invar_tools-1.15.
|
|
189
|
-
invar_tools-1.15.
|
|
190
|
-
invar_tools-1.15.
|
|
184
|
+
invar_tools-1.15.2.dist-info/METADATA,sha256=hv_0ypXK9ZqotnGr7Ndo191bIKmZw-bA4sGeXpTgmwI,28595
|
|
185
|
+
invar_tools-1.15.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
186
|
+
invar_tools-1.15.2.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
|
|
187
|
+
invar_tools-1.15.2.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
|
|
188
|
+
invar_tools-1.15.2.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
|
|
189
|
+
invar_tools-1.15.2.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
|
|
190
|
+
invar_tools-1.15.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|