prizmkit 1.1.72 → 1.1.76
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/bundled/VERSION.json +3 -3
- package/bundled/agents/prizm-dev-team-dev.md +11 -1
- package/bundled/dev-pipeline/.env.example +1 -0
- package/bundled/dev-pipeline/lib/common.sh +53 -0
- package/bundled/dev-pipeline/lib/heartbeat.sh +94 -42
- package/bundled/dev-pipeline/run-bugfix.sh +5 -0
- package/bundled/dev-pipeline/run-feature.sh +5 -0
- package/bundled/dev-pipeline/run-recovery.sh +6 -0
- package/bundled/dev-pipeline/run-refactor.sh +5 -0
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +265 -5
- package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +21 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +5 -9
- package/bundled/dev-pipeline/templates/sections/feature-context.md +3 -18
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +6 -12
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +10 -3
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -0
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +4 -8
- package/bundled/dev-pipeline-windows/lib/common.ps1 +23 -0
- package/bundled/dev-pipeline-windows/lib/heartbeat.sh +439 -0
- package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +33 -2
- package/bundled/dev-pipeline-windows/run-recovery.ps1 +11 -0
- package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +265 -5
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +21 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +1 -1
- package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +27 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +543 -14
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +664 -14
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +741 -14
- package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +2 -2
- package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +1 -1
- package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +3 -3
- package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +3 -18
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +239 -40
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +75 -26
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +142 -36
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +2 -2
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +7 -17
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +10 -3
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +3 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +7 -3
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +1 -3
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +1 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +2 -2
- package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +13 -17
- package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +2 -4
- package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +1 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +1 -0
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +1 -0
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +1 -0
- package/package.json +1 -1
|
@@ -137,7 +137,10 @@ class ProgressTracker:
|
|
|
137
137
|
self.event_format = ""
|
|
138
138
|
self.active_subagent_count = 0
|
|
139
139
|
self.subagent_status_counts = Counter()
|
|
140
|
+
self._subagent_spawn_count = 0
|
|
140
141
|
self.codex_child_thread_ids = set()
|
|
142
|
+
self.cb_session_id = ""
|
|
143
|
+
self.cb_cwd = ""
|
|
141
144
|
self.claude_session_id = ""
|
|
142
145
|
self.claude_cwd = ""
|
|
143
146
|
self.claude_task_states = {}
|
|
@@ -147,6 +150,7 @@ class ProgressTracker:
|
|
|
147
150
|
self.last_child_activity_at = ""
|
|
148
151
|
self._codex_child_session_paths = {}
|
|
149
152
|
self._claude_child_session_files = []
|
|
153
|
+
self._cb_child_session_files = []
|
|
150
154
|
self._last_child_scan_at = 0.0
|
|
151
155
|
self._last_claude_fallback_scan_at = 0.0
|
|
152
156
|
self._last_claude_fallback_scan_key = ""
|
|
@@ -158,10 +162,13 @@ class ProgressTracker:
|
|
|
158
162
|
def process_event(self, event):
|
|
159
163
|
"""Process a single stream-json event and update state.
|
|
160
164
|
|
|
161
|
-
Supports
|
|
165
|
+
Supports three formats:
|
|
162
166
|
1. Claude API raw stream: message_start, content_block_start, content_block_delta, etc.
|
|
163
167
|
2. Claude Code verbose stream-json: assistant, user, tool_result, system, etc.
|
|
164
168
|
(produced by claude/claude-internal --verbose --output-format stream-json)
|
|
169
|
+
3. CodeBuddy stream-json: message/function_call/function_call_result events
|
|
170
|
+
(produced by cbc --print -y --output-format stream-json — message type
|
|
171
|
+
with sessionId/cwd metadata, function_call for tool invocations).
|
|
165
172
|
"""
|
|
166
173
|
event_type = event.get("type", "")
|
|
167
174
|
|
|
@@ -233,6 +240,93 @@ class ProgressTracker:
|
|
|
233
240
|
|
|
234
241
|
return
|
|
235
242
|
|
|
243
|
+
# ── CodeBuddy stream-json format ──────────────────────────────
|
|
244
|
+
# cbc --print -y --output-format stream-json emits:
|
|
245
|
+
# message (role=user/assistant), function_call, function_call_result,
|
|
246
|
+
# file-history-snapshot, error. The first user message carries
|
|
247
|
+
# sessionId and cwd metadata; later function_call items carry the
|
|
248
|
+
# same fields.
|
|
249
|
+
# NOTE: cbc emits tool invocations as EITHER tool_use blocks inside a
|
|
250
|
+
# message (role=assistant) event OR as standalone function_call events,
|
|
251
|
+
# but not both for the same invocation. The two handlers are
|
|
252
|
+
# complementary rather than redundant, so no deduplication is needed.
|
|
253
|
+
# Detect via event_type=="message" with a "sessionId" field.
|
|
254
|
+
# Must run before the Claude Code assistant / tool_result branches
|
|
255
|
+
# because those also accept those types but use different internals.
|
|
256
|
+
if event_type == "message" and isinstance(event.get("sessionId"), str):
|
|
257
|
+
self.event_format = self.event_format or "stream-json"
|
|
258
|
+
role = event.get("role", "")
|
|
259
|
+
sid = event.get("sessionId", "")
|
|
260
|
+
cwd = event.get("cwd", "")
|
|
261
|
+
if sid and not self.cb_session_id:
|
|
262
|
+
self.cb_session_id = sid.strip()
|
|
263
|
+
if cwd and not self.cb_cwd:
|
|
264
|
+
self.cb_cwd = cwd.strip()
|
|
265
|
+
if role == "assistant":
|
|
266
|
+
self.message_count += 1
|
|
267
|
+
self.is_active = True
|
|
268
|
+
content = event.get("content", [])
|
|
269
|
+
if isinstance(content, list):
|
|
270
|
+
for block in content:
|
|
271
|
+
block_type = block.get("type", "")
|
|
272
|
+
if block_type == "tool_use":
|
|
273
|
+
tool_name = block.get("name", "unknown")
|
|
274
|
+
self.current_tool = tool_name
|
|
275
|
+
self.tool_call_counts[tool_name] += 1
|
|
276
|
+
self.total_tool_calls += 1
|
|
277
|
+
tool_input = block.get("input", {})
|
|
278
|
+
if isinstance(tool_input, dict):
|
|
279
|
+
self._extract_tool_summary_from_dict(tool_input)
|
|
280
|
+
self._detect_phase(
|
|
281
|
+
json.dumps(tool_input, ensure_ascii=False)[:500]
|
|
282
|
+
)
|
|
283
|
+
# Track CodeBuddy Agent/Task tool invocations as
|
|
284
|
+
# potential sub-agent spawns (Gap 3 fix).
|
|
285
|
+
self._record_cb_agent_tool_call(tool_name, tool_input)
|
|
286
|
+
elif block_type == "text":
|
|
287
|
+
text = block.get("text", "")
|
|
288
|
+
if text.strip():
|
|
289
|
+
self.last_text_snippet = text.strip()[:120]
|
|
290
|
+
self._detect_phase(text)
|
|
291
|
+
self._detect_terminal_error(
|
|
292
|
+
text, require_error_context=True
|
|
293
|
+
)
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
# CodeBuddy function_call / function_call_result in stream-json
|
|
297
|
+
if event_type in ("function_call", "function_call_result"):
|
|
298
|
+
self.event_format = self.event_format or "stream-json"
|
|
299
|
+
sid = event.get("sessionId", "")
|
|
300
|
+
cwd = event.get("cwd", "")
|
|
301
|
+
if sid and not self.cb_session_id:
|
|
302
|
+
self.cb_session_id = sid.strip()
|
|
303
|
+
if cwd and not self.cb_cwd:
|
|
304
|
+
self.cb_cwd = cwd.strip()
|
|
305
|
+
if event_type == "function_call":
|
|
306
|
+
tool_name = event.get("name", "unknown")
|
|
307
|
+
self.current_tool = tool_name
|
|
308
|
+
self.tool_call_counts[tool_name] += 1
|
|
309
|
+
self.total_tool_calls += 1
|
|
310
|
+
self.is_active = True
|
|
311
|
+
# Extract summary from arguments
|
|
312
|
+
raw_args = event.get("arguments", "")
|
|
313
|
+
if isinstance(raw_args, str) and raw_args.strip():
|
|
314
|
+
self._extract_tool_summary(raw_args)
|
|
315
|
+
self._detect_phase(raw_args[:500])
|
|
316
|
+
# Track Agent/Task tool invocations as sub-agent spawns
|
|
317
|
+
self._record_cb_agent_tool_call(tool_name, raw_args)
|
|
318
|
+
elif event_type == "function_call_result":
|
|
319
|
+
self.current_tool = None
|
|
320
|
+
# Check result text for phase / error hints
|
|
321
|
+
result_text = event.get("output") or ""
|
|
322
|
+
if result_text and isinstance(result_text, str):
|
|
323
|
+
stripped = result_text.strip()
|
|
324
|
+
if stripped:
|
|
325
|
+
self.last_text_snippet = stripped[:120]
|
|
326
|
+
self._detect_phase(stripped)
|
|
327
|
+
self._detect_terminal_error(stripped, require_error_context=True)
|
|
328
|
+
return
|
|
329
|
+
|
|
236
330
|
# ── Claude Code verbose format ──────────────────────────────
|
|
237
331
|
if event_type == "assistant":
|
|
238
332
|
self.event_format = self.event_format or "stream-json"
|
|
@@ -259,11 +353,52 @@ class ProgressTracker:
|
|
|
259
353
|
self._detect_phase(text)
|
|
260
354
|
self._detect_terminal_error(text, require_error_context=True)
|
|
261
355
|
|
|
262
|
-
elif event_type == "tool_result" or
|
|
356
|
+
elif event_type == "tool_result" or (
|
|
357
|
+
event_type == "user"
|
|
358
|
+
and not isinstance(event.get("sessionId"), str)
|
|
359
|
+
):
|
|
263
360
|
# tool_result contains output from tool execution
|
|
264
361
|
self.event_format = self.event_format or "stream-json"
|
|
265
362
|
self.is_active = True
|
|
266
363
|
|
|
364
|
+
# Check for error patterns in tool_result content (supports both formats):
|
|
365
|
+
# A) Top-level tool_result events: event["content"] is the result text
|
|
366
|
+
# B) Nested user events: event["message"]["content"][] has type=="tool_result" items
|
|
367
|
+
content_candidates = []
|
|
368
|
+
|
|
369
|
+
# Format A: top-level tool_result (Claude Code)
|
|
370
|
+
if event_type == "tool_result":
|
|
371
|
+
content_candidates.append(str(event.get("content", "")))
|
|
372
|
+
|
|
373
|
+
# Format B: nested inside user event (Claude Code, NOT CodeBuddy)
|
|
374
|
+
if event_type == "user":
|
|
375
|
+
message = event.get("message", {})
|
|
376
|
+
content_list = message.get("content", [])
|
|
377
|
+
if isinstance(content_list, list):
|
|
378
|
+
for item in content_list:
|
|
379
|
+
if isinstance(item, dict) and item.get("type") == "tool_result":
|
|
380
|
+
content_candidates.append(str(item.get("content", "")))
|
|
381
|
+
|
|
382
|
+
for result_text in content_candidates:
|
|
383
|
+
if "shorter than the provided offset" in result_text:
|
|
384
|
+
self.errors.append({
|
|
385
|
+
"type": "read_offset_overflow",
|
|
386
|
+
"tool": self.current_tool,
|
|
387
|
+
"at": datetime.now(timezone.utc).isoformat(),
|
|
388
|
+
})
|
|
389
|
+
break # one error per event is enough
|
|
390
|
+
elif "Wasted call" in result_text:
|
|
391
|
+
self.errors.append({
|
|
392
|
+
"type": "wasted_call",
|
|
393
|
+
"tool": self.current_tool,
|
|
394
|
+
"at": datetime.now(timezone.utc).isoformat(),
|
|
395
|
+
})
|
|
396
|
+
break
|
|
397
|
+
|
|
398
|
+
# Keep only last 20 errors to prevent unbounded growth in progress.json
|
|
399
|
+
if len(self.errors) > 20:
|
|
400
|
+
self.errors = self.errors[-20:]
|
|
401
|
+
|
|
267
402
|
elif event_type == "system":
|
|
268
403
|
# System events (hooks, init, task notifications, etc.) — track but don't count as messages.
|
|
269
404
|
self.event_format = self.event_format or "stream-json"
|
|
@@ -427,15 +562,60 @@ class ProgressTracker:
|
|
|
427
562
|
self._current_tool_input_parts = []
|
|
428
563
|
|
|
429
564
|
elif event_type == "error":
|
|
565
|
+
self.event_format = self.event_format or "stream-json"
|
|
430
566
|
error_msg = event.get("error", {}).get("message", "Unknown error")
|
|
567
|
+
errors = event.get("errors") or []
|
|
568
|
+
if isinstance(errors, list) and errors:
|
|
569
|
+
error_msg = "; ".join(str(e) for e in errors[:3])
|
|
431
570
|
self.errors.append(error_msg)
|
|
432
571
|
self._detect_terminal_error(str(error_msg))
|
|
433
572
|
|
|
573
|
+
# ── CodeBuddy file-history-snapshot (ignore) ─────────────────
|
|
574
|
+
elif event_type == "file-history-snapshot":
|
|
575
|
+
return
|
|
576
|
+
|
|
434
577
|
# Check for subagent indicator
|
|
435
578
|
if event.get("parent_tool_use_id"):
|
|
436
579
|
# This is a sub-agent event; tool name is still tracked normally
|
|
437
580
|
pass
|
|
438
581
|
|
|
582
|
+
def _record_cb_agent_tool_call(self, tool_name, raw_args):
|
|
583
|
+
"""Record a CodeBuddy Agent/Task* tool invocation for sub-agent tracking.
|
|
584
|
+
|
|
585
|
+
CodeBuddy spawns sub-agents via:
|
|
586
|
+
- Agent(prompt=..., run_in_background=True/False) — synchronous or bg fork
|
|
587
|
+
- TaskCreate(subject=..., description=...) — scheduled task
|
|
588
|
+
|
|
589
|
+
(TaskUpdate/TaskOutput exist but are lifecycle-only — they track
|
|
590
|
+
existing tasks rather than creating new sub-agents, so we don't
|
|
591
|
+
count them as spawns.)
|
|
592
|
+
|
|
593
|
+
We don't get child session ids from these tool calls in the stream,
|
|
594
|
+
but recording the count lets the heartbeat code in heartbeat.sh apply
|
|
595
|
+
an extended stale-kill window just as it does for Codex spawn_agent.
|
|
596
|
+
"""
|
|
597
|
+
if tool_name not in ("Agent", "TaskCreate"):
|
|
598
|
+
return
|
|
599
|
+
# Both dict (from message events) and str/JSON (from function_call events)
|
|
600
|
+
# are supported.
|
|
601
|
+
if isinstance(raw_args, dict):
|
|
602
|
+
args = raw_args
|
|
603
|
+
elif isinstance(raw_args, str):
|
|
604
|
+
try:
|
|
605
|
+
args = json.loads(raw_args)
|
|
606
|
+
except (json.JSONDecodeError, TypeError):
|
|
607
|
+
return
|
|
608
|
+
else:
|
|
609
|
+
return
|
|
610
|
+
# For Agent tool, subagent_type or run_in_background hints at delegation
|
|
611
|
+
if tool_name == "Agent":
|
|
612
|
+
subagent_type = args.get("subagent_type", "")
|
|
613
|
+
prompt = args.get("prompt", "")
|
|
614
|
+
if subagent_type or prompt:
|
|
615
|
+
self._subagent_spawn_count += 1
|
|
616
|
+
elif tool_name == "TaskCreate":
|
|
617
|
+
self._subagent_spawn_count += 1
|
|
618
|
+
|
|
439
619
|
def _record_terminal_result(self, text="", is_error=False, api_error_status=None, api_error_code=""):
|
|
440
620
|
"""Record a Claude Code terminal result event."""
|
|
441
621
|
terminal_text = str(text or "")
|
|
@@ -719,17 +899,85 @@ class ProgressTracker:
|
|
|
719
899
|
return []
|
|
720
900
|
return matches
|
|
721
901
|
|
|
902
|
+
def _cb_projects_dir(self):
|
|
903
|
+
"""Return the CodeBuddy projects directory for transcript lookup.
|
|
904
|
+
|
|
905
|
+
CodeBuddy stores per-project session transcripts and sub-agent data
|
|
906
|
+
under ~/.codebuddy/projects/{projectDir}/{sessionId}/.
|
|
907
|
+
"""
|
|
908
|
+
cb_config = os.environ.get("CODEBUDDY_CONFIG_DIR")
|
|
909
|
+
if cb_config:
|
|
910
|
+
return Path(cb_config).expanduser() / "projects"
|
|
911
|
+
cb_home = os.environ.get("CODEBUDDY_HOME")
|
|
912
|
+
if cb_home:
|
|
913
|
+
return Path(cb_home).expanduser() / "projects"
|
|
914
|
+
return Path.home() / ".codebuddy" / "projects"
|
|
915
|
+
|
|
916
|
+
def _cb_project_key(self):
|
|
917
|
+
"""Encode cwd the same way CodeBuddy stores project subdirs.
|
|
918
|
+
|
|
919
|
+
CodeBuddy uses the same sanitisation as Claude Code (\, /, : → -)
|
|
920
|
+
but strips the leading '-' so "/Users/test/MyProject" becomes
|
|
921
|
+
"Users-test-MyProject".
|
|
922
|
+
"""
|
|
923
|
+
cwd = self.cb_cwd
|
|
924
|
+
if not cwd:
|
|
925
|
+
return ""
|
|
926
|
+
return cwd.replace("\\", "-").replace("/", "-").replace(":", "").lstrip("-")
|
|
927
|
+
|
|
928
|
+
def _find_cb_child_session_files(self):
|
|
929
|
+
"""Find CodeBuddy subagent transcript data for this parent session.
|
|
930
|
+
|
|
931
|
+
CodeBuddy sub-agents store tool-results/{callId}.txt files; conversation
|
|
932
|
+
transcripts are not (as of 2026) written as agent-*.jsonl files in the
|
|
933
|
+
subagents/ directory. We track the tool-results .txt files as a proxy
|
|
934
|
+
for child activity so the heartbeat monitor can extend the stale-kill
|
|
935
|
+
window while sub-agents are running.
|
|
936
|
+
"""
|
|
937
|
+
if not self.cb_session_id:
|
|
938
|
+
return []
|
|
939
|
+
|
|
940
|
+
projects_dir = self._cb_projects_dir()
|
|
941
|
+
if not projects_dir.exists():
|
|
942
|
+
return []
|
|
943
|
+
|
|
944
|
+
project_key = self._cb_project_key()
|
|
945
|
+
if not project_key:
|
|
946
|
+
return []
|
|
947
|
+
|
|
948
|
+
subagents_dir = (
|
|
949
|
+
projects_dir / project_key / self.cb_session_id / "subagents"
|
|
950
|
+
)
|
|
951
|
+
if not subagents_dir.exists():
|
|
952
|
+
return []
|
|
953
|
+
|
|
954
|
+
# Collect all files under each agent-{id} subdirectory. These are
|
|
955
|
+
# currently tool-results/{callId}.txt files, but the glob also picks
|
|
956
|
+
# up future agent-*.jsonl transcripts should CodeBuddy add them.
|
|
957
|
+
try:
|
|
958
|
+
return sorted(
|
|
959
|
+
p for p in subagents_dir.glob("**/*")
|
|
960
|
+
if p.is_file()
|
|
961
|
+
)
|
|
962
|
+
except OSError:
|
|
963
|
+
return []
|
|
964
|
+
|
|
722
965
|
def refresh_child_session_activity(self, force=False):
|
|
723
966
|
"""Refresh child transcript file stats.
|
|
724
967
|
|
|
725
968
|
The heartbeat monitor uses this activity signature to treat subagent
|
|
726
969
|
transcript growth as real progress while the parent session is blocked
|
|
727
|
-
waiting for a child agent/tool result. Supports Codex child threads
|
|
728
|
-
Claude Code in-process teammate transcripts
|
|
970
|
+
waiting for a child agent/tool result. Supports Codex child threads,
|
|
971
|
+
Claude Code in-process teammate transcripts, and CodeBuddy sub-agent
|
|
972
|
+
file activity under subagents/.
|
|
729
973
|
"""
|
|
730
974
|
previous_signature = self.child_activity_signature
|
|
731
975
|
|
|
732
|
-
if
|
|
976
|
+
if (
|
|
977
|
+
not self.codex_child_thread_ids
|
|
978
|
+
and not self.claude_session_id
|
|
979
|
+
and not self.cb_session_id
|
|
980
|
+
):
|
|
733
981
|
self.child_session_files = []
|
|
734
982
|
self.child_total_bytes = 0
|
|
735
983
|
self.child_activity_signature = ""
|
|
@@ -750,6 +998,7 @@ class ProgressTracker:
|
|
|
750
998
|
if found:
|
|
751
999
|
self._codex_child_session_paths[thread_id] = found
|
|
752
1000
|
self._claude_child_session_files = self._find_claude_child_session_files()
|
|
1001
|
+
self._cb_child_session_files = self._find_cb_child_session_files()
|
|
753
1002
|
self._last_child_scan_at = now
|
|
754
1003
|
|
|
755
1004
|
files = []
|
|
@@ -788,6 +1037,14 @@ class ProgressTracker:
|
|
|
788
1037
|
for path in self._claude_child_session_files:
|
|
789
1038
|
add_file("claude", path.stem, path)
|
|
790
1039
|
|
|
1040
|
+
for path in self._cb_child_session_files:
|
|
1041
|
+
# Identifier for CodeBuddy sub-agent files: use the parent
|
|
1042
|
+
# directory name (agent-{id}) so heartbeat can distinguish
|
|
1043
|
+
# activity across different sub-agent instances.
|
|
1044
|
+
parent_name = path.parent.name if hasattr(path, "parent") else ""
|
|
1045
|
+
identifier = parent_name if parent_name.startswith("agent-") else path.name
|
|
1046
|
+
add_file("codebuddy", identifier, path)
|
|
1047
|
+
|
|
791
1048
|
self.child_session_files = files
|
|
792
1049
|
self.child_total_bytes = total_bytes
|
|
793
1050
|
self.child_activity_signature = "|".join(signature_parts)
|
|
@@ -823,11 +1080,14 @@ class ProgressTracker:
|
|
|
823
1080
|
"total_tool_calls": self.total_tool_calls,
|
|
824
1081
|
"active_subagent_count": self.active_subagent_count,
|
|
825
1082
|
"subagent_states": subagent_states,
|
|
1083
|
+
"subagent_spawn_count": self._subagent_spawn_count,
|
|
826
1084
|
"child_thread_ids": sorted(self.codex_child_thread_ids),
|
|
827
1085
|
"child_session_files": self.child_session_files,
|
|
828
1086
|
"child_total_bytes": self.child_total_bytes,
|
|
829
1087
|
"child_activity_signature": self.child_activity_signature,
|
|
830
1088
|
"last_child_activity_at": self.last_child_activity_at,
|
|
1089
|
+
"cb_session_id": self.cb_session_id,
|
|
1090
|
+
"cb_cwd": self.cb_cwd,
|
|
831
1091
|
"last_text_snippet": self.last_text_snippet,
|
|
832
1092
|
"last_result_is_error": self.last_result_is_error,
|
|
833
1093
|
"api_error_status": self.api_error_status,
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
"Read {{DEV_SUBAGENT_PATH}}. Implement feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}).
|
|
2
2
|
|
|
3
|
+
## Task Summary Card
|
|
4
|
+
|
|
5
|
+
**Objective**: Implement {{FEATURE_TITLE}}.
|
|
6
|
+
|
|
7
|
+
**Primary files** (see context-snapshot.md Section 4 for full manifest):
|
|
8
|
+
- Review plan.md Tasks section for the complete task-to-file mapping.
|
|
9
|
+
- Each task's `— file:` suffix identifies the target file.
|
|
10
|
+
|
|
11
|
+
**Test command**: `{{TEST_CMD}}`
|
|
12
|
+
|
|
13
|
+
**Known baseline failures**: `{{BASELINE_FAILURES}}`
|
|
14
|
+
|
|
15
|
+
**DO NOT**:
|
|
16
|
+
- Re-read source files already listed in context-snapshot.md Section 4 File Manifest
|
|
17
|
+
- Create new files unless a plan.md task explicitly requires it
|
|
18
|
+
- Run git commands
|
|
19
|
+
- Use mock success data or fake rows in UI/tests
|
|
20
|
+
|
|
3
21
|
## Required Inputs
|
|
4
22
|
|
|
5
23
|
1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` first.
|
|
@@ -35,6 +53,9 @@ Before returning, append `## Implementation Log` to `context-snapshot.md` with:
|
|
|
35
53
|
- Carry forward the Dev-isolated subset: skip scaffold/generated files listed in `context-snapshot.md`; verify dependency versions before install/build commands that resolve dependencies; after build/compile commands, ensure outputs are ignored and never commit generated artifacts.
|
|
36
54
|
- If tests fail, follow this Test Failure Recovery subset: classify failures as baseline, new regression, brittle test, or environment/tooling; fix new regressions and brittle tests while progress is being made; document baseline failures; write `failure-log.md` for blockers.
|
|
37
55
|
- Do not run git commands; staging and commit are handled by the orchestrator.
|
|
56
|
+
- **Edit safety**: If an Edit fails with 'String to replace not found', use Select-String or a targeted Read to find the target text before retrying. Never guess file offsets — verify them first.
|
|
57
|
+
- **Read safety**: If 3 consecutive Reads to the same file return 'shorter than offset' or 'Wasted call', STOP and report BLOCKED.
|
|
58
|
+
- **Test early**: Run `{{TEST_CMD}}` after every 3 successful Edit operations. Capture output with `Tee-Object (Join-Path $env:TEMP "test-out.txt")` and use Select-String for failures.
|
|
38
59
|
|
|
39
60
|
Do not return success unless:
|
|
40
61
|
1. implementation tasks are complete;
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/spec.md` (if it exists) for goals and Verification Gates; if spec.md does not exist, read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` Section 1 Task Contract instead
|
|
3
3
|
2. Read `.prizmkit/specs/{{FEATURE_SLUG}}/plan.md` for architecture decisions and completed tasks
|
|
4
4
|
3. Run /prizmkit-code-review with artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/. The skill will run its internal review-fix loop (Reviewer → filter → Dev fix, max 3 rounds) and write review-report.md.
|
|
5
|
-
4. Run the full test suite using `{{TEST_CMD}}`. When running tests:
|
|
5
|
+
4. Run the full test suite using `{{TEST_CMD}}`. When running tests: `& { {{TEST_CMD}} } 2>&1 | Tee-Object (Join-Path $env:TEMP "review-test-out.txt") | Select-Object -Last 20`, then Select-String `(Join-Path $env:TEMP "review-test-out.txt")` for details — do NOT re-run the suite multiple times.
|
|
6
6
|
5. review-report.md will be written to .prizmkit/specs/{{FEATURE_SLUG}}/ by prizmkit-code-review.
|
|
7
7
|
Report: verdict (PASS/NEEDS_FIXES), number of rounds, findings fixed/rejected."
|
|
@@ -17,6 +17,12 @@
|
|
|
17
17
|
|
|
18
18
|
{{ACCEPTANCE_CRITERIA}}
|
|
19
19
|
|
|
20
|
+
## Your Mission
|
|
21
|
+
|
|
22
|
+
You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATURE_TITLE}}".
|
|
23
|
+
|
|
24
|
+
**CRITICAL**: You MUST NOT exit until ALL work is complete and committed.
|
|
25
|
+
|
|
20
26
|
## Instructions
|
|
21
27
|
|
|
22
28
|
You are running in **headless non-interactive mode** — no human is available for input.
|
|
@@ -44,3 +50,24 @@ Infer what needs to be done from the feature context above and follow the standa
|
|
|
44
50
|
- Do NOT push to remote — the user will push manually.
|
|
45
51
|
- Write all artifacts to `.prizmkit/specs/{{FEATURE_SLUG}}/`.
|
|
46
52
|
- If a step fails after 3 attempts, write a status report and stop.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Failure Capture Protocol
|
|
56
|
+
|
|
57
|
+
If you encounter an unrecoverable error, context overflow, or are about to exit without completing all steps:
|
|
58
|
+
|
|
59
|
+
1. Write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` BEFORE exiting:
|
|
60
|
+
```
|
|
61
|
+
FAILURE_TYPE: timeout | test_failure | review_rejected | context_overflow | unknown
|
|
62
|
+
PHASE: <failed phase>
|
|
63
|
+
ROOT_CAUSE: <1-2 sentence explanation>
|
|
64
|
+
ATTEMPTED: <approaches already tried>
|
|
65
|
+
SUGGESTION: <what the next session should try differently>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
2. This file is intentionally lightweight — write it BEFORE context runs out.
|
|
69
|
+
|
|
70
|
+
After a successful session (all steps complete + commit done), delete it:
|
|
71
|
+
```powershell
|
|
72
|
+
Remove-Item -Force -ErrorAction SilentlyContinue .prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md
|
|
73
|
+
```
|