prizmkit 1.0.7 → 1.0.9

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.0.7",
3
- "bundledAt": "2026-03-11T16:21:41.120Z",
4
- "bundledFrom": "9678bf1"
2
+ "frameworkVersion": "1.0.9",
3
+ "bundledAt": "2026-03-11T17:48:07.887Z",
4
+ "bundledFrom": "41d8286"
5
5
  }
@@ -14,6 +14,10 @@ set -euo pipefail
14
14
  # ./launch-bugfix-daemon.sh logs [--lines N] [--follow]
15
15
  # ./launch-bugfix-daemon.sh restart [bug-fix-list.json] [--env "KEY=VAL ..."]
16
16
  #
17
+ # NOTE:
18
+ # In AI skill sessions, always use this daemon wrapper.
19
+ # Do NOT call `run-bugfix.sh run ...` directly, because foreground sessions may be killed by CLI timeout.
20
+ #
17
21
  # Files managed:
18
22
  # bugfix-state/.pipeline.pid - PID of the background run-bugfix.sh process
19
23
  # bugfix-state/pipeline-daemon.log - Consolidated stdout+stderr
@@ -14,6 +14,10 @@ set -euo pipefail
14
14
  # ./launch-daemon.sh logs [--lines N] [--follow]
15
15
  # ./launch-daemon.sh restart [feature-list.json] [--env "KEY=VAL ..."]
16
16
  #
17
+ # NOTE:
18
+ # In AI skill sessions, always use this daemon wrapper.
19
+ # Do NOT call `run.sh run ...` directly, because foreground sessions may be killed by CLI timeout.
20
+ #
17
21
  # Files managed:
18
22
  # state/.pipeline.pid - PID of the background run.sh process
