@blxzer/cursor-trellis 0.3.4 → 0.3.6
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/CHANGELOG.md +46 -0
- package/README.md +13 -13
- package/README.zh-CN.md +1 -1
- package/bin/cstl.js +1 -1
- package/bin/smart-search.js +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +17 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/campaign/canvas-render.d.ts +68 -0
- package/dist/commands/campaign/canvas-render.d.ts.map +1 -0
- package/dist/commands/campaign/canvas-render.js +414 -0
- package/dist/commands/campaign/canvas-render.js.map +1 -0
- package/dist/commands/campaign/compose.d.ts +15 -0
- package/dist/commands/campaign/compose.d.ts.map +1 -0
- package/dist/commands/campaign/compose.js +110 -0
- package/dist/commands/campaign/compose.js.map +1 -0
- package/dist/commands/campaign/index.d.ts +13 -0
- package/dist/commands/campaign/index.d.ts.map +1 -0
- package/dist/commands/campaign/index.js +134 -0
- package/dist/commands/campaign/index.js.map +1 -0
- package/dist/commands/campaign/kind-map.d.ts +6 -0
- package/dist/commands/campaign/kind-map.d.ts.map +1 -0
- package/dist/commands/campaign/kind-map.js +21 -0
- package/dist/commands/campaign/kind-map.js.map +1 -0
- package/dist/commands/campaign/mcp-server.d.ts +6 -0
- package/dist/commands/campaign/mcp-server.d.ts.map +1 -0
- package/dist/commands/campaign/mcp-server.js +167 -0
- package/dist/commands/campaign/mcp-server.js.map +1 -0
- package/dist/commands/campaign/render.d.ts +5 -0
- package/dist/commands/campaign/render.d.ts.map +1 -0
- package/dist/commands/campaign/render.js +103 -0
- package/dist/commands/campaign/render.js.map +1 -0
- package/dist/commands/campaign/trellis-load.d.ts +13 -0
- package/dist/commands/campaign/trellis-load.d.ts.map +1 -0
- package/dist/commands/campaign/trellis-load.js +122 -0
- package/dist/commands/campaign/trellis-load.js.map +1 -0
- package/dist/commands/campaign/types.d.ts +61 -0
- package/dist/commands/campaign/types.d.ts.map +1 -0
- package/dist/commands/campaign/types.js +3 -0
- package/dist/commands/campaign/types.js.map +1 -0
- package/dist/commands/goal/index.d.ts +3 -0
- package/dist/commands/goal/index.d.ts.map +1 -0
- package/dist/commands/goal/index.js +159 -0
- package/dist/commands/goal/index.js.map +1 -0
- package/dist/commands/goal/review.d.ts +6 -0
- package/dist/commands/goal/review.d.ts.map +1 -0
- package/dist/commands/goal/review.js +28 -0
- package/dist/commands/goal/review.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/rpc/client.d.ts +51 -0
- package/dist/commands/rpc/client.d.ts.map +1 -0
- package/dist/commands/rpc/client.js +147 -0
- package/dist/commands/rpc/client.js.map +1 -0
- package/dist/commands/rpc/index.d.ts +10 -0
- package/dist/commands/rpc/index.d.ts.map +1 -0
- package/dist/commands/rpc/index.js +157 -0
- package/dist/commands/rpc/index.js.map +1 -0
- package/dist/commands/rpc/serve.d.ts +23 -0
- package/dist/commands/rpc/serve.d.ts.map +1 -0
- package/dist/commands/rpc/serve.js +60 -0
- package/dist/commands/rpc/serve.js.map +1 -0
- package/dist/commands/rpc/smoke.d.ts +16 -0
- package/dist/commands/rpc/smoke.d.ts.map +1 -0
- package/dist/commands/rpc/smoke.js +92 -0
- package/dist/commands/rpc/smoke.js.map +1 -0
- package/dist/commands/sdk/index.d.ts +9 -0
- package/dist/commands/sdk/index.d.ts.map +1 -0
- package/dist/commands/sdk/index.js +58 -0
- package/dist/commands/sdk/index.js.map +1 -0
- package/dist/commands/sdk/run.d.ts +42 -0
- package/dist/commands/sdk/run.d.ts.map +1 -0
- package/dist/commands/sdk/run.js +220 -0
- package/dist/commands/sdk/run.js.map +1 -0
- package/dist/commands/sdk/status.d.ts +14 -0
- package/dist/commands/sdk/status.d.ts.map +1 -0
- package/dist/commands/sdk/status.js +69 -0
- package/dist/commands/sdk/status.js.map +1 -0
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +13 -1
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/goal/action-packet.d.ts +89 -0
- package/dist/goal/action-packet.d.ts.map +1 -0
- package/dist/goal/action-packet.js +113 -0
- package/dist/goal/action-packet.js.map +1 -0
- package/dist/goal/audit.d.ts +14 -0
- package/dist/goal/audit.d.ts.map +1 -0
- package/dist/goal/audit.js +12 -0
- package/dist/goal/audit.js.map +1 -0
- package/dist/goal/constants.d.ts +26 -0
- package/dist/goal/constants.d.ts.map +1 -0
- package/dist/goal/constants.js +24 -0
- package/dist/goal/constants.js.map +1 -0
- package/dist/goal/paths.d.ts +8 -0
- package/dist/goal/paths.d.ts.map +1 -0
- package/dist/goal/paths.js +36 -0
- package/dist/goal/paths.js.map +1 -0
- package/dist/goal/preflight.d.ts +21 -0
- package/dist/goal/preflight.d.ts.map +1 -0
- package/dist/goal/preflight.js +97 -0
- package/dist/goal/preflight.js.map +1 -0
- package/dist/goal/review-seam.d.ts +44 -0
- package/dist/goal/review-seam.d.ts.map +1 -0
- package/dist/goal/review-seam.js +153 -0
- package/dist/goal/review-seam.js.map +1 -0
- package/dist/goal/reviewer-rules.d.ts +13 -0
- package/dist/goal/reviewer-rules.d.ts.map +1 -0
- package/dist/goal/reviewer-rules.js +153 -0
- package/dist/goal/reviewer-rules.js.map +1 -0
- package/dist/goal/reviewer.d.ts +9 -0
- package/dist/goal/reviewer.d.ts.map +1 -0
- package/dist/goal/reviewer.js +54 -0
- package/dist/goal/reviewer.js.map +1 -0
- package/dist/goal/runtime.d.ts +32 -0
- package/dist/goal/runtime.d.ts.map +1 -0
- package/dist/goal/runtime.js +242 -0
- package/dist/goal/runtime.js.map +1 -0
- package/dist/goal/sdk-client.d.ts +10 -0
- package/dist/goal/sdk-client.d.ts.map +1 -0
- package/dist/goal/sdk-client.js +34 -0
- package/dist/goal/sdk-client.js.map +1 -0
- package/dist/goal/state.d.ts +40 -0
- package/dist/goal/state.d.ts.map +1 -0
- package/dist/goal/state.js +37 -0
- package/dist/goal/state.js.map +1 -0
- package/dist/goal/task-triggers.d.ts +15 -0
- package/dist/goal/task-triggers.d.ts.map +1 -0
- package/dist/goal/task-triggers.js +23 -0
- package/dist/goal/task-triggers.js.map +1 -0
- package/dist/goal/walls.d.ts +12 -0
- package/dist/goal/walls.d.ts.map +1 -0
- package/dist/goal/walls.js +65 -0
- package/dist/goal/walls.js.map +1 -0
- package/dist/goal/worker-prompt.d.ts +13 -0
- package/dist/goal/worker-prompt.d.ts.map +1 -0
- package/dist/goal/worker-prompt.js +41 -0
- package/dist/goal/worker-prompt.js.map +1 -0
- package/dist/goal/worker.d.ts +42 -0
- package/dist/goal/worker.d.ts.map +1 -0
- package/dist/goal/worker.js +180 -0
- package/dist/goal/worker.js.map +1 -0
- package/dist/migrations/manifests/0.3.5.json +9 -0
- package/dist/migrations/manifests/0.3.6.json +9 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +35 -29
- package/dist/templates/common/bundled-skills/smart-search-cli/references/cli-contract.md +11 -25
- package/dist/templates/common/commands/continue.md +15 -3
- package/dist/templates/common/skills/check.md +7 -4
- package/dist/templates/cursor/agents/cstl-check.md +1 -0
- package/dist/templates/cursor/fixtures/expected-rules.d.ts.map +1 -1
- package/dist/templates/cursor/fixtures/expected-rules.js +6 -1
- package/dist/templates/cursor/fixtures/expected-rules.js.map +1 -1
- package/dist/templates/cursor/rules/cstl-cursor-modes.mdc +32 -0
- package/dist/templates/cursor/rules/cstl-triage.mdc +2 -4
- package/dist/templates/cursor/rules/retrieval-routing.mdc +26 -7
- package/dist/templates/markdown/agents.md +2 -0
- package/dist/templates/markdown/index.d.ts +3 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +3 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/guides/cursor-context-injection-guide.md.txt +38 -21
- package/dist/templates/markdown/spec/guides/cursor-native-modes-guide.md.txt +125 -0
- package/dist/templates/markdown/spec/guides/index.md.txt +107 -104
- package/dist/templates/markdown/spec/guides/injection-budget-guide.md.txt +111 -0
- package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +38 -6
- package/dist/templates/markdown/spec/guides/verification-strength-guide.md.txt +184 -0
- package/dist/templates/shared-hooks/session-start.py +10 -0
- package/dist/templates/trellis/config.yaml +18 -0
- package/dist/templates/trellis/index.d.ts +5 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +14 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/common/artifact_locale.py +278 -0
- package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +51 -2
- package/dist/templates/trellis/scripts/common/config.py +39 -0
- package/dist/templates/trellis/scripts/common/injection_budget.py +317 -0
- package/dist/templates/trellis/scripts/common/parent_orchestration.py +500 -5
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +9 -3
- package/dist/templates/trellis/scripts/common/session_context.py +32 -4
- package/dist/templates/trellis/scripts/common/session_memory.py +26 -0
- package/dist/templates/trellis/scripts/common/subagent_dispatch.py +74 -9
- package/dist/templates/trellis/scripts/common/task_context.py +18 -0
- package/dist/templates/trellis/scripts/common/task_dashboard.py +16 -1
- package/dist/templates/trellis/scripts/common/task_map.py +670 -614
- package/dist/templates/trellis/scripts/common/task_store.py +191 -40
- package/dist/templates/trellis/scripts/common/test_observable_defaults.py +135 -0
- package/dist/templates/trellis/scripts/cursor_retrieval_probe_prompt.md +14 -12
- package/dist/templates/trellis/scripts/generate_dispatch_prompt.py +182 -0
- package/dist/templates/trellis/scripts/injection_budget_probe.py +69 -0
- package/dist/templates/trellis/scripts/retrieval_probe_matrix_template.json +3 -3
- package/dist/templates/trellis/scripts/spec_health_outcomes.py +160 -0
- package/dist/templates/trellis/scripts/task.py +51 -0
- package/dist/templates/trellis/tasks/locale/en/default-prd.md +19 -0
- package/dist/templates/trellis/tasks/locale/zh/default-prd.md +19 -0
- package/dist/templates/trellis/workflow.md +23 -3
- package/dist/utils/codebase-retrieval-router.d.ts.map +1 -1
- package/dist/utils/codebase-retrieval-router.js +14 -0
- package/dist/utils/codebase-retrieval-router.js.map +1 -1
- package/dist/utils/cursor-sdk-gate.d.ts +10 -0
- package/dist/utils/cursor-sdk-gate.d.ts.map +1 -0
- package/dist/utils/cursor-sdk-gate.js +32 -0
- package/dist/utils/cursor-sdk-gate.js.map +1 -0
- package/dist/utils/project-capabilities.d.ts +30 -3
- package/dist/utils/project-capabilities.d.ts.map +1 -1
- package/dist/utils/project-capabilities.js +182 -11
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/readiness.d.ts.map +1 -1
- package/dist/utils/readiness.js +26 -0
- package/dist/utils/readiness.js.map +1 -1
- package/package.json +4 -3
|
@@ -20,6 +20,7 @@ from .paths import DIR_WORKFLOW, DIR_WORKSPACE, FILE_JOURNAL_PREFIX, get_develop
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
SECTION_NAMES = {"summary", "main changes", "git commits", "testing", "status", "next steps"}
|
|
23
|
+
JOURNAL_SNIPPET_MAX_TOKENS = 150
|
|
23
24
|
FIELD_WEIGHTS = {
|
|
24
25
|
"title": 8,
|
|
25
26
|
"task": 8,
|
|
@@ -337,6 +338,31 @@ def normalize_space(value: str) -> str:
|
|
|
337
338
|
return re.sub(r"\s+", " ", value).strip()
|
|
338
339
|
|
|
339
340
|
|
|
341
|
+
def truncate_to_token_budget(text: str, max_tokens: int = JOURNAL_SNIPPET_MAX_TOKENS) -> str:
|
|
342
|
+
"""Collapse whitespace and hard-cap by whitespace-split token count."""
|
|
343
|
+
normalized = normalize_space(text)
|
|
344
|
+
if not normalized:
|
|
345
|
+
return ""
|
|
346
|
+
tokens = normalized.split()
|
|
347
|
+
if len(tokens) <= max_tokens:
|
|
348
|
+
return normalized
|
|
349
|
+
return " ".join(tokens[:max_tokens])
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def get_latest_journal_summary(
|
|
353
|
+
journal_path: Path,
|
|
354
|
+
repo_root: Path,
|
|
355
|
+
developer: str,
|
|
356
|
+
max_tokens: int = JOURNAL_SNIPPET_MAX_TOKENS,
|
|
357
|
+
) -> str:
|
|
358
|
+
"""Return the latest session summary from one journal file (≤ max_tokens)."""
|
|
359
|
+
entries = parse_journal(journal_path, repo_root, developer)
|
|
360
|
+
if not entries:
|
|
361
|
+
return ""
|
|
362
|
+
summary = entries[-1].sections.get("summary", "")
|
|
363
|
+
return truncate_to_token_budget(summary, max_tokens)
|
|
364
|
+
|
|
365
|
+
|
|
340
366
|
def to_repo_path(path: Path, repo_root: Path) -> str:
|
|
341
367
|
try:
|
|
342
368
|
return path.resolve().relative_to(repo_root.resolve()).as_posix()
|
|
@@ -12,6 +12,11 @@ import sys
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Literal
|
|
14
14
|
|
|
15
|
+
from .injection_budget import (
|
|
16
|
+
JSONL_MAX_ENTRIES,
|
|
17
|
+
JSONL_MAX_FILE_CHARS,
|
|
18
|
+
JSONL_MAX_TOTAL_CHARS,
|
|
19
|
+
)
|
|
15
20
|
from .io import read_json
|
|
16
21
|
from .paths import FILE_TASK_JSON
|
|
17
22
|
|
|
@@ -87,7 +92,8 @@ def read_jsonl_entries(
|
|
|
87
92
|
jsonl_path: str,
|
|
88
93
|
*,
|
|
89
94
|
warn_prefix: str = "subagent-dispatch",
|
|
90
|
-
|
|
95
|
+
apply_budget: bool = True,
|
|
96
|
+
) -> tuple[list[tuple[str, str]], list[str]]:
|
|
91
97
|
full_path = os.path.join(base_path, jsonl_path)
|
|
92
98
|
if not os.path.exists(full_path):
|
|
93
99
|
print(
|
|
@@ -95,10 +101,13 @@ def read_jsonl_entries(
|
|
|
95
101
|
"sub-agent will receive only task artifacts",
|
|
96
102
|
file=sys.stderr,
|
|
97
103
|
)
|
|
98
|
-
return []
|
|
104
|
+
return [], []
|
|
99
105
|
|
|
100
106
|
results: list[tuple[str, str]] = []
|
|
107
|
+
skipped: list[str] = []
|
|
101
108
|
saw_real_entry = False
|
|
109
|
+
loaded_entries = 0
|
|
110
|
+
total_chars = 0
|
|
102
111
|
try:
|
|
103
112
|
with open(full_path, "r", encoding="utf-8") as f:
|
|
104
113
|
for line in f:
|
|
@@ -112,12 +121,38 @@ def read_jsonl_entries(
|
|
|
112
121
|
if not file_path:
|
|
113
122
|
continue
|
|
114
123
|
saw_real_entry = True
|
|
124
|
+
if apply_budget and loaded_entries >= JSONL_MAX_ENTRIES:
|
|
125
|
+
skipped.append(f"{file_path}: entry cap ({JSONL_MAX_ENTRIES})")
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
expanded: list[tuple[str, str]] = []
|
|
115
129
|
if entry_type == "directory":
|
|
116
|
-
|
|
130
|
+
expanded = read_directory_contents(base_path, file_path)
|
|
117
131
|
else:
|
|
118
132
|
content = read_file_content(base_path, file_path)
|
|
119
133
|
if content:
|
|
120
|
-
|
|
134
|
+
expanded = [(file_path, content)]
|
|
135
|
+
|
|
136
|
+
if not expanded:
|
|
137
|
+
skipped.append(f"{file_path}: missing or empty")
|
|
138
|
+
continue
|
|
139
|
+
|
|
140
|
+
block_chars = sum(len(content) for _, content in expanded)
|
|
141
|
+
if apply_budget and block_chars > JSONL_MAX_FILE_CHARS:
|
|
142
|
+
skipped.append(
|
|
143
|
+
f"{file_path}: file cap ({block_chars}>{JSONL_MAX_FILE_CHARS} chars)"
|
|
144
|
+
)
|
|
145
|
+
continue
|
|
146
|
+
if apply_budget and total_chars + block_chars > JSONL_MAX_TOTAL_CHARS:
|
|
147
|
+
skipped.append(
|
|
148
|
+
f"{file_path}: total cap "
|
|
149
|
+
f"({total_chars + block_chars}>{JSONL_MAX_TOTAL_CHARS})"
|
|
150
|
+
)
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
results.extend(expanded)
|
|
154
|
+
total_chars += block_chars
|
|
155
|
+
loaded_entries += 1
|
|
121
156
|
except json.JSONDecodeError:
|
|
122
157
|
continue
|
|
123
158
|
except OSError:
|
|
@@ -129,13 +164,23 @@ def read_jsonl_entries(
|
|
|
129
164
|
"(only seed / empty) — sub-agent will receive only task artifacts.",
|
|
130
165
|
file=sys.stderr,
|
|
131
166
|
)
|
|
132
|
-
|
|
167
|
+
elif apply_budget and (results or skipped):
|
|
168
|
+
loaded_paths = ", ".join(path for path, _ in results) or "(none)"
|
|
169
|
+
print(
|
|
170
|
+
f"[{warn_prefix}] injection-budget: {jsonl_path} "
|
|
171
|
+
f"loaded {loaded_entries} entries ({total_chars} chars): {loaded_paths}",
|
|
172
|
+
file=sys.stderr,
|
|
173
|
+
)
|
|
174
|
+
for reason in skipped:
|
|
175
|
+
print(f"[{warn_prefix}] injection-budget: skipped {reason}", file=sys.stderr)
|
|
176
|
+
return results, skipped
|
|
133
177
|
|
|
134
178
|
|
|
135
179
|
def get_agent_context(repo_root: str, task_dir: str, agent_type: str) -> str:
|
|
136
180
|
context_parts: list[str] = []
|
|
137
181
|
agent_jsonl = f"{task_dir}/{agent_type}.jsonl"
|
|
138
|
-
|
|
182
|
+
entries, _ = read_jsonl_entries(repo_root, agent_jsonl)
|
|
183
|
+
for file_path, content in entries:
|
|
139
184
|
context_parts.append(f"=== {file_path} ===\n{content}")
|
|
140
185
|
return "\n\n".join(context_parts)
|
|
141
186
|
|
|
@@ -166,7 +211,8 @@ def get_implement_context(repo_root: str, task_dir: str) -> str:
|
|
|
166
211
|
|
|
167
212
|
def get_check_context(repo_root: str, task_dir: str) -> str:
|
|
168
213
|
context_parts: list[str] = []
|
|
169
|
-
|
|
214
|
+
entries, _ = read_jsonl_entries(repo_root, f"{task_dir}/check.jsonl")
|
|
215
|
+
for file_path, content in entries:
|
|
170
216
|
context_parts.append(f"=== {file_path} ===\n{content}")
|
|
171
217
|
|
|
172
218
|
prd_content = read_file_content(repo_root, f"{task_dir}/prd.md")
|
|
@@ -192,7 +238,25 @@ def get_finish_context(repo_root: str, task_dir: str) -> str:
|
|
|
192
238
|
|
|
193
239
|
|
|
194
240
|
def get_research_context(repo_root: str, task_dir: str | None) -> str:
|
|
195
|
-
|
|
241
|
+
context_parts: list[str] = []
|
|
242
|
+
|
|
243
|
+
if task_dir:
|
|
244
|
+
entries, _ = read_jsonl_entries(repo_root, f"{task_dir}/research.jsonl")
|
|
245
|
+
for file_path, content in entries:
|
|
246
|
+
context_parts.append(f"=== {file_path} ===\n{content}")
|
|
247
|
+
|
|
248
|
+
prd_content = read_file_content(repo_root, f"{task_dir}/prd.md")
|
|
249
|
+
if prd_content:
|
|
250
|
+
context_parts.append(
|
|
251
|
+
f"=== {task_dir}/prd.md (Requirements) ===\n{prd_content}"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
design_content = read_file_content(repo_root, f"{task_dir}/design.md")
|
|
255
|
+
if design_content:
|
|
256
|
+
context_parts.append(
|
|
257
|
+
f"=== {task_dir}/design.md (Technical Design) ===\n{design_content}"
|
|
258
|
+
)
|
|
259
|
+
|
|
196
260
|
spec_path = f"{DIR_WORKFLOW}/{DIR_SPEC}"
|
|
197
261
|
spec_root = Path(repo_root) / DIR_WORKFLOW / DIR_SPEC
|
|
198
262
|
|
|
@@ -219,7 +283,8 @@ To get structured package info, run: `python ./{DIR_WORKFLOW}/scripts/get_contex
|
|
|
219
283
|
- Spec files: `{spec_path}/**/*.md`
|
|
220
284
|
- Code search: Use Glob and Grep tools
|
|
221
285
|
- External facts / docs: load `smart-search-cli` skill and use Bash (`smart-search` CLI), not Cursor WebSearch/WebFetch by default"""
|
|
222
|
-
|
|
286
|
+
context_parts.append(project_structure)
|
|
287
|
+
return "\n\n".join(context_parts)
|
|
223
288
|
|
|
224
289
|
|
|
225
290
|
def build_implement_prompt(original_prompt: str, context: str) -> str:
|
|
@@ -24,6 +24,11 @@ from pathlib import Path
|
|
|
24
24
|
from .log import Colors, colored
|
|
25
25
|
from .paths import get_repo_root
|
|
26
26
|
from .task_utils import resolve_task_dir
|
|
27
|
+
from .injection_budget import (
|
|
28
|
+
JSONL_MAX_ENTRIES,
|
|
29
|
+
JSONL_MAX_TOTAL_CHARS,
|
|
30
|
+
measure_jsonl_manifest,
|
|
31
|
+
)
|
|
27
32
|
|
|
28
33
|
|
|
29
34
|
# =============================================================================
|
|
@@ -159,6 +164,19 @@ def _validate_jsonl(jsonl_file: Path, repo_root: Path) -> int:
|
|
|
159
164
|
|
|
160
165
|
if errors == 0:
|
|
161
166
|
print(f" {colored(f'{file_name}: ✓ ({real_entries} entries)', Colors.GREEN)}")
|
|
167
|
+
budget = measure_jsonl_manifest(repo_root, jsonl_file.parent, file_name)
|
|
168
|
+
if real_entries > JSONL_MAX_ENTRIES:
|
|
169
|
+
print(
|
|
170
|
+
f" {colored(f'{file_name}: budget WARN — {real_entries} entries (max {JSONL_MAX_ENTRIES})', Colors.YELLOW)}"
|
|
171
|
+
)
|
|
172
|
+
if budget.expanded_chars > JSONL_MAX_TOTAL_CHARS:
|
|
173
|
+
print(
|
|
174
|
+
f" {colored(f'{file_name}: budget WARN — expanded {budget.expanded_chars} chars (max {JSONL_MAX_TOTAL_CHARS})', Colors.YELLOW)}"
|
|
175
|
+
)
|
|
176
|
+
elif budget.skipped:
|
|
177
|
+
print(
|
|
178
|
+
f" {colored(f'{file_name}: budget WARN — {len(budget.skipped)} entries would be skipped at dispatch', Colors.YELLOW)}"
|
|
179
|
+
)
|
|
162
180
|
else:
|
|
163
181
|
print(f" {colored(f'{file_name}: ✗ ({errors} errors)', Colors.RED)}")
|
|
164
182
|
|
|
@@ -7,6 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
from .active_task import resolve_selected_task
|
|
9
9
|
from .paths import DIR_TASKS, DIR_WORKFLOW, get_developer, get_repo_root, get_tasks_dir
|
|
10
|
+
from .task_gates import verify_evidence_status
|
|
10
11
|
from .task_map import get_child_state
|
|
11
12
|
from .tasks import (
|
|
12
13
|
children_progress,
|
|
@@ -23,6 +24,19 @@ def _task_path(dir_name: str) -> str:
|
|
|
23
24
|
return f"{DIR_WORKFLOW}/{DIR_TASKS}/{dir_name}"
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def format_verify_summary(task_dir: Path, task_data: dict) -> str:
|
|
28
|
+
"""Return a compact verify evidence label for dashboard task lines."""
|
|
29
|
+
verify_path = task_dir / "verify.md"
|
|
30
|
+
if not verify_path.is_file():
|
|
31
|
+
return "[verify: missing]"
|
|
32
|
+
status = verify_evidence_status(task_dir, task_data)
|
|
33
|
+
if all(status.values()):
|
|
34
|
+
return "[verify: ok]"
|
|
35
|
+
if any(status.values()):
|
|
36
|
+
return "[verify: partial]"
|
|
37
|
+
return "[verify: missing]"
|
|
38
|
+
|
|
39
|
+
|
|
26
40
|
def _selected_line(
|
|
27
41
|
repo_root: Path,
|
|
28
42
|
platform_input: dict | None = None,
|
|
@@ -123,9 +137,10 @@ def _append_task(
|
|
|
123
137
|
integration_state = get_child_state(parent_dir, name)
|
|
124
138
|
status_display = format_child_task_display(task.status, integration_state)
|
|
125
139
|
assignee = task.assignee or "-"
|
|
140
|
+
verify_summary = format_verify_summary(task.directory, task.raw or {})
|
|
126
141
|
prefix = " " * indent + " - "
|
|
127
142
|
lines.append(
|
|
128
|
-
f"{prefix}{_task_path(name)} ({status_display}){progress} [{assignee}]"
|
|
143
|
+
f"{prefix}{_task_path(name)} ({status_display}){progress} [{assignee}] {verify_summary}"
|
|
129
144
|
)
|
|
130
145
|
for child_name in task.children:
|
|
131
146
|
if child_name in all_tasks:
|