ki-manager 2.3.0.dev1__tar.gz → 2.3.0.dev2__tar.gz
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.
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/CHANGELOG.md +14 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/PKG-INFO +1 -1
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/pyproject.toml +1 -1
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/__init__.py +1 -1
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/ki_search.py +40 -3
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/server.py +107 -18
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/tools/facade.py +20 -4
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/.gitignore +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/LICENSE +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/README.md +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/cli.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/add_ki_to_config.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/analyze_module.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/audit_coverage.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/finalize_ki_scaffolds.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/find_unmapped_files.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/generate_dir_index.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/generate_ki_scaffolds.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/ki_dependency_analyzer.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/ki_graph_visualize.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/ki_utils.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/knowledge_engine.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/sync_agents_md.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/tools/__init__.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/tools/scaffold.py +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/workflows/create-adr.md +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/workflows/expand-knowledge.md +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/workflows/scaffold-knowledge.md +0 -0
- {ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/workflows/sync-knowledge.md +0 -0
|
@@ -9,6 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [2.3.0.dev2] — 2026-10-06
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- `ki_search` output summarization & pagination: compact Markdown list formatting by default (saving up to 60% of context tokens and preventing MCP client disk dumping), reduced default result limit from 10 to 5, and added `offset` parameter for seamless result pagination.
|
|
16
|
+
- `ki_search` format option: added `format: "markdown"|"json"` allowing clients to choose between compact human/LLM-readable lists or raw JSON.
|
|
17
|
+
- `ki_read` and `read_know_file` character offset: added optional `offset` parameter enabling targeted reading from specific character positions without requiring repeated full reads.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `ki_read` path resolution: resilient cascade resolving paths relative to knowledge root (`.ki-base` by default), project root, subfolder prefixes, or filename basenames across KI and ADR documents.
|
|
21
|
+
- `ki_instructions` tool schema: aligned document list with active workflows (`scaffold-knowledge`, `expand-knowledge`, `sync-knowledge`, `create-adr`), removing deprecated `update-knowledge`.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Fixed `KeyError: 'know_root'` in `ki_status` tool when checking active project status.
|
|
25
|
+
|
|
12
26
|
## [2.3.0.dev1] — 2026-10-05
|
|
13
27
|
|
|
14
28
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ki-manager
|
|
3
|
-
Version: 2.3.0.
|
|
3
|
+
Version: 2.3.0.dev2
|
|
4
4
|
Summary: Knowledge Item (KI) management MCP server for AI-assisted development
|
|
5
5
|
Project-URL: Homepage, https://github.com/Laeryid/KI-base
|
|
6
6
|
Project-URL: Repository, https://github.com/Laeryid/KI-base
|
|
@@ -196,7 +196,8 @@ def search_knowledge(
|
|
|
196
196
|
query: str,
|
|
197
197
|
project_root: Optional[str] = None,
|
|
198
198
|
scope: str = "all",
|
|
199
|
-
limit: int =
|
|
199
|
+
limit: int = 5,
|
|
200
|
+
offset: int = 0,
|
|
200
201
|
k1: float = 1.5,
|
|
201
202
|
b: float = 0.75,
|
|
202
203
|
) -> Dict[str, Any]:
|
|
@@ -206,7 +207,8 @@ def search_knowledge(
|
|
|
206
207
|
:param query: Search string (e.g. "workspace detection" or "управление зависимостями")
|
|
207
208
|
:param project_root: Root path of the project. If None, resolved via ki_utils.
|
|
208
209
|
:param scope: "all", "ki", or "adr".
|
|
209
|
-
:param limit: Max number of results to return.
|
|
210
|
+
:param limit: Max number of results to return (default: 5).
|
|
211
|
+
:param offset: Offset index for pagination (default: 0).
|
|
210
212
|
:param k1: BM25 k1 parameter.
|
|
211
213
|
:param b: BM25 b parameter.
|
|
212
214
|
"""
|
|
@@ -296,10 +298,45 @@ def search_knowledge(
|
|
|
296
298
|
})
|
|
297
299
|
|
|
298
300
|
scored_results.sort(key=lambda x: x["score"], reverse=True)
|
|
299
|
-
|
|
301
|
+
safe_offset = max(0, offset)
|
|
302
|
+
final_results = scored_results[safe_offset : safe_offset + limit]
|
|
300
303
|
|
|
301
304
|
return {
|
|
302
305
|
"query": query,
|
|
303
306
|
"total": len(scored_results),
|
|
307
|
+
"offset": safe_offset,
|
|
308
|
+
"limit": limit,
|
|
304
309
|
"results": final_results,
|
|
305
310
|
}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def format_search_markdown(search_dict: Dict[str, Any]) -> str:
|
|
314
|
+
"""Formats search results into a clean, compact Markdown summary."""
|
|
315
|
+
query = search_dict.get("query", "")
|
|
316
|
+
total = search_dict.get("total", 0)
|
|
317
|
+
results = search_dict.get("results", [])
|
|
318
|
+
offset = search_dict.get("offset", 0)
|
|
319
|
+
limit = search_dict.get("limit", 5)
|
|
320
|
+
|
|
321
|
+
if total == 0 or not results:
|
|
322
|
+
return f'No documentation matching "{query}" found.'
|
|
323
|
+
|
|
324
|
+
start_idx = offset + 1
|
|
325
|
+
end_idx = offset + len(results)
|
|
326
|
+
out = [f'Found {total} result(s) for "{query}" (showing {start_idx}-{end_idx}):\n']
|
|
327
|
+
|
|
328
|
+
for i, r in enumerate(results, start=start_idx):
|
|
329
|
+
doc_type = r.get("type", "ki").upper()
|
|
330
|
+
title = r.get("title", "")
|
|
331
|
+
path = r.get("path", "")
|
|
332
|
+
score = r.get("score", 0.0)
|
|
333
|
+
snippet = r.get("snippet", "").strip()
|
|
334
|
+
|
|
335
|
+
out.append(f"{i}. [{doc_type}] **{title}** (`{path}`, score: {score})")
|
|
336
|
+
if snippet:
|
|
337
|
+
out.append(f" > {snippet}")
|
|
338
|
+
|
|
339
|
+
if end_idx < total:
|
|
340
|
+
out.append(f"\n*Showing {end_idx} of {total} results. Call ki_search(query='{query}', offset={end_idx}) to view more.*")
|
|
341
|
+
|
|
342
|
+
return "\n".join(out)
|
|
@@ -204,8 +204,8 @@ MCP_TOOLS = [
|
|
|
204
204
|
"- 'knowledge-items' \u2014 table of registered KI files\n"
|
|
205
205
|
"- 'create-adr' \u2014 workflow: document architectural decisions\n"
|
|
206
206
|
"- 'expand-knowledge' \u2014 workflow: deep enrichment of KI files\n"
|
|
207
|
+
"- 'scaffold-knowledge' \u2014 workflow: bulk scaffold of uncovered modules\n"
|
|
207
208
|
"- 'sync-knowledge' \u2014 workflow: sync KI after code changes\n"
|
|
208
|
-
"- 'update-knowledge' \u2014 workflow: update KI files\n"
|
|
209
209
|
"Call this before starting any documentation workflow task."
|
|
210
210
|
),
|
|
211
211
|
"inputSchema": {
|
|
@@ -679,7 +679,11 @@ MCP_TOOLS = [
|
|
|
679
679
|
),
|
|
680
680
|
"inputSchema": {
|
|
681
681
|
"type": "object",
|
|
682
|
-
"properties": {
|
|
682
|
+
"properties": {
|
|
683
|
+
"rel_path": {"type": "string", "description": "Path relative to knowledge root/"},
|
|
684
|
+
"max_chars": {"type": "integer", "description": "Optional maximum number of characters to return"},
|
|
685
|
+
"offset": {"type": "integer", "default": 0, "description": "Optional character offset to start reading from"},
|
|
686
|
+
},
|
|
683
687
|
"required": ["rel_path"],
|
|
684
688
|
},
|
|
685
689
|
"annotations": {
|
|
@@ -1198,35 +1202,76 @@ def tool_read_file(args: dict) -> Any:
|
|
|
1198
1202
|
jail = get_jail_dir()
|
|
1199
1203
|
|
|
1200
1204
|
target = None
|
|
1201
|
-
|
|
1205
|
+
norm = ki_utils.normalize_path(rel_path, make_absolute=False)
|
|
1206
|
+
base_name = os.path.basename(norm)
|
|
1207
|
+
|
|
1208
|
+
# 1. Try resolving within jail (knowledge root from config, default .ki-base)
|
|
1202
1209
|
if jail:
|
|
1210
|
+
# 1a. Direct path inside jail
|
|
1203
1211
|
try:
|
|
1204
|
-
cand = validate_path(
|
|
1205
|
-
if os.path.exists(cand):
|
|
1212
|
+
cand = validate_path(norm)
|
|
1213
|
+
if os.path.exists(cand) and os.path.isfile(cand):
|
|
1206
1214
|
target = cand
|
|
1207
1215
|
except Exception:
|
|
1208
1216
|
target = None
|
|
1209
1217
|
|
|
1218
|
+
# 1b. Try inside jail/knowledge/ (standard structure: <jail>/knowledge/<file>)
|
|
1219
|
+
if not target:
|
|
1220
|
+
try:
|
|
1221
|
+
cand = validate_path(os.path.join("knowledge", norm))
|
|
1222
|
+
if os.path.exists(cand) and os.path.isfile(cand):
|
|
1223
|
+
target = cand
|
|
1224
|
+
except Exception:
|
|
1225
|
+
target = None
|
|
1226
|
+
|
|
1227
|
+
# 1c. If rel_path starts with the knowledge_root folder name itself (e.g. '.ki-base/...' or 'knowledge/...'),
|
|
1228
|
+
# strip the prefix and resolve inside jail
|
|
1229
|
+
if not target and project_root:
|
|
1230
|
+
rel_to_proj = os.path.relpath(jail, project_root).replace("\\", "/")
|
|
1231
|
+
if norm.startswith(rel_to_proj + "/"):
|
|
1232
|
+
sub_path = norm[len(rel_to_proj) + 1:]
|
|
1233
|
+
try:
|
|
1234
|
+
cand = validate_path(sub_path)
|
|
1235
|
+
if os.path.exists(cand) and os.path.isfile(cand):
|
|
1236
|
+
target = cand
|
|
1237
|
+
except Exception:
|
|
1238
|
+
pass
|
|
1239
|
+
if not target:
|
|
1240
|
+
try:
|
|
1241
|
+
cand = validate_path(os.path.join("knowledge", sub_path))
|
|
1242
|
+
if os.path.exists(cand) and os.path.isfile(cand):
|
|
1243
|
+
target = cand
|
|
1244
|
+
except Exception:
|
|
1245
|
+
pass
|
|
1246
|
+
|
|
1210
1247
|
# 2. Try resolving ADR or path relative to project_root
|
|
1211
1248
|
if not target and project_root:
|
|
1212
|
-
norm = ki_utils.normalize_path(rel_path, make_absolute=False)
|
|
1213
1249
|
candidates = ki_utils.get_decisions_dirs(project_root, jail)
|
|
1214
1250
|
# Check by basename in decisions dirs
|
|
1215
1251
|
for d in candidates:
|
|
1216
|
-
cand_p = os.path.abspath(os.path.join(d,
|
|
1217
|
-
if os.path.exists(cand_p) and cand_p.endswith(".md"):
|
|
1252
|
+
cand_p = os.path.abspath(os.path.join(d, base_name))
|
|
1253
|
+
if os.path.exists(cand_p) and cand_p.endswith(".md") and os.path.isfile(cand_p):
|
|
1218
1254
|
target = cand_p
|
|
1219
1255
|
break
|
|
1220
1256
|
if not target:
|
|
1221
1257
|
# Check relative to project root, ensuring it is within decisions or jail
|
|
1222
1258
|
cand_p = os.path.abspath(os.path.join(project_root, norm))
|
|
1223
|
-
if os.path.exists(cand_p) and cand_p.endswith(".md"):
|
|
1259
|
+
if os.path.exists(cand_p) and cand_p.endswith(".md") and os.path.isfile(cand_p):
|
|
1224
1260
|
valid_prefixes = candidates + ([jail] if jail else [])
|
|
1225
1261
|
for vp in valid_prefixes:
|
|
1226
1262
|
if os.path.normcase(cand_p).startswith(os.path.normcase(vp)):
|
|
1227
1263
|
target = cand_p
|
|
1228
1264
|
break
|
|
1229
1265
|
|
|
1266
|
+
# 3. Fallback: Search by basename in jail (knowledge root) and its subfolders
|
|
1267
|
+
if not target and jail and os.path.exists(jail):
|
|
1268
|
+
for root, _, files in os.walk(jail):
|
|
1269
|
+
if base_name in files:
|
|
1270
|
+
cand_p = os.path.abspath(os.path.join(root, base_name))
|
|
1271
|
+
if cand_p.endswith(".md") and os.path.isfile(cand_p):
|
|
1272
|
+
target = cand_p
|
|
1273
|
+
break
|
|
1274
|
+
|
|
1230
1275
|
if not target or not os.path.exists(target):
|
|
1231
1276
|
return f"File not found: '{rel_path}'."
|
|
1232
1277
|
|
|
@@ -1243,14 +1288,31 @@ def tool_read_file(args: dict) -> Any:
|
|
|
1243
1288
|
return f"Section '{section}' not found in '{rel_path}'."
|
|
1244
1289
|
content = sec_content
|
|
1245
1290
|
|
|
1291
|
+
offset = 0
|
|
1292
|
+
if args.get("offset") is not None:
|
|
1293
|
+
try:
|
|
1294
|
+
offset = max(0, int(args["offset"]))
|
|
1295
|
+
except (ValueError, TypeError):
|
|
1296
|
+
offset = 0
|
|
1297
|
+
|
|
1246
1298
|
max_chars = args.get("max_chars")
|
|
1247
1299
|
if max_chars is not None:
|
|
1248
1300
|
try:
|
|
1249
1301
|
mc = int(max_chars)
|
|
1250
|
-
if mc > 0
|
|
1251
|
-
|
|
1302
|
+
if mc > 0:
|
|
1303
|
+
total_len = len(content)
|
|
1304
|
+
chunk = content[offset : offset + mc]
|
|
1305
|
+
if offset + mc < total_len:
|
|
1306
|
+
content = chunk + f"\n\n... [truncated to {mc} characters, offset {offset} of {total_len}]"
|
|
1307
|
+
else:
|
|
1308
|
+
content = chunk
|
|
1309
|
+
elif offset > 0:
|
|
1310
|
+
content = content[offset:]
|
|
1252
1311
|
except (ValueError, TypeError):
|
|
1253
|
-
|
|
1312
|
+
if offset > 0:
|
|
1313
|
+
content = content[offset:]
|
|
1314
|
+
elif offset > 0:
|
|
1315
|
+
content = content[offset:]
|
|
1254
1316
|
|
|
1255
1317
|
return content
|
|
1256
1318
|
|
|
@@ -1302,8 +1364,10 @@ def handle_tool_call(name: str, args: dict) -> Any:
|
|
|
1302
1364
|
return "\n".join(f"- {v['name']}: {k}" for k, v in reg["projects"].items())
|
|
1303
1365
|
if name == "ki_status":
|
|
1304
1366
|
match = ki_utils.find_project_by_cwd(args.get("path"))
|
|
1305
|
-
|
|
1306
|
-
|
|
1367
|
+
if match:
|
|
1368
|
+
loc = get_jail_dir() or match.get("workspace", "")
|
|
1369
|
+
return f"Active: {match['name']} at {loc}"
|
|
1370
|
+
return "No project active for current workspace."
|
|
1307
1371
|
if name == "ki_prune_registry":
|
|
1308
1372
|
reg = ki_utils.load_registry()
|
|
1309
1373
|
before = len(reg["projects"])
|
|
@@ -1401,7 +1465,28 @@ def handle_tool_call(name: str, args: dict) -> Any:
|
|
|
1401
1465
|
# ─── File Ops ───
|
|
1402
1466
|
if name == "read_know_file":
|
|
1403
1467
|
with open(validate_path(args["rel_path"]), "r", encoding="utf-8") as f:
|
|
1404
|
-
|
|
1468
|
+
content = f.read()
|
|
1469
|
+
offset = 0
|
|
1470
|
+
if args.get("offset") is not None:
|
|
1471
|
+
try:
|
|
1472
|
+
offset = max(0, int(args["offset"]))
|
|
1473
|
+
except (ValueError, TypeError):
|
|
1474
|
+
offset = 0
|
|
1475
|
+
max_chars = args.get("max_chars")
|
|
1476
|
+
if max_chars is not None:
|
|
1477
|
+
try:
|
|
1478
|
+
mc = int(max_chars)
|
|
1479
|
+
if mc > 0:
|
|
1480
|
+
total_len = len(content)
|
|
1481
|
+
chunk = content[offset : offset + mc]
|
|
1482
|
+
if offset + mc < total_len:
|
|
1483
|
+
return chunk + f"\n\n... [truncated to {mc} characters, offset {offset} of {total_len}]"
|
|
1484
|
+
return chunk
|
|
1485
|
+
except (ValueError, TypeError):
|
|
1486
|
+
pass
|
|
1487
|
+
if offset > 0:
|
|
1488
|
+
return content[offset:]
|
|
1489
|
+
return content
|
|
1405
1490
|
if name == "write_know_file":
|
|
1406
1491
|
p = validate_path(args["rel_path"], is_write=True)
|
|
1407
1492
|
os.makedirs(os.path.dirname(p), exist_ok=True)
|
|
@@ -1454,9 +1539,13 @@ def handle_tool_call(name: str, args: dict) -> Any:
|
|
|
1454
1539
|
if name == "ki_search":
|
|
1455
1540
|
query = args.get("query", "").strip()
|
|
1456
1541
|
scope = args.get("scope", "all")
|
|
1457
|
-
limit = int(args.get("limit",
|
|
1458
|
-
|
|
1459
|
-
|
|
1542
|
+
limit = int(args.get("limit", 5))
|
|
1543
|
+
offset = int(args.get("offset", 0))
|
|
1544
|
+
fmt = args.get("format", "markdown")
|
|
1545
|
+
res = ki_search.search_knowledge(query, project_root=get_project_root(), scope=scope, limit=limit, offset=offset)
|
|
1546
|
+
if fmt == "json":
|
|
1547
|
+
return json.dumps(res, ensure_ascii=False, indent=2)
|
|
1548
|
+
return ki_search.format_search_markdown(res)
|
|
1460
1549
|
|
|
1461
1550
|
if name == "ki_read":
|
|
1462
1551
|
return tool_read_file(args)
|
|
@@ -87,8 +87,19 @@ KI_SEARCH_TOOL = {
|
|
|
87
87
|
},
|
|
88
88
|
"limit": {
|
|
89
89
|
"type": "integer",
|
|
90
|
-
"default":
|
|
91
|
-
"description": "Maximum number of results to return (default:
|
|
90
|
+
"default": 5,
|
|
91
|
+
"description": "Maximum number of results to return (default: 5).",
|
|
92
|
+
},
|
|
93
|
+
"offset": {
|
|
94
|
+
"type": "integer",
|
|
95
|
+
"default": 0,
|
|
96
|
+
"description": "Result offset for pagination (default: 0).",
|
|
97
|
+
},
|
|
98
|
+
"format": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"enum": ["markdown", "json"],
|
|
101
|
+
"default": "markdown",
|
|
102
|
+
"description": "Output format: 'markdown' (compact list, default) or 'json'.",
|
|
92
103
|
},
|
|
93
104
|
},
|
|
94
105
|
"required": ["query"],
|
|
@@ -105,14 +116,14 @@ KI_READ_TOOL = {
|
|
|
105
116
|
"name": "ki_read",
|
|
106
117
|
"description": (
|
|
107
118
|
"Read a Knowledge Item (KI) or ADR markdown file. "
|
|
108
|
-
"Supports optional section filtering (by markdown header)
|
|
119
|
+
"Supports optional section filtering (by markdown header), character limits, and offset."
|
|
109
120
|
),
|
|
110
121
|
"inputSchema": {
|
|
111
122
|
"type": "object",
|
|
112
123
|
"properties": {
|
|
113
124
|
"rel_path": {
|
|
114
125
|
"type": "string",
|
|
115
|
-
"description": "
|
|
126
|
+
"description": "Path or filename of the Knowledge Item or ADR (e.g. 'KI_architecture.md', 'knowledge/KI_architecture.md', or '001_some.md').",
|
|
116
127
|
},
|
|
117
128
|
"section": {
|
|
118
129
|
"type": "string",
|
|
@@ -122,6 +133,11 @@ KI_READ_TOOL = {
|
|
|
122
133
|
"type": "integer",
|
|
123
134
|
"description": "Optional maximum number of characters to return (truncates if exceeded).",
|
|
124
135
|
},
|
|
136
|
+
"offset": {
|
|
137
|
+
"type": "integer",
|
|
138
|
+
"default": 0,
|
|
139
|
+
"description": "Optional character offset to start reading from (default: 0).",
|
|
140
|
+
},
|
|
125
141
|
},
|
|
126
142
|
"required": ["rel_path"],
|
|
127
143
|
},
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/finalize_ki_scaffolds.py
RENAMED
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/find_unmapped_files.py
RENAMED
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/generate_dir_index.py
RENAMED
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/generate_ki_scaffolds.py
RENAMED
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/ki_dependency_analyzer.py
RENAMED
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/scripts/ki_graph_visualize.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/workflows/expand-knowledge.md
RENAMED
|
File without changes
|
{ki_manager-2.3.0.dev1 → ki_manager-2.3.0.dev2}/src/ki_manager/workflows/scaffold-knowledge.md
RENAMED
|
File without changes
|
|
File without changes
|