invar-tools 1.15.0__py3-none-any.whl → 1.15.1__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 +411 -22
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.dist-info}/METADATA +1 -1
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.dist-info}/RECORD +9 -9
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.dist-info}/WHEEL +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.dist-info}/entry_points.txt +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.dist-info}/licenses/LICENSE +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.dist-info}/licenses/LICENSE-GPL +0 -0
- {invar_tools-1.15.0.dist-info → invar_tools-1.15.1.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()
|
|
@@ -9,14 +9,20 @@ import { Type } from "@sinclair/typebox";
|
|
|
9
9
|
import type { CustomToolFactory } from "@mariozechner/pi-coding-agent";
|
|
10
10
|
|
|
11
11
|
const factory: CustomToolFactory = (pi) => {
|
|
12
|
-
// Helper to
|
|
13
|
-
async function
|
|
12
|
+
// Helper to resolve invar command (with uvx fallback)
|
|
13
|
+
async function resolveInvarCommand(): Promise<{ command: string; args: string[] }> {
|
|
14
|
+
// Try direct invar command first
|
|
14
15
|
try {
|
|
15
16
|
const result = await pi.exec("which", ["invar"]);
|
|
16
|
-
|
|
17
|
+
if (result.exitCode === 0) {
|
|
18
|
+
return { command: "invar", args: [] };
|
|
19
|
+
}
|
|
17
20
|
} catch {
|
|
18
|
-
|
|
21
|
+
// Fall through to uvx
|
|
19
22
|
}
|
|
23
|
+
|
|
24
|
+
// Fallback to uvx invar-tools
|
|
25
|
+
return { command: "uvx", args: ["invar-tools"] };
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
// Helper to validate path/target parameters (defense-in-depth)
|
|
@@ -58,12 +64,8 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
58
64
|
})),
|
|
59
65
|
}),
|
|
60
66
|
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"];
|
|
67
|
+
const cmd = await resolveInvarCommand();
|
|
68
|
+
const args = [...cmd.args, "guard"];
|
|
67
69
|
|
|
68
70
|
// Default is --changed (check modified files)
|
|
69
71
|
if (params.changed === false) {
|
|
@@ -80,7 +82,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
80
82
|
args.push("--strict");
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
const result = await pi.exec(
|
|
85
|
+
const result = await pi.exec(cmd.command, args, { cwd: pi.cwd, signal });
|
|
84
86
|
|
|
85
87
|
if (result.killed) {
|
|
86
88
|
throw new Error("Guard verification was cancelled");
|
|
@@ -111,16 +113,13 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
111
113
|
}),
|
|
112
114
|
}),
|
|
113
115
|
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
|
-
}
|
|
116
|
+
const cmd = await resolveInvarCommand();
|
|
118
117
|
|
|
119
118
|
if (!isValidPath(params.target)) {
|
|
120
119
|
throw new Error("Invalid target path: contains unsafe characters or path traversal");
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
const result = await pi.exec(
|
|
122
|
+
const result = await pi.exec(cmd.command, [...cmd.args, "sig", params.target], {
|
|
124
123
|
cwd: pi.cwd,
|
|
125
124
|
signal,
|
|
126
125
|
});
|
|
@@ -160,16 +159,13 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
160
159
|
})),
|
|
161
160
|
}),
|
|
162
161
|
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
|
-
}
|
|
162
|
+
const cmd = await resolveInvarCommand();
|
|
167
163
|
|
|
168
164
|
if (params.path && params.path !== "." && !isValidPath(params.path)) {
|
|
169
165
|
throw new Error("Invalid path: contains unsafe characters or path traversal");
|
|
170
166
|
}
|
|
171
167
|
|
|
172
|
-
const args = ["map"];
|
|
168
|
+
const args = [...cmd.args, "map"];
|
|
173
169
|
|
|
174
170
|
if (params.path && params.path !== ".") {
|
|
175
171
|
args.push(params.path);
|
|
@@ -179,7 +175,7 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
179
175
|
args.push("--top", params.top.toString());
|
|
180
176
|
}
|
|
181
177
|
|
|
182
|
-
const result = await pi.exec(
|
|
178
|
+
const result = await pi.exec(cmd.command, args, {
|
|
183
179
|
cwd: pi.cwd,
|
|
184
180
|
signal,
|
|
185
181
|
});
|
|
@@ -201,6 +197,399 @@ const factory: CustomToolFactory = (pi) => {
|
|
|
201
197
|
};
|
|
202
198
|
},
|
|
203
199
|
},
|
|
200
|
+
|
|
201
|
+
// =========================================================================
|
|
202
|
+
// invar_doc_toc - Extract document structure (Table of Contents)
|
|
203
|
+
// =========================================================================
|
|
204
|
+
{
|
|
205
|
+
name: "invar_doc_toc",
|
|
206
|
+
label: "Invar Doc TOC",
|
|
207
|
+
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.",
|
|
208
|
+
parameters: Type.Object({
|
|
209
|
+
file: Type.String({
|
|
210
|
+
description: "Path to markdown file",
|
|
211
|
+
}),
|
|
212
|
+
depth: Type.Optional(Type.Number({
|
|
213
|
+
description: "Maximum heading depth to include (1-6)",
|
|
214
|
+
default: 6,
|
|
215
|
+
minimum: 1,
|
|
216
|
+
maximum: 6,
|
|
217
|
+
})),
|
|
218
|
+
}),
|
|
219
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
220
|
+
const cmd = await resolveInvarCommand();
|
|
221
|
+
|
|
222
|
+
if (!isValidPath(params.file)) {
|
|
223
|
+
throw new Error("Invalid file path: contains unsafe characters or path traversal");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const args = [...cmd.args, "doc", "toc", params.file];
|
|
227
|
+
|
|
228
|
+
if (params.depth && params.depth !== 6) {
|
|
229
|
+
args.push("--depth", params.depth.toString());
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const result = await pi.exec(cmd.command, args, {
|
|
233
|
+
cwd: pi.cwd,
|
|
234
|
+
signal,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
if (result.killed) {
|
|
238
|
+
throw new Error("Doc toc command was cancelled");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (result.exitCode !== 0) {
|
|
242
|
+
throw new Error(`Failed to extract TOC: ${result.stderr}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
content: [{ type: "text", text: result.stdout }],
|
|
247
|
+
details: {
|
|
248
|
+
file: params.file,
|
|
249
|
+
depth: params.depth || 6,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
// =========================================================================
|
|
256
|
+
// invar_doc_read - Read a specific section from a document
|
|
257
|
+
// =========================================================================
|
|
258
|
+
{
|
|
259
|
+
name: "invar_doc_read",
|
|
260
|
+
label: "Invar Doc Read",
|
|
261
|
+
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.",
|
|
262
|
+
parameters: Type.Object({
|
|
263
|
+
file: Type.String({
|
|
264
|
+
description: "Path to markdown file",
|
|
265
|
+
}),
|
|
266
|
+
section: Type.String({
|
|
267
|
+
description: "Section path: slug ('requirements/auth'), fuzzy ('auth'), index ('#0/#1'), or line ('@48')",
|
|
268
|
+
}),
|
|
269
|
+
children: Type.Optional(Type.Boolean({
|
|
270
|
+
description: "Include child sections in output",
|
|
271
|
+
default: true,
|
|
272
|
+
})),
|
|
273
|
+
}),
|
|
274
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
275
|
+
const cmd = await resolveInvarCommand();
|
|
276
|
+
|
|
277
|
+
if (!isValidPath(params.file) || !isValidPath(params.section)) {
|
|
278
|
+
throw new Error("Invalid file or section path: contains unsafe characters or path traversal");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const args = [...cmd.args, "doc", "read", params.file, params.section, "--json"];
|
|
282
|
+
|
|
283
|
+
if (params.children === false) {
|
|
284
|
+
args.push("--no-children");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const result = await pi.exec(cmd.command, args, {
|
|
288
|
+
cwd: pi.cwd,
|
|
289
|
+
signal,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
if (result.killed) {
|
|
293
|
+
throw new Error("Doc read command was cancelled");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (result.exitCode !== 0) {
|
|
297
|
+
throw new Error(`Failed to read section: ${result.stderr}`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
content: [{ type: "text", text: result.stdout }],
|
|
302
|
+
details: {
|
|
303
|
+
file: params.file,
|
|
304
|
+
section: params.section,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
// =========================================================================
|
|
311
|
+
// invar_doc_find - Find sections matching a pattern
|
|
312
|
+
// =========================================================================
|
|
313
|
+
{
|
|
314
|
+
name: "invar_doc_find",
|
|
315
|
+
label: "Invar Doc Find",
|
|
316
|
+
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.",
|
|
317
|
+
parameters: Type.Object({
|
|
318
|
+
file: Type.String({
|
|
319
|
+
description: "Path to markdown file",
|
|
320
|
+
}),
|
|
321
|
+
pattern: Type.String({
|
|
322
|
+
description: "Title pattern (glob-style, e.g., '*auth*')",
|
|
323
|
+
}),
|
|
324
|
+
content: Type.Optional(Type.String({
|
|
325
|
+
description: "Optional content search pattern",
|
|
326
|
+
})),
|
|
327
|
+
level: Type.Optional(Type.Number({
|
|
328
|
+
description: "Filter by heading level (1-6)",
|
|
329
|
+
minimum: 1,
|
|
330
|
+
maximum: 6,
|
|
331
|
+
})),
|
|
332
|
+
}),
|
|
333
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
334
|
+
const cmd = await resolveInvarCommand();
|
|
335
|
+
|
|
336
|
+
if (!isValidPath(params.file)) {
|
|
337
|
+
throw new Error("Invalid file path: contains unsafe characters or path traversal");
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const args = [...cmd.args, "doc", "find", params.pattern, params.file, "--json"];
|
|
341
|
+
|
|
342
|
+
if (params.content) {
|
|
343
|
+
args.push("--content", params.content);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (params.level) {
|
|
347
|
+
args.push("--level", params.level.toString());
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const result = await pi.exec(cmd.command, args, {
|
|
351
|
+
cwd: pi.cwd,
|
|
352
|
+
signal,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
if (result.killed) {
|
|
356
|
+
throw new Error("Doc find command was cancelled");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (result.exitCode !== 0) {
|
|
360
|
+
throw new Error(`Failed to find sections: ${result.stderr}`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
content: [{ type: "text", text: result.stdout }],
|
|
365
|
+
details: {
|
|
366
|
+
file: params.file,
|
|
367
|
+
pattern: params.pattern,
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
// =========================================================================
|
|
374
|
+
// invar_doc_replace - Replace a section's content
|
|
375
|
+
// =========================================================================
|
|
376
|
+
{
|
|
377
|
+
name: "invar_doc_replace",
|
|
378
|
+
label: "Invar Doc Replace",
|
|
379
|
+
description: "Replace a section's content in a markdown document. Use this INSTEAD of Edit()/Write() for section replacement.",
|
|
380
|
+
parameters: Type.Object({
|
|
381
|
+
file: Type.String({
|
|
382
|
+
description: "Path to markdown file",
|
|
383
|
+
}),
|
|
384
|
+
section: Type.String({
|
|
385
|
+
description: "Section path to replace (slug, fuzzy, index, or line anchor)",
|
|
386
|
+
}),
|
|
387
|
+
content: Type.String({
|
|
388
|
+
description: "New content to replace the section with",
|
|
389
|
+
}),
|
|
390
|
+
keep_heading: Type.Optional(Type.Boolean({
|
|
391
|
+
description: "If true, preserve the original heading line",
|
|
392
|
+
default: true,
|
|
393
|
+
})),
|
|
394
|
+
}),
|
|
395
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
396
|
+
const cmd = await resolveInvarCommand();
|
|
397
|
+
|
|
398
|
+
if (!isValidPath(params.file) || !isValidPath(params.section)) {
|
|
399
|
+
throw new Error("Invalid file or section path: contains unsafe characters or path traversal");
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Write content to temporary file to avoid shell injection
|
|
403
|
+
const fs = require("fs");
|
|
404
|
+
const path = require("path");
|
|
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 fs = require("fs");
|
|
487
|
+
const path = require("path");
|
|
488
|
+
const tmpFile = path.join(pi.cwd, `.invar-tmp-${Date.now()}.txt`);
|
|
489
|
+
|
|
490
|
+
try {
|
|
491
|
+
fs.writeFileSync(tmpFile, params.content, "utf-8");
|
|
492
|
+
|
|
493
|
+
const args = [
|
|
494
|
+
...cmd.args,
|
|
495
|
+
"doc",
|
|
496
|
+
"insert",
|
|
497
|
+
params.file,
|
|
498
|
+
params.anchor,
|
|
499
|
+
"--content",
|
|
500
|
+
tmpFile,
|
|
501
|
+
];
|
|
502
|
+
|
|
503
|
+
if (params.position && params.position !== "after") {
|
|
504
|
+
args.push("--position", params.position);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const result = await pi.exec(cmd.command, args, {
|
|
508
|
+
cwd: pi.cwd,
|
|
509
|
+
signal,
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
if (result.killed) {
|
|
513
|
+
throw new Error("Doc insert command was cancelled");
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (result.exitCode !== 0) {
|
|
517
|
+
throw new Error(`Failed to insert content: ${result.stderr}`);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return {
|
|
521
|
+
content: [{ type: "text", text: result.stdout || "Content inserted successfully" }],
|
|
522
|
+
details: {
|
|
523
|
+
file: params.file,
|
|
524
|
+
anchor: params.anchor,
|
|
525
|
+
position: params.position || "after",
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
} finally {
|
|
529
|
+
// Clean up temp file
|
|
530
|
+
try {
|
|
531
|
+
fs.unlinkSync(tmpFile);
|
|
532
|
+
} catch {
|
|
533
|
+
// Ignore cleanup errors
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
|
|
539
|
+
// =========================================================================
|
|
540
|
+
// invar_doc_delete - Delete a section from a document
|
|
541
|
+
// =========================================================================
|
|
542
|
+
{
|
|
543
|
+
name: "invar_doc_delete",
|
|
544
|
+
label: "Invar Doc Delete",
|
|
545
|
+
description: "Delete a section from a markdown document. Use this INSTEAD of Edit()/Write() for section deletion.",
|
|
546
|
+
parameters: Type.Object({
|
|
547
|
+
file: Type.String({
|
|
548
|
+
description: "Path to markdown file",
|
|
549
|
+
}),
|
|
550
|
+
section: Type.String({
|
|
551
|
+
description: "Section path to delete (slug, fuzzy, index, or line anchor)",
|
|
552
|
+
}),
|
|
553
|
+
children: Type.Optional(Type.Boolean({
|
|
554
|
+
description: "Include child sections in deletion",
|
|
555
|
+
default: true,
|
|
556
|
+
})),
|
|
557
|
+
}),
|
|
558
|
+
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
559
|
+
const cmd = await resolveInvarCommand();
|
|
560
|
+
|
|
561
|
+
if (!isValidPath(params.file) || !isValidPath(params.section)) {
|
|
562
|
+
throw new Error("Invalid file or section path: contains unsafe characters or path traversal");
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const args = [...cmd.args, "doc", "delete", params.file, params.section];
|
|
566
|
+
|
|
567
|
+
if (params.children === false) {
|
|
568
|
+
args.push("--no-children");
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const result = await pi.exec(cmd.command, args, {
|
|
572
|
+
cwd: pi.cwd,
|
|
573
|
+
signal,
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
if (result.killed) {
|
|
577
|
+
throw new Error("Doc delete command was cancelled");
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (result.exitCode !== 0) {
|
|
581
|
+
throw new Error(`Failed to delete section: ${result.stderr}`);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return {
|
|
585
|
+
content: [{ type: "text", text: result.stdout || "Section deleted successfully" }],
|
|
586
|
+
details: {
|
|
587
|
+
file: params.file,
|
|
588
|
+
section: params.section,
|
|
589
|
+
},
|
|
590
|
+
};
|
|
591
|
+
},
|
|
592
|
+
},
|
|
204
593
|
];
|
|
205
594
|
};
|
|
206
595
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: invar-tools
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.1
|
|
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=G3ST0Bd8RWl7LnUGAMJmhIeTvq6L7C18ruVU4bs_S4s,19810
|
|
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.1.dist-info/METADATA,sha256=2Pgh_tDChmFZRZpdBlLTf4JrjsX4bFFKq8XznWFTuH4,28595
|
|
185
|
+
invar_tools-1.15.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
186
|
+
invar_tools-1.15.1.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
|
|
187
|
+
invar_tools-1.15.1.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
|
|
188
|
+
invar_tools-1.15.1.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
|
|
189
|
+
invar_tools-1.15.1.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
|
|
190
|
+
invar_tools-1.15.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|