19
23
  # state/pipeline-daemon.log - Consolidated stdout+stderr from run.sh
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================
3
+ # dev-pipeline/lib/heartbeat.sh - Shared heartbeat monitoring
4
+ #
5
+ # Provides start_heartbeat / stop_heartbeat functions that read
6
+ # structured progress from progress.json (written by
7
+ # parse-stream-progress.py) and fall back to tail-based monitoring.
8
+ #
9
+ # Usage:
10
+ # source "$SCRIPT_DIR/lib/heartbeat.sh"
11
+ # start_heartbeat "$cli_pid" "$session_log" "$progress_json" "$interval"
12
+ # # ... wait for CLI to finish ...
13
+ # stop_heartbeat "$_HEARTBEAT_PID"
14
+ #
15
+ # Requires: colors (GREEN, YELLOW, BLUE, NC) and log functions
16
+ # to be defined before sourcing.
17
+ # ============================================================
18
+
19
+ # Start a heartbeat monitor in the background.
20
+ # Sets _HEARTBEAT_PID to the background process PID.
21
+ #
22
+ # Arguments:
23
+ # $1 - cli_pid PID of the AI CLI process to monitor
24
+ # $2 - session_log Path to session.log
25
+ # $3 - progress_json Path to progress.json (may not exist if stream-json disabled)
26
+ # $4 - interval Heartbeat interval in seconds
27
+ start_heartbeat() {
28
+ local cli_pid="$1"
29
+ local session_log="$2"
30
+ local progress_json="$3"
31
+ local heartbeat_interval="$4"
32
+
33
+ (
34
+ local elapsed=0
35
+ local prev_size=0
36
+ while kill -0 "$cli_pid" 2>/dev/null; do
37
+ sleep "$heartbeat_interval"
38
+ elapsed=$((elapsed + heartbeat_interval))
39
+ kill -0 "$cli_pid" 2>/dev/null || break
40
+
41
+ # Get log file size
42
+ local cur_size=0
43
+ if [[ -f "$session_log" ]]; then
44
+ cur_size=$(wc -c < "$session_log" 2>/dev/null || echo 0)
45
+ cur_size=$(echo "$cur_size" | tr -d ' ')
46
+ fi
47
+
48
+ local growth=$((cur_size - prev_size))
49
+ prev_size=$cur_size
50
+
51
+ local size_display
52
+ if [[ $cur_size -gt 1048576 ]]; then
53
+ size_display="$((cur_size / 1048576))MB"
54
+ elif [[ $cur_size -gt 1024 ]]; then
55
+ size_display="$((cur_size / 1024))KB"
56
+ else
57
+ size_display="${cur_size}B"
58
+ fi
59
+
60
+ local mins=$((elapsed / 60))
61
+ local secs=$((elapsed % 60))
62
+
63
+ local status_icon
64
+ if [[ $growth -gt 0 ]]; then
65
+ status_icon="${GREEN}▶${NC}"
66
+ else
67
+ status_icon="${YELLOW}⏸${NC}"
68
+ fi
69
+
70
+ # Try structured progress from progress.json
71
+ if [[ -f "$progress_json" ]]; then
72
+ local phase tool msgs tools_total
73
+ phase=$(python3 -c "
74
+ import json, sys
75
+ try:
76
+ with open('$progress_json') as f:
77
+ d = json.load(f)
78
+ parts = []
79
+ if d.get('current_phase'):
80
+ parts.append('phase: ' + d['current_phase'])
81
+ if d.get('current_tool'):
82
+ parts.append('tool: ' + d['current_tool'])
83
+ parts.append('msgs: ' + str(d.get('message_count', 0)))
84
+ parts.append(str(d.get('total_tool_calls', 0)) + ' tool calls')
85
+ print(' | '.join(parts))
86
+ except Exception:
87
+ sys.exit(1)
88
+ " 2>/dev/null) && {
89
+ echo -e " ${status_icon} ${BLUE}[HEARTBEAT]${NC} ${mins}m${secs}s | log: ${size_display} | ${phase}"
90
+ continue
91
+ }
92
+ fi
93
+
94
+ # Fallback: tail-based activity detection
95
+ local last_activity=""
96
+ if [[ -f "$session_log" ]]; then
97
+ last_activity=$(tail -20 "$session_log" 2>/dev/null | grep -v '^$' | tail -1 | cut -c1-80 || echo "")
98
+ fi
99
+
100
+ echo -e " ${status_icon} ${BLUE}[HEARTBEAT]${NC} ${mins}m${secs}s elapsed | log: ${size_display} (+${growth}B) | ${last_activity}"
101
+ done
102
+ ) &
103
+ _HEARTBEAT_PID=$!
104
+ }
105
+
106
+ # Stop a heartbeat monitor process.
107
+ #
108
+ # Arguments:
109
+ # $1 - heartbeat_pid PID returned by start_heartbeat
110
+ stop_heartbeat() {
111
+ local heartbeat_pid="$1"
112
+ if [[ -n "$heartbeat_pid" ]]; then
113
+ kill "$heartbeat_pid" 2>/dev/null || true
114
+ wait "$heartbeat_pid" 2>/dev/null || true
115
+ fi
116
+ }
117
+
118
+ # Start the stream-json progress parser as a background process.
119
+ # Sets _PARSER_PID to the background process PID.
120
+ # No-op if USE_STREAM_JSON is not "true".
121
+ #
122
+ # Arguments:
123
+ # $1 - session_log Path to session.log
124
+ # $2 - progress_json Path to write progress.json
125
+ # $3 - scripts_dir Path to scripts/ directory
126
+ start_progress_parser() {
127
+ local session_log="$1"
128
+ local progress_json="$2"
129
+ local scripts_dir="$3"
130
+
131
+ _PARSER_PID=""
132
+
133
+ if [[ "${USE_STREAM_JSON:-}" != "true" ]]; then
134
+ return 0
135
+ fi
136
+
137
+ local parser_script="$scripts_dir/parse-stream-progress.py"
138
+ if [[ ! -f "$parser_script" ]]; then
139
+ return 0
140
+ fi
141
+
142
+ python3 "$parser_script" \
143
+ --session-log "$session_log" \
144
+ --progress-file "$progress_json" &
145
+ _PARSER_PID=$!
146
+ }
147
+
148
+ # Stop the progress parser process.
149
+ #
150
+ # Arguments:
151
+ # $1 - parser_pid PID returned by start_progress_parser
152
+ stop_progress_parser() {
153
+ local parser_pid="$1"
154
+ if [[ -n "$parser_pid" ]]; then
155
+ kill "$parser_pid" 2>/dev/null || true
156
+ wait "$parser_pid" 2>/dev/null || true
157
+ fi
158
+ }
159
+
160
+ # Detect whether the AI CLI supports --output-format stream-json.
161
+ # Sets USE_STREAM_JSON to "true" or "false".
162
+ #
163
+ # Arguments:
164
+ # $1 - cli_cmd The AI CLI command
165
+ detect_stream_json_support() {
166
+ local cli_cmd="$1"
167
+ USE_STREAM_JSON="false"
168
+
169
+ # Try to detect support via --help output
170
+ if "$cli_cmd" --help 2>&1 | grep -q "stream-json" 2>/dev/null; then
171
+ USE_STREAM_JSON="true"
172
+ fi
173
+ }
@@ -7,6 +7,12 @@ description: "Launch and manage the bugfix pipeline from within a cbc session. S
7
7
 
