context-loader 1.0.0__tar.gz → 1.1.0__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.
- {context_loader-1.0.0 → context_loader-1.1.0}/PKG-INFO +8 -5
- {context_loader-1.0.0 → context_loader-1.1.0}/README.md +7 -4
- {context_loader-1.0.0 → context_loader-1.1.0}/context_loader/__init__.py +1 -1
- {context_loader-1.0.0 → context_loader-1.1.0}/context_loader/application.py +117 -1
- {context_loader-1.0.0 → context_loader-1.1.0}/context_loader/render.py +25 -14
- {context_loader-1.0.0 → context_loader-1.1.0}/pyproject.toml +1 -1
- {context_loader-1.0.0 → context_loader-1.1.0}/pyproject.toml.orig +1 -1
- {context_loader-1.0.0 → context_loader-1.1.0}/tool_cli_contract.json +1 -1
- {context_loader-1.0.0 → context_loader-1.1.0}/LICENSE +0 -0
- {context_loader-1.0.0 → context_loader-1.1.0}/context_loader/cli.py +0 -0
- {context_loader-1.0.0 → context_loader-1.1.0}/context_loader/collect.py +0 -0
- {context_loader-1.0.0 → context_loader-1.1.0}/context_loader/git.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: context-loader
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Render deterministic local Git context for any executor
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -240,7 +240,7 @@ project-context --repo /path/to/repo --format json
|
|
|
240
240
|
|
|
241
241
|
## Install
|
|
242
242
|
|
|
243
|
-
Source version: `1.
|
|
243
|
+
Source version: `1.1.0`. Install its matching published release or an exact source commit.
|
|
244
244
|
|
|
245
245
|
Install via `uv`:
|
|
246
246
|
|
|
@@ -254,7 +254,7 @@ Install via `pip`:
|
|
|
254
254
|
pip install context-loader
|
|
255
255
|
```
|
|
256
256
|
|
|
257
|
-
For development or source-based installs tracking current repository (`1.
|
|
257
|
+
For development or source-based installs tracking current repository (`1.1.0`):
|
|
258
258
|
|
|
259
259
|
```bash
|
|
260
260
|
uv tool install git+https://github.com/xuanheng-tech/context-loader.git
|
|
@@ -345,7 +345,7 @@ Keys are serialized in sorted order with `ensure_ascii=False`. The declared cont
|
|
|
345
345
|
"schema_version": 1,
|
|
346
346
|
"tool": {
|
|
347
347
|
"name": "context-loader",
|
|
348
|
-
"version": "1.
|
|
348
|
+
"version": "1.1.0"
|
|
349
349
|
},
|
|
350
350
|
"repository": {
|
|
351
351
|
"requested_path": "/canonical/requested/path",
|
|
@@ -374,6 +374,7 @@ Keys are serialized in sorted order with `ensure_ascii=False`. The declared cont
|
|
|
374
374
|
],
|
|
375
375
|
"context": "the same assembled Markdown context",
|
|
376
376
|
"context_sha256": "sha256-hex",
|
|
377
|
+
"statuses": [],
|
|
377
378
|
"warnings": []
|
|
378
379
|
}
|
|
379
380
|
```
|
|
@@ -384,12 +385,14 @@ assembly order, after the existing newline normalization and truncation rules. `
|
|
|
384
385
|
`repository` from `global`; version 1.0.0's fixed root-file selection currently emits only
|
|
385
386
|
`repository` sources and does not add any global-file discovery.
|
|
386
387
|
|
|
388
|
+
`statuses` lists machine-readable collection and render conditions that previously appeared only inside `context` Markdown: skipped or absent sources, truncated sources, unreadable directory-tree entries, sections omitted under the global output budget, and truncated working-tree or declared-command listings. Each entry has stable `code`, `subject_kind`, and `subject` fields. `sources`, `context`, and `schema_version` remain unchanged; callers can ignore `statuses` safely.
|
|
389
|
+
|
|
387
390
|
The optional `selection` object is present only on a rendered `AGENTS.md` source. Its section entries
|
|
388
391
|
contain heading, heading level, and fixed selection reasons; it never contains the original focus or
|
|
389
392
|
target path. Existing source fields and schema version 1 remain unchanged.
|
|
390
393
|
|
|
391
394
|
The JSON schema version and package version are independent: `schema_version` is currently the
|
|
392
|
-
integer `1`, while `tool.version` is `1.
|
|
395
|
+
integer `1`, while `tool.version` is `1.1.0`. Callers must depend only on fields declared above.
|
|
393
396
|
The document contains no generated time or random identifier, so unchanged input produces identical
|
|
394
397
|
JSON bytes. On failure, stdout remains empty and stderr contains only a short diagnostic.
|
|
395
398
|
|
|
@@ -29,7 +29,7 @@ project-context --repo /path/to/repo --format json
|
|
|
29
29
|
|
|
30
30
|
## Install
|
|
31
31
|
|
|
32
|
-
Source version: `1.
|
|
32
|
+
Source version: `1.1.0`. Install its matching published release or an exact source commit.
|
|
33
33
|
|
|
34
34
|
Install via `uv`:
|
|
35
35
|
|
|
@@ -43,7 +43,7 @@ Install via `pip`:
|
|
|
43
43
|
pip install context-loader
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
For development or source-based installs tracking current repository (`1.
|
|
46
|
+
For development or source-based installs tracking current repository (`1.1.0`):
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
49
|
uv tool install git+https://github.com/xuanheng-tech/context-loader.git
|
|
@@ -134,7 +134,7 @@ Keys are serialized in sorted order with `ensure_ascii=False`. The declared cont
|
|
|
134
134
|
"schema_version": 1,
|
|
135
135
|
"tool": {
|
|
136
136
|
"name": "context-loader",
|
|
137
|
-
"version": "1.
|
|
137
|
+
"version": "1.1.0"
|
|
138
138
|
},
|
|
139
139
|
"repository": {
|
|
140
140
|
"requested_path": "/canonical/requested/path",
|
|
@@ -163,6 +163,7 @@ Keys are serialized in sorted order with `ensure_ascii=False`. The declared cont
|
|
|
163
163
|
],
|
|
164
164
|
"context": "the same assembled Markdown context",
|
|
165
165
|
"context_sha256": "sha256-hex",
|
|
166
|
+
"statuses": [],
|
|
166
167
|
"warnings": []
|
|
167
168
|
}
|
|
168
169
|
```
|
|
@@ -173,12 +174,14 @@ assembly order, after the existing newline normalization and truncation rules. `
|
|
|
173
174
|
`repository` from `global`; version 1.0.0's fixed root-file selection currently emits only
|
|
174
175
|
`repository` sources and does not add any global-file discovery.
|
|
175
176
|
|
|
177
|
+
`statuses` lists machine-readable collection and render conditions that previously appeared only inside `context` Markdown: skipped or absent sources, truncated sources, unreadable directory-tree entries, sections omitted under the global output budget, and truncated working-tree or declared-command listings. Each entry has stable `code`, `subject_kind`, and `subject` fields. `sources`, `context`, and `schema_version` remain unchanged; callers can ignore `statuses` safely.
|
|
178
|
+
|
|
176
179
|
The optional `selection` object is present only on a rendered `AGENTS.md` source. Its section entries
|
|
177
180
|
contain heading, heading level, and fixed selection reasons; it never contains the original focus or
|
|
178
181
|
target path. Existing source fields and schema version 1 remain unchanged.
|
|
179
182
|
|
|
180
183
|
The JSON schema version and package version are independent: `schema_version` is currently the
|
|
181
|
-
integer `1`, while `tool.version` is `1.
|
|
184
|
+
integer `1`, while `tool.version` is `1.1.0`. Callers must depend only on fields declared above.
|
|
182
185
|
The document contains no generated time or random identifier, so unchanged input produces identical
|
|
183
186
|
JSON bytes. On failure, stdout remains empty and stderr contains only a short diagnostic.
|
|
184
187
|
|
|
@@ -10,9 +10,16 @@ from pathlib import Path
|
|
|
10
10
|
|
|
11
11
|
from . import __version__
|
|
12
12
|
from .collect import (
|
|
13
|
+
NOT_PRESENT,
|
|
14
|
+
SKIPPED_ENCODING,
|
|
15
|
+
SKIPPED_NOT_REGULAR,
|
|
16
|
+
SKIPPED_SYMLINK,
|
|
17
|
+
SKIPPED_UNREADABLE,
|
|
18
|
+
TRUNCATION_MARKER,
|
|
13
19
|
AgentsSectionAuditEntry,
|
|
14
20
|
AgentsSelectionAudit,
|
|
15
21
|
AgentsSelectionInputError,
|
|
22
|
+
CollectedFile,
|
|
16
23
|
ProjectContext,
|
|
17
24
|
collect_project_context,
|
|
18
25
|
)
|
|
@@ -22,6 +29,14 @@ from .render import render_markdown_with_details, rendered_source_contents
|
|
|
22
29
|
JSON_SCHEMA_VERSION = 1
|
|
23
30
|
TOOL_NAME = "context-loader"
|
|
24
31
|
|
|
32
|
+
_STATUS_CODE_BY_MESSAGE = {
|
|
33
|
+
NOT_PRESENT: "not_present",
|
|
34
|
+
SKIPPED_SYMLINK: "skipped_symlink",
|
|
35
|
+
SKIPPED_NOT_REGULAR: "skipped_not_regular",
|
|
36
|
+
SKIPPED_ENCODING: "skipped_encoding",
|
|
37
|
+
SKIPPED_UNREADABLE: "skipped_unreadable",
|
|
38
|
+
}
|
|
39
|
+
|
|
25
40
|
|
|
26
41
|
@dataclass(frozen=True, slots=True)
|
|
27
42
|
class ToolIdentity:
|
|
@@ -46,6 +61,15 @@ class ProjectContextSource:
|
|
|
46
61
|
selection: AgentsSelectionAudit | None = None
|
|
47
62
|
|
|
48
63
|
|
|
64
|
+
@dataclass(frozen=True, slots=True)
|
|
65
|
+
class ContextStatus:
|
|
66
|
+
"""One machine-readable skipped, omitted, truncated, or unreadable condition."""
|
|
67
|
+
|
|
68
|
+
code: str
|
|
69
|
+
subject_kind: str
|
|
70
|
+
subject: str
|
|
71
|
+
|
|
72
|
+
|
|
49
73
|
@dataclass(frozen=True, slots=True)
|
|
50
74
|
class ProjectContextResult:
|
|
51
75
|
schema_version: int
|
|
@@ -55,6 +79,7 @@ class ProjectContextResult:
|
|
|
55
79
|
context: str
|
|
56
80
|
context_sha256: str
|
|
57
81
|
warnings: tuple[str, ...]
|
|
82
|
+
statuses: tuple[ContextStatus, ...]
|
|
58
83
|
|
|
59
84
|
|
|
60
85
|
def _text_sha256(content: str) -> str:
|
|
@@ -102,6 +127,79 @@ def _sources(
|
|
|
102
127
|
return tuple(sources)
|
|
103
128
|
|
|
104
129
|
|
|
130
|
+
def _status(code: str, subject_kind: str, subject: str) -> ContextStatus:
|
|
131
|
+
return ContextStatus(code=code, subject_kind=subject_kind, subject=subject)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _statuses_for_source(source: CollectedFile) -> list[ContextStatus]:
|
|
135
|
+
if source.status is not None:
|
|
136
|
+
code = _STATUS_CODE_BY_MESSAGE.get(source.status, "skipped_unreadable")
|
|
137
|
+
return [_status(code, "source", source.name)]
|
|
138
|
+
statuses: list[ContextStatus] = []
|
|
139
|
+
if source.truncated or (source.selection is not None and source.selection.truncated):
|
|
140
|
+
statuses.append(_status("truncated", "source", source.name))
|
|
141
|
+
if source.selection is not None:
|
|
142
|
+
if source.selection.parse_fallback:
|
|
143
|
+
statuses.append(_status("parse_fallback", "source", source.name))
|
|
144
|
+
if source.selection.source_scan_truncated:
|
|
145
|
+
statuses.append(_status("source_scan_truncated", "source", source.name))
|
|
146
|
+
if source.selection.index_truncated:
|
|
147
|
+
statuses.append(_status("index_truncated", "source", source.name))
|
|
148
|
+
return statuses
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _build_statuses(
|
|
152
|
+
project: ProjectContext,
|
|
153
|
+
*,
|
|
154
|
+
omitted_sections: tuple[str, ...],
|
|
155
|
+
changes_truncated: bool,
|
|
156
|
+
commands_truncated: bool,
|
|
157
|
+
rendered_sources: tuple[ProjectContextSource, ...],
|
|
158
|
+
) -> tuple[ContextStatus, ...]:
|
|
159
|
+
statuses: list[ContextStatus] = []
|
|
160
|
+
for source in (project.instructions, project.overview, *project.entry_files):
|
|
161
|
+
statuses.extend(_statuses_for_source(source))
|
|
162
|
+
|
|
163
|
+
truncated_sources = {
|
|
164
|
+
status.subject
|
|
165
|
+
for status in statuses
|
|
166
|
+
if status.subject_kind == "source" and status.code == "truncated"
|
|
167
|
+
}
|
|
168
|
+
for source in rendered_sources:
|
|
169
|
+
if TRUNCATION_MARKER not in source.content:
|
|
170
|
+
continue
|
|
171
|
+
name = source.path.name
|
|
172
|
+
if name in truncated_sources:
|
|
173
|
+
continue
|
|
174
|
+
statuses.append(_status("truncated", "source", name))
|
|
175
|
+
truncated_sources.add(name)
|
|
176
|
+
|
|
177
|
+
if commands_truncated:
|
|
178
|
+
statuses.append(_status("truncated", "commands", "Declared Commands"))
|
|
179
|
+
if changes_truncated:
|
|
180
|
+
statuses.append(_status("truncated", "changes", "Working Tree Changes"))
|
|
181
|
+
|
|
182
|
+
if project.directory_tree.truncated:
|
|
183
|
+
statuses.append(_status("truncated", "tree", "Directory Tree"))
|
|
184
|
+
for entry in project.directory_tree.entries:
|
|
185
|
+
if entry.kind == "unreadable_directory":
|
|
186
|
+
subject = entry.path if entry.path else "."
|
|
187
|
+
statuses.append(_status("unreadable", "tree_entry", subject))
|
|
188
|
+
|
|
189
|
+
for title in omitted_sections:
|
|
190
|
+
statuses.append(_status("section_omitted", "section", title))
|
|
191
|
+
|
|
192
|
+
deduped: list[ContextStatus] = []
|
|
193
|
+
seen: set[tuple[str, str, str]] = set()
|
|
194
|
+
for status in statuses:
|
|
195
|
+
key = (status.code, status.subject_kind, status.subject)
|
|
196
|
+
if key in seen:
|
|
197
|
+
continue
|
|
198
|
+
seen.add(key)
|
|
199
|
+
deduped.append(status)
|
|
200
|
+
return tuple(deduped)
|
|
201
|
+
|
|
202
|
+
|
|
105
203
|
def load_project_context(
|
|
106
204
|
repo: str | os.PathLike[str],
|
|
107
205
|
*,
|
|
@@ -120,6 +218,14 @@ def load_project_context(
|
|
|
120
218
|
raise ContextLoaderError(str(exc), exit_code=2) from None
|
|
121
219
|
rendered = render_markdown_with_details(state, project)
|
|
122
220
|
context = rendered.output.decode("utf-8")
|
|
221
|
+
sources = _sources(state.repository, project, rendered.included_sections)
|
|
222
|
+
statuses = _build_statuses(
|
|
223
|
+
project,
|
|
224
|
+
omitted_sections=rendered.omitted_sections,
|
|
225
|
+
changes_truncated=rendered.changes_truncated,
|
|
226
|
+
commands_truncated=rendered.commands_truncated,
|
|
227
|
+
rendered_sources=sources,
|
|
228
|
+
)
|
|
123
229
|
return ProjectContextResult(
|
|
124
230
|
schema_version=JSON_SCHEMA_VERSION,
|
|
125
231
|
tool=ToolIdentity(name=TOOL_NAME, version=__version__),
|
|
@@ -127,10 +233,11 @@ def load_project_context(
|
|
|
127
233
|
requested_path=location.requested_path,
|
|
128
234
|
canonical_root=location.canonical_root,
|
|
129
235
|
),
|
|
130
|
-
sources=
|
|
236
|
+
sources=sources,
|
|
131
237
|
context=context,
|
|
132
238
|
context_sha256=hashlib.sha256(rendered.output).hexdigest(),
|
|
133
239
|
warnings=(),
|
|
240
|
+
statuses=statuses,
|
|
134
241
|
)
|
|
135
242
|
|
|
136
243
|
|
|
@@ -157,6 +264,14 @@ def _selection_document(selection: AgentsSelectionAudit) -> dict[str, object]:
|
|
|
157
264
|
}
|
|
158
265
|
|
|
159
266
|
|
|
267
|
+
def _status_document(status: ContextStatus) -> dict[str, object]:
|
|
268
|
+
return {
|
|
269
|
+
"code": status.code,
|
|
270
|
+
"subject": status.subject,
|
|
271
|
+
"subject_kind": status.subject_kind,
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
160
275
|
def _source_document(source: ProjectContextSource) -> dict[str, object]:
|
|
161
276
|
document: dict[str, object] = {
|
|
162
277
|
"ordinal": source.ordinal,
|
|
@@ -184,6 +299,7 @@ def render_json(result: ProjectContextResult) -> bytes:
|
|
|
184
299
|
"canonical_root": os.fspath(result.repository.canonical_root),
|
|
185
300
|
},
|
|
186
301
|
"sources": [_source_document(source) for source in result.sources],
|
|
302
|
+
"statuses": [_status_document(status) for status in result.statuses],
|
|
187
303
|
"context": result.context,
|
|
188
304
|
"context_sha256": result.context_sha256,
|
|
189
305
|
"warnings": list(result.warnings),
|
|
@@ -34,6 +34,9 @@ GLOBAL_OMISSION = "Omitted: global output limit reached."
|
|
|
34
34
|
class MarkdownRender:
|
|
35
35
|
output: bytes
|
|
36
36
|
included_sections: tuple[str, ...]
|
|
37
|
+
omitted_sections: tuple[str, ...]
|
|
38
|
+
changes_truncated: bool
|
|
39
|
+
commands_truncated: bool
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
def _display(value: str) -> str:
|
|
@@ -173,10 +176,12 @@ def _command_line(command: DeclaredCommand) -> str:
|
|
|
173
176
|
return f"- `{invocation}` → `{_display(command.target)}`"
|
|
174
177
|
|
|
175
178
|
|
|
176
|
-
def _bounded_lines(
|
|
179
|
+
def _bounded_lines(
|
|
180
|
+
lines: list[str], limit: int, *, already_truncated: bool = False
|
|
181
|
+
) -> tuple[str, bool]:
|
|
177
182
|
complete = "\n".join(lines)
|
|
178
183
|
if not already_truncated and len(complete.encode()) <= limit:
|
|
179
|
-
return complete
|
|
184
|
+
return complete, False
|
|
180
185
|
marker_size = len(TRUNCATION_MARKER.encode())
|
|
181
186
|
budget = max(0, limit - marker_size - 1)
|
|
182
187
|
selected: list[str] = []
|
|
@@ -188,20 +193,15 @@ def _bounded_lines(lines: list[str], limit: int, *, already_truncated: bool = Fa
|
|
|
188
193
|
selected.append(line)
|
|
189
194
|
used += size
|
|
190
195
|
selected.append(TRUNCATION_MARKER)
|
|
191
|
-
return "\n".join(selected)
|
|
196
|
+
return "\n".join(selected), True
|
|
192
197
|
|
|
193
198
|
|
|
194
|
-
def _render_commands(commands: tuple[DeclaredCommand, ...]) -> str:
|
|
199
|
+
def _render_commands(commands: tuple[DeclaredCommand, ...]) -> tuple[str, bool]:
|
|
195
200
|
lines = [_command_line(command) for command in commands]
|
|
196
201
|
if not lines:
|
|
197
202
|
lines.append("No supported command declarations found.")
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
"## Declared Commands",
|
|
201
|
-
"",
|
|
202
|
-
_bounded_lines(lines, DECLARED_COMMANDS_LIMIT_BYTES),
|
|
203
|
-
)
|
|
204
|
-
)
|
|
203
|
+
body, truncated = _bounded_lines(lines, DECLARED_COMMANDS_LIMIT_BYTES)
|
|
204
|
+
return "\n".join(("## Declared Commands", "", body)), truncated
|
|
205
205
|
|
|
206
206
|
|
|
207
207
|
def _entry_body(source: CollectedFile, remaining: int) -> tuple[str | None, int]:
|
|
@@ -276,7 +276,7 @@ def _render_directory_tree(tree: DirectoryTree) -> str:
|
|
|
276
276
|
lines = [_tree_line(entry) for entry in tree.entries]
|
|
277
277
|
if not lines:
|
|
278
278
|
lines.append("No entries.")
|
|
279
|
-
body = _bounded_lines(
|
|
279
|
+
body, _truncated = _bounded_lines(
|
|
280
280
|
lines,
|
|
281
281
|
DIRECTORY_TREE_LIMIT_BYTES,
|
|
282
282
|
already_truncated=tree.truncated,
|
|
@@ -298,6 +298,8 @@ def render_markdown_with_details(state: RepositoryState, project: ProjectContext
|
|
|
298
298
|
f"- Repository: `{_display(os.fspath(state.repository))}`",
|
|
299
299
|
)
|
|
300
300
|
)
|
|
301
|
+
commands_section, commands_truncated = _render_commands(project.commands)
|
|
302
|
+
changes_truncated = _change_lines(state)[1]
|
|
301
303
|
sections: list[tuple[str, str | None]] = [
|
|
302
304
|
("Git State", _render_git_state(state)),
|
|
303
305
|
(
|
|
@@ -312,7 +314,7 @@ def render_markdown_with_details(state: RepositoryState, project: ProjectContext
|
|
|
312
314
|
"Project Overview",
|
|
313
315
|
_render_source_section("Project Overview", project.overview, README_LIMIT_BYTES),
|
|
314
316
|
),
|
|
315
|
-
("Declared Commands",
|
|
317
|
+
("Declared Commands", commands_section),
|
|
316
318
|
("Project Entry Files", _render_entry_files(project.entry_files)),
|
|
317
319
|
("Recent Commits", _render_recent_commits(state.commits)),
|
|
318
320
|
("Directory Tree", _render_directory_tree(project.directory_tree)),
|
|
@@ -320,6 +322,7 @@ def render_markdown_with_details(state: RepositoryState, project: ProjectContext
|
|
|
320
322
|
|
|
321
323
|
rendered_parts = [header.encode()]
|
|
322
324
|
included_sections: list[str] = []
|
|
325
|
+
omitted_sections: list[str] = []
|
|
323
326
|
omission_started = False
|
|
324
327
|
for index, (title, full_section) in enumerate(sections):
|
|
325
328
|
omission = _omitted_section(title).encode()
|
|
@@ -330,6 +333,7 @@ def render_markdown_with_details(state: RepositoryState, project: ProjectContext
|
|
|
330
333
|
if omission_started or full_section is None:
|
|
331
334
|
selected = omission
|
|
332
335
|
omission_started = True
|
|
336
|
+
omitted_sections.append(title)
|
|
333
337
|
else:
|
|
334
338
|
candidate = full_section.encode()
|
|
335
339
|
tentative = b"\n\n".join((*rendered_parts, candidate, *future_omissions)) + b"\n"
|
|
@@ -339,12 +343,19 @@ def render_markdown_with_details(state: RepositoryState, project: ProjectContext
|
|
|
339
343
|
else:
|
|
340
344
|
selected = omission
|
|
341
345
|
omission_started = True
|
|
346
|
+
omitted_sections.append(title)
|
|
342
347
|
rendered_parts.append(selected)
|
|
343
348
|
|
|
344
349
|
output = b"\n\n".join(rendered_parts) + b"\n"
|
|
345
350
|
if len(output) > GLOBAL_OUTPUT_LIMIT_BYTES:
|
|
346
351
|
raise RuntimeError("global context output limit could not be satisfied")
|
|
347
|
-
return MarkdownRender(
|
|
352
|
+
return MarkdownRender(
|
|
353
|
+
output=output,
|
|
354
|
+
included_sections=tuple(included_sections),
|
|
355
|
+
omitted_sections=tuple(omitted_sections),
|
|
356
|
+
changes_truncated=changes_truncated,
|
|
357
|
+
commands_truncated=commands_truncated,
|
|
358
|
+
)
|
|
348
359
|
|
|
349
360
|
|
|
350
361
|
def rendered_source_contents(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|