prizmkit 1.0.136 → 1.0.138
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/dev-pipeline/lib/common.sh +12 -7
- package/bundled/dev-pipeline/run-bugfix.sh +7 -0
- package/bundled/dev-pipeline/run.sh +33 -2
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +12 -0
- package/bundled/skills/_metadata.json +1 -1
- package/package.json +1 -1
- package/src/manifest.js +5 -1
- package/src/scaffold.js +40 -10
- package/src/upgrade.js +25 -3
package/bundled/VERSION.json
CHANGED
|
@@ -90,22 +90,27 @@ except: pass
|
|
|
90
90
|
|
|
91
91
|
# prizm_detect_subagents <session_log>
|
|
92
92
|
#
|
|
93
|
-
# Scan session log for subagent spawns and log the result.
|
|
94
|
-
#
|
|
93
|
+
# Scan session log for subagent spawns, count them, and log the result.
|
|
94
|
+
# Sets _SUBAGENT_COUNT to the number of Agent tool calls detected.
|
|
95
95
|
# Requires: USE_STREAM_JSON (from detect_stream_json_support)
|
|
96
|
+
_SUBAGENT_COUNT=0
|
|
96
97
|
prizm_detect_subagents() {
|
|
97
98
|
local session_log="$1"
|
|
99
|
+
_SUBAGENT_COUNT=0
|
|
98
100
|
[[ -f "$session_log" ]] || return 0
|
|
99
101
|
|
|
100
|
-
local
|
|
102
|
+
local count=0
|
|
101
103
|
if [[ "$USE_STREAM_JSON" == "true" ]]; then
|
|
102
|
-
grep -
|
|
104
|
+
count=$(grep -c '"name"[[:space:]]*:[[:space:]]*"Agent"' "$session_log" 2>/dev/null || echo "0")
|
|
103
105
|
else
|
|
104
|
-
grep -
|
|
106
|
+
count=$(grep -cE '(Tool: Agent|"tool":\s*"Agent"|tool_use.*Agent|subagent_type)' "$session_log" 2>/dev/null || echo "0")
|
|
105
107
|
fi
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
_SUBAGENT_COUNT=$count
|
|
110
|
+
if [[ "$count" -gt 0 ]]; then
|
|
111
|
+
log_info "Subagent calls detected in session: $count"
|
|
112
|
+
else
|
|
113
|
+
log_info "Subagent calls detected in session: 0 (single-agent mode)"
|
|
109
114
|
fi
|
|
110
115
|
}
|
|
111
116
|
|
|
@@ -599,6 +599,7 @@ main() {
|
|
|
599
599
|
fi
|
|
600
600
|
|
|
601
601
|
local session_count=0
|
|
602
|
+
local total_subagent_calls=0
|
|
602
603
|
|
|
603
604
|
while true; do
|
|
604
605
|
# Find next bug to process
|
|
@@ -614,6 +615,7 @@ main() {
|
|
|
614
615
|
log_success "════════════════════════════════════════════════════"
|
|
615
616
|
log_success " All bugs processed! Bug fix pipeline finished."
|
|
616
617
|
log_success " Total sessions: $session_count"
|
|
618
|
+
log_success " Total subagent calls: $total_subagent_calls"
|
|
617
619
|
log_success "════════════════════════════════════════════════════"
|
|
618
620
|
|
|
619
621
|
# Merge dev branch back to original
|
|
@@ -672,6 +674,10 @@ main() {
|
|
|
672
674
|
--state-dir "$STATE_DIR" \
|
|
673
675
|
--output "$bootstrap_prompt" >/dev/null 2>&1
|
|
674
676
|
|
|
677
|
+
# Log agent configuration (bugfix always uses dual-agent: Orchestrator + Dev + Reviewer)
|
|
678
|
+
log_info "Pipeline mode: ${BOLD}standard${NC} (Dual Agent — Orchestrator + Dev + Reviewer)"
|
|
679
|
+
log_info "Agents: 3 (critic: disabled)"
|
|
680
|
+
|
|
675
681
|
# Spawn session
|
|
676
682
|
log_info "Spawning AI CLI session: $session_id"
|
|
677
683
|
_SPAWN_RESULT=""
|
|
@@ -681,6 +687,7 @@ main() {
|
|
|
681
687
|
"$bootstrap_prompt" "$session_dir" "$MAX_RETRIES" "$_ORIGINAL_BRANCH"
|
|
682
688
|
|
|
683
689
|
session_count=$((session_count + 1))
|
|
690
|
+
total_subagent_calls=$((total_subagent_calls + _SUBAGENT_COUNT))
|
|
684
691
|
|
|
685
692
|
log_info "Pausing 5s before next bug..."
|
|
686
693
|
sleep 5
|
|
@@ -647,8 +647,11 @@ sys.exit(1)
|
|
|
647
647
|
log_error "Failed to generate bootstrap prompt for $feature_id"
|
|
648
648
|
return 1
|
|
649
649
|
}
|
|
650
|
-
local feature_model
|
|
650
|
+
local feature_model pipeline_mode agent_count critic_enabled
|
|
651
651
|
feature_model=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
|
|
652
|
+
pipeline_mode=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('pipeline_mode','lite'))" 2>/dev/null || echo "lite")
|
|
653
|
+
agent_count=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('agent_count',1))" 2>/dev/null || echo "1")
|
|
654
|
+
critic_enabled=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('critic_enabled','false'))" 2>/dev/null || echo "false")
|
|
652
655
|
|
|
653
656
|
# Dry-Run: Print info and exit
|
|
654
657
|
if [[ "$dry_run" == true ]]; then
|
|
@@ -664,6 +667,8 @@ sys.exit(1)
|
|
|
664
667
|
else
|
|
665
668
|
log_info "Mode: auto-detect (from complexity)"
|
|
666
669
|
fi
|
|
670
|
+
log_info "Pipeline mode: $pipeline_mode"
|
|
671
|
+
log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
|
|
667
672
|
if [[ -n "$feature_model" ]]; then
|
|
668
673
|
log_info "Feature Model: $feature_model"
|
|
669
674
|
elif [[ -n "${MODEL:-}" ]]; then
|
|
@@ -707,6 +712,15 @@ sys.exit(1)
|
|
|
707
712
|
if [[ -n "$mode_override" ]]; then
|
|
708
713
|
log_info "Mode Override: $mode_override"
|
|
709
714
|
fi
|
|
715
|
+
local _run_one_mode_desc
|
|
716
|
+
case "$pipeline_mode" in
|
|
717
|
+
lite) _run_one_mode_desc="Tier 1 — Single Agent" ;;
|
|
718
|
+
standard) _run_one_mode_desc="Tier 2 — Orchestrator + Dev + Reviewer" ;;
|
|
719
|
+
full) _run_one_mode_desc="Tier 3 — Full Team (+ Multi-Critic)" ;;
|
|
720
|
+
*) _run_one_mode_desc="$pipeline_mode" ;;
|
|
721
|
+
esac
|
|
722
|
+
log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_run_one_mode_desc)"
|
|
723
|
+
log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
|
|
710
724
|
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
711
725
|
log_info "Session timeout: ${SESSION_TIMEOUT}s"
|
|
712
726
|
else
|
|
@@ -881,6 +895,7 @@ main() {
|
|
|
881
895
|
|
|
882
896
|
# Main processing loop
|
|
883
897
|
local session_count=0
|
|
898
|
+
local total_subagent_calls=0
|
|
884
899
|
|
|
885
900
|
while true; do
|
|
886
901
|
# Check for stuck features
|
|
@@ -923,6 +938,7 @@ for f in data.get('stuck_features', []):
|
|
|
923
938
|
log_success "════════════════════════════════════════════════════"
|
|
924
939
|
log_success " All features completed! Pipeline finished."
|
|
925
940
|
log_success " Total sessions: $session_count"
|
|
941
|
+
log_success " Total subagent calls: $total_subagent_calls"
|
|
926
942
|
log_success "════════════════════════════════════════════════════"
|
|
927
943
|
break
|
|
928
944
|
fi
|
|
@@ -999,8 +1015,22 @@ for f in data.get('stuck_features', []):
|
|
|
999
1015
|
log_error "Failed to generate bootstrap prompt for $feature_id"
|
|
1000
1016
|
continue
|
|
1001
1017
|
}
|
|
1002
|
-
local feature_model
|
|
1018
|
+
local feature_model pipeline_mode agent_count critic_enabled
|
|
1003
1019
|
feature_model=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
|
|
1020
|
+
pipeline_mode=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('pipeline_mode','lite'))" 2>/dev/null || echo "lite")
|
|
1021
|
+
agent_count=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('agent_count',1))" 2>/dev/null || echo "1")
|
|
1022
|
+
critic_enabled=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('critic_enabled','false'))" 2>/dev/null || echo "false")
|
|
1023
|
+
|
|
1024
|
+
# Log pipeline mode and agent configuration
|
|
1025
|
+
local _mode_desc
|
|
1026
|
+
case "$pipeline_mode" in
|
|
1027
|
+
lite) _mode_desc="Tier 1 — Single Agent" ;;
|
|
1028
|
+
standard) _mode_desc="Tier 2 — Orchestrator + Dev + Reviewer" ;;
|
|
1029
|
+
full) _mode_desc="Tier 3 — Full Team (+ Multi-Critic)" ;;
|
|
1030
|
+
*) _mode_desc="$pipeline_mode" ;;
|
|
1031
|
+
esac
|
|
1032
|
+
log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_mode_desc)"
|
|
1033
|
+
log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
|
|
1004
1034
|
|
|
1005
1035
|
# Mark feature as in-progress before spawning session
|
|
1006
1036
|
python3 "$SCRIPTS_DIR/update-feature-status.py" \
|
|
@@ -1042,6 +1072,7 @@ for f in data.get('stuck_features', []):
|
|
|
1042
1072
|
fi
|
|
1043
1073
|
|
|
1044
1074
|
session_count=$((session_count + 1))
|
|
1075
|
+
total_subagent_calls=$((total_subagent_calls + _SUBAGENT_COUNT))
|
|
1045
1076
|
|
|
1046
1077
|
# Brief pause before next iteration
|
|
1047
1078
|
log_info "Pausing 5s before next feature..."
|
|
@@ -723,10 +723,22 @@ def main():
|
|
|
723
723
|
|
|
724
724
|
# Success
|
|
725
725
|
feature_model = feature.get("model", "")
|
|
726
|
+
pipeline_mode = replacements.get("{{PIPELINE_MODE}}", "lite")
|
|
727
|
+
critic_enabled = replacements.get("{{CRITIC_ENABLED}}", "false") == "true"
|
|
728
|
+
# Map mode to agent count for logging
|
|
729
|
+
# lite=1 (single agent), standard/full=3 (orchestrator + dev + reviewer)
|
|
730
|
+
mode_agent_counts = {"lite": 1, "standard": 3, "full": 3}
|
|
731
|
+
agent_count = mode_agent_counts.get(pipeline_mode, 1)
|
|
732
|
+
critic_count_val = int(replacements.get("{{CRITIC_COUNT}}", "1"))
|
|
733
|
+
if critic_enabled:
|
|
734
|
+
agent_count += critic_count_val
|
|
726
735
|
output = {
|
|
727
736
|
"success": True,
|
|
728
737
|
"output_path": os.path.abspath(args.output),
|
|
729
738
|
"model": feature_model,
|
|
739
|
+
"pipeline_mode": pipeline_mode,
|
|
740
|
+
"agent_count": agent_count,
|
|
741
|
+
"critic_enabled": "true" if critic_enabled else "false",
|
|
730
742
|
}
|
|
731
743
|
print(json.dumps(output, indent=2, ensure_ascii=False))
|
|
732
744
|
sys.exit(0)
|
package/package.json
CHANGED
package/src/manifest.js
CHANGED
|
@@ -55,6 +55,7 @@ export async function writeManifest(projectRoot, data) {
|
|
|
55
55
|
* @param {boolean} params.team - whether team config was installed
|
|
56
56
|
* @param {string} [params.aiCli] - AI CLI command
|
|
57
57
|
* @param {string} [params.rulesPreset] - rules preset name
|
|
58
|
+
* @param {string[]} [params.extras] - installed extras (e.g. ['playwright-cli'])
|
|
58
59
|
* @returns {Object} manifest
|
|
59
60
|
*/
|
|
60
61
|
export function buildManifest({
|
|
@@ -68,6 +69,7 @@ export function buildManifest({
|
|
|
68
69
|
team,
|
|
69
70
|
aiCli,
|
|
70
71
|
rulesPreset,
|
|
72
|
+
extras,
|
|
71
73
|
}) {
|
|
72
74
|
const now = new Date().toISOString();
|
|
73
75
|
return {
|
|
@@ -87,6 +89,7 @@ export function buildManifest({
|
|
|
87
89
|
agents: [...agents],
|
|
88
90
|
rules: [...rules],
|
|
89
91
|
pipeline: pipeline ? [...pipeline] : [],
|
|
92
|
+
extras: extras ? [...extras] : [],
|
|
90
93
|
other: [platform === 'claude' ? 'CLAUDE.md' : platform === 'codebuddy' ? 'CODEBUDDY.md' : 'CLAUDE.md'],
|
|
91
94
|
},
|
|
92
95
|
};
|
|
@@ -96,7 +99,7 @@ export function buildManifest({
|
|
|
96
99
|
* Diff two manifests and return added/removed items.
|
|
97
100
|
* @param {Object} oldManifest - previous manifest
|
|
98
101
|
* @param {Object} newManifest - new manifest to compare against
|
|
99
|
-
* @returns {Object} { skills: {added, removed}, agents: {added, removed}, rules: {added, removed} }
|
|
102
|
+
* @returns {Object} { skills: {added, removed}, agents: {added, removed}, rules: {added, removed}, pipeline: {added, removed}, extras: {added, removed} }
|
|
100
103
|
*/
|
|
101
104
|
export function diffManifest(oldManifest, newManifest) {
|
|
102
105
|
function diffArrays(oldArr, newArr) {
|
|
@@ -116,5 +119,6 @@ export function diffManifest(oldManifest, newManifest) {
|
|
|
116
119
|
Array.isArray(oldManifest?.files?.pipeline) ? oldManifest.files.pipeline : [],
|
|
117
120
|
Array.isArray(newManifest?.files?.pipeline) ? newManifest.files.pipeline : [],
|
|
118
121
|
),
|
|
122
|
+
extras: diffArrays(oldManifest?.files?.extras, newManifest?.files?.extras),
|
|
119
123
|
};
|
|
120
124
|
}
|
package/src/scaffold.js
CHANGED
|
@@ -676,6 +676,7 @@ export async function installPipeline(projectRoot, dryRun, { forceOverwrite = fa
|
|
|
676
676
|
*/
|
|
677
677
|
export async function installGitignore(projectRoot, options, dryRun) {
|
|
678
678
|
const targetPath = path.join(projectRoot, '.gitignore');
|
|
679
|
+
const templateContent = generateGitignore({ pipeline: options.pipeline });
|
|
679
680
|
|
|
680
681
|
if (dryRun) {
|
|
681
682
|
console.log(chalk.gray(` [dry-run] .gitignore`));
|
|
@@ -683,12 +684,23 @@ export async function installGitignore(projectRoot, options, dryRun) {
|
|
|
683
684
|
}
|
|
684
685
|
|
|
685
686
|
if (await fs.pathExists(targetPath)) {
|
|
686
|
-
|
|
687
|
-
|
|
687
|
+
// 合并模式:追加缺失条目
|
|
688
|
+
const existing = await fs.readFile(targetPath, 'utf-8');
|
|
689
|
+
const existingLines = new Set(existing.split('\n').map(l => l.trim()));
|
|
690
|
+
const templateLines = templateContent.split('\n').map(l => l.trim()).filter(Boolean);
|
|
691
|
+
const missing = templateLines.filter(line => !existingLines.has(line) && !line.startsWith('#'));
|
|
692
|
+
|
|
693
|
+
if (missing.length > 0) {
|
|
694
|
+
const separator = existing.endsWith('\n') ? '' : '\n';
|
|
695
|
+
const header = existingLines.has('# PrizmKit') ? '' : '# PrizmKit\n';
|
|
696
|
+
await fs.appendFile(targetPath, separator + '\n' + header + missing.join('\n') + '\n');
|
|
697
|
+
console.log(chalk.green(` ✓ .gitignore (added ${missing.length} entries)`));
|
|
698
|
+
} else {
|
|
699
|
+
console.log(chalk.green(' ✓ .gitignore (up-to-date)'));
|
|
700
|
+
}
|
|
688
701
|
} else {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
console.log(chalk.green(` ✓ .gitignore`));
|
|
702
|
+
await fs.writeFile(targetPath, templateContent);
|
|
703
|
+
console.log(chalk.green(' ✓ .gitignore'));
|
|
692
704
|
}
|
|
693
705
|
}
|
|
694
706
|
|
|
@@ -733,6 +745,21 @@ export async function installPlaywrightCli(projectRoot, dryRun) {
|
|
|
733
745
|
}
|
|
734
746
|
}
|
|
735
747
|
|
|
748
|
+
// ============================================================
|
|
749
|
+
// Extras 注册表
|
|
750
|
+
// ============================================================
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* 外部工具注册表。upgrade.js 遍历此表来安装/更新外部工具。
|
|
754
|
+
* 新增工具只需:1) 写 installXxx 函数 2) 加一行到此表
|
|
755
|
+
*/
|
|
756
|
+
export const EXTRAS_REGISTRY = {
|
|
757
|
+
'playwright-cli': {
|
|
758
|
+
label: '浏览器交互工具',
|
|
759
|
+
install: installPlaywrightCli,
|
|
760
|
+
},
|
|
761
|
+
};
|
|
762
|
+
|
|
736
763
|
// ============================================================
|
|
737
764
|
// 主安装函数
|
|
738
765
|
// ============================================================
|
|
@@ -846,9 +873,11 @@ export async function scaffold(config) {
|
|
|
846
873
|
}
|
|
847
874
|
}
|
|
848
875
|
|
|
849
|
-
// 10.
|
|
876
|
+
// 10. Extras (external tools via registry)
|
|
877
|
+
const activeExtras = [];
|
|
850
878
|
if (playwrightCli) {
|
|
851
|
-
|
|
879
|
+
activeExtras.push('playwright-cli');
|
|
880
|
+
console.log(chalk.blue(` ${EXTRAS_REGISTRY['playwright-cli'].label}:`));
|
|
852
881
|
await installPlaywrightCli(projectRoot, dryRun);
|
|
853
882
|
console.log('');
|
|
854
883
|
}
|
|
@@ -866,15 +895,15 @@ export async function scaffold(config) {
|
|
|
866
895
|
}
|
|
867
896
|
}
|
|
868
897
|
|
|
869
|
-
//
|
|
898
|
+
// 12. Git pre-commit hook
|
|
870
899
|
console.log(chalk.blue(' Git Hook:'));
|
|
871
900
|
await installGitHook(projectRoot, dryRun);
|
|
872
901
|
|
|
873
|
-
//
|
|
902
|
+
// 13. PrizmKit scripts (always installed)
|
|
874
903
|
console.log(chalk.blue(' PrizmKit 脚本:'));
|
|
875
904
|
await installPrizmkitScripts(projectRoot, dryRun);
|
|
876
905
|
|
|
877
|
-
//
|
|
906
|
+
// 14. Write installation manifest
|
|
878
907
|
if (!dryRun) {
|
|
879
908
|
const agentsDir = getAgentsDir();
|
|
880
909
|
const agentFileNames = (await fs.readdir(agentsDir)).filter(f => f.endsWith('.md'));
|
|
@@ -894,6 +923,7 @@ export async function scaffold(config) {
|
|
|
894
923
|
team,
|
|
895
924
|
aiCli,
|
|
896
925
|
rulesPreset: rulesPresetName,
|
|
926
|
+
extras: activeExtras,
|
|
897
927
|
});
|
|
898
928
|
await writeManifest(projectRoot, manifest);
|
|
899
929
|
console.log(chalk.green(' ✓ .prizmkit/manifest.json'));
|
package/src/upgrade.js
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
installGitignore,
|
|
31
31
|
installProjectMemory,
|
|
32
32
|
resolvePipelineFileList,
|
|
33
|
+
EXTRAS_REGISTRY,
|
|
33
34
|
} from './scaffold.js';
|
|
34
35
|
|
|
35
36
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -244,6 +245,13 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
244
245
|
// Resolve pipeline file list from source (for manifest diff)
|
|
245
246
|
const newPipelineFiles = pipeline ? resolvePipelineFileList() : [];
|
|
246
247
|
|
|
248
|
+
// Resolve extras: merge old manifest extras + default extras for old manifests without the field
|
|
249
|
+
const extrasToInstall = [...new Set([
|
|
250
|
+
...(oldManifest?.files?.extras || []),
|
|
251
|
+
// Old manifests without extras field: default to all registered extras
|
|
252
|
+
...(!oldManifest?.files?.extras ? Object.keys(EXTRAS_REGISTRY) : []),
|
|
253
|
+
])].filter(name => EXTRAS_REGISTRY[name]); // only keep extras that still exist in registry
|
|
254
|
+
|
|
247
255
|
// 4. Build new manifest and compute diff
|
|
248
256
|
const newManifest = buildManifest({
|
|
249
257
|
version: pkg.version,
|
|
@@ -256,6 +264,7 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
256
264
|
team,
|
|
257
265
|
aiCli,
|
|
258
266
|
rulesPreset,
|
|
267
|
+
extras: extrasToInstall,
|
|
259
268
|
});
|
|
260
269
|
|
|
261
270
|
// Preserve original installedAt
|
|
@@ -263,7 +272,7 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
263
272
|
newManifest.installedAt = oldManifest.installedAt;
|
|
264
273
|
}
|
|
265
274
|
|
|
266
|
-
const diff = oldManifest ? diffManifest(oldManifest, newManifest) : { skills: { added: [], removed: [] }, agents: { added: [], removed: [] }, rules: { added: [], removed: [] }, pipeline: { added: [], removed: [] } };
|
|
275
|
+
const diff = oldManifest ? diffManifest(oldManifest, newManifest) : { skills: { added: [], removed: [] }, agents: { added: [], removed: [] }, rules: { added: [], removed: [] }, pipeline: { added: [], removed: [] }, extras: { added: [], removed: [] } };
|
|
267
276
|
|
|
268
277
|
// 5. Display upgrade summary
|
|
269
278
|
const oldVersion = oldManifest?.version || 'unknown';
|
|
@@ -273,8 +282,8 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
273
282
|
console.log(` Suite: ${suite}`);
|
|
274
283
|
console.log('');
|
|
275
284
|
|
|
276
|
-
const totalAdded = diff.skills.added.length + diff.agents.added.length + diff.rules.added.length + diff.pipeline.added.length;
|
|
277
|
-
const totalRemoved = diff.skills.removed.length + diff.agents.removed.length + diff.rules.removed.length + diff.pipeline.removed.length;
|
|
285
|
+
const totalAdded = diff.skills.added.length + diff.agents.added.length + diff.rules.added.length + diff.pipeline.added.length + diff.extras.added.length;
|
|
286
|
+
const totalRemoved = diff.skills.removed.length + diff.agents.removed.length + diff.rules.removed.length + diff.pipeline.removed.length + diff.extras.removed.length;
|
|
278
287
|
const totalUpdated = newSkillList.length + newAgentFiles.length + newRuleFiles.length;
|
|
279
288
|
|
|
280
289
|
if (diff.skills.added.length) console.log(chalk.green(` + Skills added: ${diff.skills.added.join(', ')}`));
|
|
@@ -285,6 +294,8 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
285
294
|
if (diff.rules.removed.length) console.log(chalk.red(` - Rules removed: ${diff.rules.removed.join(', ')}`));
|
|
286
295
|
if (diff.pipeline.added.length) console.log(chalk.green(` + Pipeline files added: ${diff.pipeline.added.length} file(s)`));
|
|
287
296
|
if (diff.pipeline.removed.length) console.log(chalk.red(` - Pipeline files removed: ${diff.pipeline.removed.length} file(s)`));
|
|
297
|
+
if (diff.extras.added.length) console.log(chalk.green(` + Extras added: ${diff.extras.added.join(', ')}`));
|
|
298
|
+
if (diff.extras.removed.length) console.log(chalk.red(` - Extras removed: ${diff.extras.removed.join(', ')}`));
|
|
288
299
|
|
|
289
300
|
if (totalAdded === 0 && totalRemoved === 0 && oldVersion === pkg.version) {
|
|
290
301
|
console.log(chalk.gray(' No changes detected. Re-installing all files to ensure consistency.'));
|
|
@@ -360,6 +371,17 @@ export async function runUpgrade(directory, options = {}) {
|
|
|
360
371
|
console.log('');
|
|
361
372
|
}
|
|
362
373
|
|
|
374
|
+
// Extras (external tools via registry)
|
|
375
|
+
if (extrasToInstall.length > 0) {
|
|
376
|
+
for (const extraName of extrasToInstall) {
|
|
377
|
+
const entry = EXTRAS_REGISTRY[extraName];
|
|
378
|
+
if (!entry) continue;
|
|
379
|
+
console.log(chalk.blue(` ${entry.label}:`));
|
|
380
|
+
await entry.install(projectRoot, dryRun);
|
|
381
|
+
console.log('');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
363
385
|
// Git hook
|
|
364
386
|
console.log(chalk.blue(' Git Hook:'));
|
|
365
387
|
await installGitHook(projectRoot, dryRun);
|