8
8
  Launch the autonomous bug fix pipeline from within a cbc conversation. The pipeline runs as a fully detached background process -- closing the cbc session does NOT stop the pipeline.
9
9
 
10
+ ### Mandatory Execution Mode (MUST)
11
+
12
+ - Always use daemon mode via `dev-pipeline/launch-bugfix-daemon.sh` for start/stop/status/log actions.
13
+ - NEVER run `dev-pipeline/run-bugfix.sh run ...` directly from this skill.
14
+ - Reason: foreground `run-bugfix.sh` can be terminated by AI CLI command timeout (e.g. cbc 120s), while daemon mode survives session timeout.
15
+
10
16
  ### When to Use
11
17
 
12
18
  **Start bugfix pipeline** -- User says:
@@ -14,7 +20,7 @@ Launch the autonomous bug fix pipeline from within a cbc conversation. The pipel
14
20
  - "start bug fix", "run bug fix", "execute bug list", "begin fixing"
15
21
  - "启动 bug 修复", "开始修复 bug", "运行 bug 修复流水线", "开始修 bug"
16
22
  - "修复所有 bug", "批量修复", "启动修复流水线"
17
- - After bug-planner completes: "go", "start", "fix them", "开始吧", "开始修复"
23
+ - After bug-planner completes: "fix them", "开始修复"
18
24
 
19
25
  **Check status** -- User says:
20
26
  - "bugfix status", "check bug fixes", "how's the fixing going", "bug fix progress"
@@ -7,6 +7,12 @@ description: "Launch and manage the dev-pipeline from within a cbc session. Star
7
7
 
8
8
  Launch the autonomous development pipeline from within a cbc conversation. The pipeline runs as a fully detached background process -- closing the cbc session does NOT stop the pipeline.
9
9
 
10
+ ### Mandatory Execution Mode (MUST)
11
+
12
+ - Always use daemon mode via `dev-pipeline/launch-daemon.sh` for start/stop/status/log actions.
13
+ - NEVER run `dev-pipeline/run.sh run ...` directly from this skill.
14
+ - Reason: foreground `run.sh` can be terminated by AI CLI command timeout (e.g. cbc 120s), while daemon mode survives session timeout.
15
+
10
16
  ### When to Use
11
17
 
12
18
  **Start pipeline** -- User says:
@@ -14,7 +20,7 @@ Launch the autonomous development pipeline from within a cbc conversation. The p
14
20
  - "run the features", "execute feature list", "start implementing"
15
21
  - "启动流水线", "开始实现", "运行流水线", "开始自动开发"
16
22
  - "实现接下来的步骤", "执行 feature list", "开始构建"
17
- - After app-planner completes: "go", "start", "build it", "开始吧"
23
+ - After app-planner completes: "build it", " feature list 开始开发"
18
24
 
19
25
  **Check status** -- User says:
20
26
  - "pipeline status", "check pipeline", "how's it going", "progress"
@@ -28,6 +34,10 @@ Launch the autonomous development pipeline from within a cbc conversation. The p
28
34
  - "show logs", "pipeline logs", "tail logs", "what's happening"
29
35
  - "查看日志", "流水线日志", "看看日志"
30
36
 
37
+ **Retry single feature node** -- User says:
38
+ - "retry F-003", "retry this feature", "retry this node"
39
+ - "重试 F-003", "重试这个节点", "重跑这个 feature"
40
+
31
41
  **Do NOT use this skill when:**
32
42
  - User wants to plan features (use `app-planner` instead)
33
43
  - User wants to implement a single feature manually within current session (use `prizmkit-implement`)
@@ -201,6 +211,26 @@ Pass via `--env`:
201
211
  dev-pipeline/launch-daemon.sh start feature-list.json --env "SESSION_TIMEOUT=7200 MAX_RETRIES=5 VERBOSE=1"
202
212
  ```
203
213
 
214
+ ---
215
+
216
+ #### Intent F: Retry Single Feature Node
217
+
218
+ When user says "retry F-003" or "重试 F-003":
219
+
220
+ ```bash
221
+ dev-pipeline/retry-feature.sh F-003 feature-list.json
222
+ ```
223
+
224
+ When user says "从头重试 F-003" or "clean retry F-003":
225
+
226
+ ```bash
227
+ dev-pipeline/reset-feature.sh F-003 --clean --run feature-list.json
228
+ ```
229
+
230
+ Notes:
231
+ - `retry-feature.sh` runs exactly one feature session and exits.
232
+ - Keep pipeline daemon mode for main run management (`launch-daemon.sh`).
233
+
204
234
  ### Error Handling
205
235
 
206
236
  | Error | Action |
@@ -211,7 +241,7 @@ dev-pipeline/launch-daemon.sh start feature-list.json --env "SESSION_TIMEOUT=720
211
241
  | Pipeline already running | Show status, ask if user wants to stop and restart |
212
242
  | PID file stale (process dead) | `launch-daemon.sh` auto-cleans, retry start |
213
243
  | Launch failed (process died immediately) | Show last 20 lines of log: `tail -20 dev-pipeline/state/pipeline-daemon.log` |
214
- | All features blocked/failed | Show status, suggest resetting failed features: `dev-pipeline/run.sh run <F-XXX> --clean` |
244
+ | All features blocked/failed | Show status, suggest daemon-safe recovery: `dev-pipeline/reset-feature.sh <F-XXX> --clean --run feature-list.json` |
215
245
  | Permission denied on script | Run `chmod +x dev-pipeline/launch-daemon.sh dev-pipeline/run.sh` |
216
246
 
217
247
  ### Integration Notes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/scaffold.js CHANGED
@@ -435,7 +435,7 @@ async function installPipeline(projectRoot, dryRun) {
435
435
  const items = [
436
436
  'run.sh', 'retry-feature.sh', 'reset-feature.sh', 'launch-daemon.sh',
437
437
  'run-bugfix.sh', 'retry-bug.sh', 'launch-bugfix-daemon.sh',
438
- 'scripts', 'templates', 'assets', 'README.md', '.gitignore',
438
+ 'lib', 'scripts', 'templates', 'assets', 'README.md', '.gitignore',
439
439
  ];
440
440
 
441
441
  let installedCount = 0;