superpower_setup 1.0.0
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/README.md +77 -0
- package/bin/cli.js +91 -0
- package/package.json +24 -0
- package/src/index.js +261 -0
- package/src/utils.js +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# superpower_setup
|
|
2
|
+
|
|
3
|
+
CLI tool để cài đặt [obra/superpowers](https://github.com/obra/superpowers) vào project Google Antigravity.
|
|
4
|
+
|
|
5
|
+
## Cài đặt & Sử dụng
|
|
6
|
+
|
|
7
|
+
### Cài đặt superpowers vào project
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx superpower_setup init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Cập nhật superpowers lên phiên bản mới nhất
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx superpower_setup update
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Options
|
|
20
|
+
|
|
21
|
+
| Option | Mô tả | Mặc định |
|
|
22
|
+
|--------|--------|----------|
|
|
23
|
+
| `--target <path>` | Thư mục đích | Thư mục hiện tại |
|
|
24
|
+
| `--branch <name>` | Branch của repo superpowers | `main` |
|
|
25
|
+
| `--force` | Ghi đè files đã tồn tại | `false` |
|
|
26
|
+
|
|
27
|
+
### Ví dụ
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Cài đặt vào project hiện tại
|
|
31
|
+
npx superpower_setup init
|
|
32
|
+
|
|
33
|
+
# Cài đặt vào thư mục khác
|
|
34
|
+
npx superpower_setup init --target /path/to/project
|
|
35
|
+
|
|
36
|
+
# Ghi đè files đã có
|
|
37
|
+
npx superpower_setup init --force
|
|
38
|
+
|
|
39
|
+
# Cài đặt từ branch khác
|
|
40
|
+
npx superpower_setup init --branch develop
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Cấu trúc sau khi cài đặt
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
project-root/
|
|
47
|
+
├── .agents/
|
|
48
|
+
│ ├── skills/superpowers/ # 14 skills
|
|
49
|
+
│ ├── agents/superpowers/ # Agent definitions
|
|
50
|
+
│ ├── commands/superpowers/ # Custom commands
|
|
51
|
+
│ └── hooks/superpowers/ # Session hooks
|
|
52
|
+
├── GEMINI.md # Context file (tham chiếu skills)
|
|
53
|
+
└── gemini-extension.json # Extension config
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Skills đi kèm
|
|
57
|
+
|
|
58
|
+
| Skill | Mô tả |
|
|
59
|
+
|-------|--------|
|
|
60
|
+
| **brainstorming** | Socratic design refinement |
|
|
61
|
+
| **test-driven-development** | RED-GREEN-REFACTOR cycle |
|
|
62
|
+
| **systematic-debugging** | 4-phase root cause process |
|
|
63
|
+
| **writing-plans** | Detailed implementation plans |
|
|
64
|
+
| **executing-plans** | Batch execution with checkpoints |
|
|
65
|
+
| **subagent-driven-development** | Fast iteration with two-stage review |
|
|
66
|
+
| **using-git-worktrees** | Parallel development branches |
|
|
67
|
+
| **requesting-code-review** | Pre-review checklist |
|
|
68
|
+
| **receiving-code-review** | Responding to feedback |
|
|
69
|
+
| **finishing-a-development-branch** | Merge/PR decision workflow |
|
|
70
|
+
| **verification-before-completion** | Ensure it's actually fixed |
|
|
71
|
+
| **dispatching-parallel-agents** | Concurrent subagent workflows |
|
|
72
|
+
| **writing-skills** | Create new skills |
|
|
73
|
+
| **using-superpowers** | Introduction to the skills system |
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { runInit } from "../src/index.js";
|
|
5
|
+
import { logInfo, logError, LOG_COLORS } from "../src/utils.js";
|
|
6
|
+
|
|
7
|
+
const PACKAGE_VERSION = "1.0.0";
|
|
8
|
+
|
|
9
|
+
const HELP_TEXT = `
|
|
10
|
+
${LOG_COLORS.cyan}superpower_setup${LOG_COLORS.reset} - Cài đặt obra/superpowers vào Google Antigravity project
|
|
11
|
+
|
|
12
|
+
${LOG_COLORS.yellow}Usage:${LOG_COLORS.reset}
|
|
13
|
+
npx superpower_setup init [options] Tải và cài đặt superpowers skills
|
|
14
|
+
npx superpower_setup update [options] Cập nhật superpowers lên phiên bản mới nhất
|
|
15
|
+
npx superpower_setup --help Hiển thị help
|
|
16
|
+
npx superpower_setup --version Hiển thị version
|
|
17
|
+
|
|
18
|
+
${LOG_COLORS.yellow}Options:${LOG_COLORS.reset}
|
|
19
|
+
--target <path> Thư mục đích (mặc định: thư mục hiện tại)
|
|
20
|
+
--branch <name> Branch của repo superpowers (mặc định: main)
|
|
21
|
+
--force Ghi đè files đã tồn tại
|
|
22
|
+
--help, -h Hiển thị help
|
|
23
|
+
--version, -v Hiển thị version
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
function main() {
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
const command = args[0];
|
|
29
|
+
|
|
30
|
+
if (!command || command === "--help" || command === "-h") {
|
|
31
|
+
console.log(HELP_TEXT);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (command === "--version" || command === "-v") {
|
|
36
|
+
console.log(`superpower_setup v${PACKAGE_VERSION}`);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const command_args = args.slice(1);
|
|
41
|
+
|
|
42
|
+
let parsed_options;
|
|
43
|
+
try {
|
|
44
|
+
const { values } = parseArgs({
|
|
45
|
+
args: command_args,
|
|
46
|
+
options: {
|
|
47
|
+
target: { type: "string", default: process.cwd() },
|
|
48
|
+
branch: { type: "string", default: "main" },
|
|
49
|
+
force: { type: "boolean", default: false },
|
|
50
|
+
help: { type: "boolean", short: "h", default: false },
|
|
51
|
+
},
|
|
52
|
+
allowPositionals: true,
|
|
53
|
+
});
|
|
54
|
+
parsed_options = values;
|
|
55
|
+
} catch (err) {
|
|
56
|
+
logError(`Lỗi parse arguments: ${err.message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (parsed_options.help) {
|
|
61
|
+
console.log(HELP_TEXT);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
switch (command) {
|
|
66
|
+
case "init":
|
|
67
|
+
runInit({
|
|
68
|
+
target_dir: parsed_options.target,
|
|
69
|
+
branch: parsed_options.branch,
|
|
70
|
+
is_force: parsed_options.force,
|
|
71
|
+
is_update: false,
|
|
72
|
+
});
|
|
73
|
+
break;
|
|
74
|
+
|
|
75
|
+
case "update":
|
|
76
|
+
runInit({
|
|
77
|
+
target_dir: parsed_options.target,
|
|
78
|
+
branch: parsed_options.branch,
|
|
79
|
+
is_force: true,
|
|
80
|
+
is_update: true,
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
|
|
84
|
+
default:
|
|
85
|
+
logError(`Lệnh không hợp lệ: "${command}"`);
|
|
86
|
+
logInfo('Chạy "npx superpower_setup --help" để xem hướng dẫn.');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "superpower_setup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to install obra/superpowers skills into Google Antigravity projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"superpower_setup": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"superpowers",
|
|
16
|
+
"gemini",
|
|
17
|
+
"antigravity",
|
|
18
|
+
"ai",
|
|
19
|
+
"skills",
|
|
20
|
+
"coding-agent"
|
|
21
|
+
],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "MIT"
|
|
24
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { randomBytes } from "node:crypto";
|
|
5
|
+
import {
|
|
6
|
+
logInfo,
|
|
7
|
+
logSuccess,
|
|
8
|
+
logWarning,
|
|
9
|
+
logError,
|
|
10
|
+
logStep,
|
|
11
|
+
ensureDir,
|
|
12
|
+
copyDirRecursive,
|
|
13
|
+
cleanUp,
|
|
14
|
+
checkGitInstalled,
|
|
15
|
+
cloneRepo,
|
|
16
|
+
LOG_COLORS,
|
|
17
|
+
} from "./utils.js";
|
|
18
|
+
|
|
19
|
+
const REPO_URL = "https://github.com/obra/superpowers.git";
|
|
20
|
+
const TOTAL_STEPS = 5;
|
|
21
|
+
|
|
22
|
+
// Các thư mục/files cần copy từ repo superpowers
|
|
23
|
+
// Theo docs Antigravity: skills đặt trong .agents/skills/<skill-folder>/ (workspace-specific)
|
|
24
|
+
// Ref: https://antigravity.google/docs/skills
|
|
25
|
+
const COPY_MAP = [
|
|
26
|
+
{ source: "skills", dest_sub: join(".agents", "skills", "superpowers"), type: "dir" },
|
|
27
|
+
{ source: "agents", dest_sub: join(".agents", "agents", "superpowers"), type: "dir" },
|
|
28
|
+
{ source: "commands", dest_sub: join(".agents", "commands", "superpowers"), type: "dir" },
|
|
29
|
+
{ source: "hooks", dest_sub: join(".agents", "hooks", "superpowers"), type: "dir" },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Tạo nội dung GEMINI.md cho project đích
|
|
34
|
+
* References đến tất cả skills đã cài đặt
|
|
35
|
+
*/
|
|
36
|
+
function buildGeminiMdContent(skills_dir) {
|
|
37
|
+
const lines = [
|
|
38
|
+
"# Superpowers Skills",
|
|
39
|
+
"",
|
|
40
|
+
"<!-- Auto-generated by superpower_setup. Do not edit this section manually. -->",
|
|
41
|
+
"",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
// Tham chiếu đến skills theo cấu trúc Antigravity (.agents/skills/)
|
|
45
|
+
lines.push("@./.agents/skills/superpowers/using-superpowers/SKILL.md");
|
|
46
|
+
lines.push("@./.agents/skills/superpowers/using-superpowers/references/gemini-tools.md");
|
|
47
|
+
lines.push("");
|
|
48
|
+
|
|
49
|
+
return lines.join("\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Cập nhật hoặc tạo GEMINI.md ở root project
|
|
54
|
+
*/
|
|
55
|
+
function setupGeminiMd(target_dir, is_force) {
|
|
56
|
+
const gemini_md_path = join(target_dir, "GEMINI.md");
|
|
57
|
+
const superpowers_content = buildGeminiMdContent(target_dir);
|
|
58
|
+
const MARKER_START = "<!-- SUPERPOWERS_START -->";
|
|
59
|
+
const MARKER_END = "<!-- SUPERPOWERS_END -->";
|
|
60
|
+
const wrapped_content = `${MARKER_START}\n${superpowers_content}\n${MARKER_END}`;
|
|
61
|
+
|
|
62
|
+
if (existsSync(gemini_md_path)) {
|
|
63
|
+
const existing_content = readFileSync(gemini_md_path, "utf-8");
|
|
64
|
+
|
|
65
|
+
// Kiểm tra xem đã có section superpowers chưa
|
|
66
|
+
if (existing_content.includes(MARKER_START)) {
|
|
67
|
+
if (!is_force) {
|
|
68
|
+
logWarning("GEMINI.md đã chứa cấu hình superpowers. Dùng --force để ghi đè.");
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// Replace section cũ
|
|
72
|
+
const regex = new RegExp(
|
|
73
|
+
`${escapeRegex(MARKER_START)}[\\s\\S]*?${escapeRegex(MARKER_END)}`,
|
|
74
|
+
"g"
|
|
75
|
+
);
|
|
76
|
+
const updated_content = existing_content.replace(regex, wrapped_content);
|
|
77
|
+
writeFileSync(gemini_md_path, updated_content, "utf-8");
|
|
78
|
+
logSuccess("Đã cập nhật section superpowers trong GEMINI.md");
|
|
79
|
+
} else {
|
|
80
|
+
// Append vào cuối file
|
|
81
|
+
const updated_content = `${existing_content}\n\n${wrapped_content}\n`;
|
|
82
|
+
writeFileSync(gemini_md_path, updated_content, "utf-8");
|
|
83
|
+
logSuccess("Đã thêm cấu hình superpowers vào GEMINI.md");
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
writeFileSync(gemini_md_path, `${wrapped_content}\n`, "utf-8");
|
|
87
|
+
logSuccess("Đã tạo GEMINI.md với cấu hình superpowers");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Copy gemini-extension.json vào root project
|
|
95
|
+
*/
|
|
96
|
+
function setupGeminiExtension(repo_dir, target_dir, is_force) {
|
|
97
|
+
const source_path = join(repo_dir, "gemini-extension.json");
|
|
98
|
+
const dest_path = join(target_dir, "gemini-extension.json");
|
|
99
|
+
|
|
100
|
+
if (!existsSync(source_path)) {
|
|
101
|
+
logWarning("Không tìm thấy gemini-extension.json trong repo.");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (existsSync(dest_path) && !is_force) {
|
|
106
|
+
logWarning("gemini-extension.json đã tồn tại. Dùng --force để ghi đè.");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Đọc và chỉnh sửa contextFileName path
|
|
111
|
+
const extension_content = JSON.parse(readFileSync(source_path, "utf-8"));
|
|
112
|
+
extension_content.contextFileName = "GEMINI.md";
|
|
113
|
+
|
|
114
|
+
writeFileSync(dest_path, JSON.stringify(extension_content, null, 2) + "\n", "utf-8");
|
|
115
|
+
logSuccess("Đã copy gemini-extension.json");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Thêm .agents vào .gitignore nếu chưa có
|
|
120
|
+
*/
|
|
121
|
+
function setupGitignore(target_dir) {
|
|
122
|
+
const gitignore_path = join(target_dir, ".gitignore");
|
|
123
|
+
const entry = ".agents";
|
|
124
|
+
|
|
125
|
+
if (existsSync(gitignore_path)) {
|
|
126
|
+
const content = readFileSync(gitignore_path, "utf-8");
|
|
127
|
+
const lines = content.split(/\r?\n/).map((l) => l.trim());
|
|
128
|
+
|
|
129
|
+
if (lines.includes(entry) || lines.includes(entry + "/")) {
|
|
130
|
+
logInfo(".agents đã có trong .gitignore");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Append vào cuối file
|
|
135
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
136
|
+
writeFileSync(gitignore_path, `${content}${separator}\n# Superpowers skills\n${entry}\n`, "utf-8");
|
|
137
|
+
logSuccess("Đã thêm .agents vào .gitignore");
|
|
138
|
+
} else {
|
|
139
|
+
writeFileSync(gitignore_path, `# Superpowers skills\n${entry}\n`, "utf-8");
|
|
140
|
+
logSuccess("Đã tạo .gitignore với .agents");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Escape regex special characters
|
|
146
|
+
*/
|
|
147
|
+
function escapeRegex(str) {
|
|
148
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Main init function
|
|
153
|
+
*/
|
|
154
|
+
export function runInit({ target_dir, branch, is_force, is_update }) {
|
|
155
|
+
const resolved_target = resolve(target_dir);
|
|
156
|
+
const action_name = is_update ? "Cập nhật" : "Cài đặt";
|
|
157
|
+
const temp_dir = join(tmpdir(), `superpower_setup_${randomBytes(6).toString("hex")}`);
|
|
158
|
+
|
|
159
|
+
console.log("");
|
|
160
|
+
console.log(
|
|
161
|
+
`${LOG_COLORS.bold}${LOG_COLORS.magenta}⚡ Superpower Setup${LOG_COLORS.reset} - ${action_name} superpowers skills`
|
|
162
|
+
);
|
|
163
|
+
console.log(`${LOG_COLORS.dim} Target: ${resolved_target}${LOG_COLORS.reset}`);
|
|
164
|
+
console.log(`${LOG_COLORS.dim} Branch: ${branch}${LOG_COLORS.reset}`);
|
|
165
|
+
console.log("");
|
|
166
|
+
|
|
167
|
+
// ── Step 1: Kiểm tra git ──────────────────────────────────────────
|
|
168
|
+
logStep(1, TOTAL_STEPS, "Kiểm tra prerequisites...");
|
|
169
|
+
|
|
170
|
+
if (!checkGitInstalled()) {
|
|
171
|
+
logError("Git chưa được cài đặt. Vui lòng cài đặt git trước.");
|
|
172
|
+
logInfo("Tải git tại: https://git-scm.com/downloads");
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
logSuccess("Git đã sẵn sàng");
|
|
177
|
+
|
|
178
|
+
// ── Step 2: Clone repo ────────────────────────────────────────────
|
|
179
|
+
logStep(2, TOTAL_STEPS, "Tải superpowers từ GitHub...");
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
logInfo(`Cloning ${REPO_URL} (branch: ${branch})...`);
|
|
183
|
+
cloneRepo({ repo_url: REPO_URL, target_dir: temp_dir, branch });
|
|
184
|
+
logSuccess("Đã tải xong repo superpowers");
|
|
185
|
+
} catch (err) {
|
|
186
|
+
logError(`Không thể clone repo: ${err.message}`);
|
|
187
|
+
cleanUp(temp_dir);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ── Step 3: Copy files ────────────────────────────────────────────
|
|
192
|
+
logStep(3, TOTAL_STEPS, "Copy skills, agents, commands, hooks...");
|
|
193
|
+
|
|
194
|
+
let total_files = 0;
|
|
195
|
+
|
|
196
|
+
for (const item of COPY_MAP) {
|
|
197
|
+
const source_path = join(temp_dir, item.source);
|
|
198
|
+
const dest_path = join(resolved_target, item.dest_sub);
|
|
199
|
+
|
|
200
|
+
if (!existsSync(source_path)) {
|
|
201
|
+
logWarning(`Không tìm thấy thư mục: ${item.source}`);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (existsSync(dest_path) && !is_force && !is_update) {
|
|
206
|
+
logWarning(`${item.dest_sub} đã tồn tại. Dùng --force để ghi đè.`);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Xóa thư mục cũ nếu update/force
|
|
211
|
+
if (existsSync(dest_path) && (is_force || is_update)) {
|
|
212
|
+
cleanUp(dest_path);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const count = copyDirRecursive(source_path, dest_path);
|
|
216
|
+
total_files += count;
|
|
217
|
+
logSuccess(`${item.source}/ → ${item.dest_sub} (${count} files)`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
logInfo(`Tổng cộng: ${total_files} files đã được copy`);
|
|
221
|
+
|
|
222
|
+
// ── Step 4: Setup GEMINI.md, gemini-extension.json, .gitignore ────
|
|
223
|
+
logStep(4, TOTAL_STEPS, "Cấu hình GEMINI.md, gemini-extension.json, .gitignore...");
|
|
224
|
+
|
|
225
|
+
setupGeminiMd(resolved_target, is_force || is_update);
|
|
226
|
+
setupGeminiExtension(temp_dir, resolved_target, is_force || is_update);
|
|
227
|
+
setupGitignore(resolved_target);
|
|
228
|
+
|
|
229
|
+
// ── Step 5: Cleanup ───────────────────────────────────────────────
|
|
230
|
+
logStep(5, TOTAL_STEPS, "Dọn dẹp...");
|
|
231
|
+
|
|
232
|
+
cleanUp(temp_dir);
|
|
233
|
+
logSuccess("Đã xóa temp files");
|
|
234
|
+
|
|
235
|
+
// ── Done ──────────────────────────────────────────────────────────
|
|
236
|
+
console.log("");
|
|
237
|
+
console.log(
|
|
238
|
+
`${LOG_COLORS.green}${LOG_COLORS.bold}🎉 ${action_name} superpowers thành công!${LOG_COLORS.reset}`
|
|
239
|
+
);
|
|
240
|
+
console.log("");
|
|
241
|
+
console.log(`${LOG_COLORS.cyan}Các skills đã được cài đặt:${LOG_COLORS.reset}`);
|
|
242
|
+
console.log(" • brainstorming - Socratic design refinement");
|
|
243
|
+
console.log(" • dispatching-parallel-agents - Concurrent subagent workflows");
|
|
244
|
+
console.log(" • executing-plans - Batch execution with checkpoints");
|
|
245
|
+
console.log(" • finishing-a-development-branch - Merge/PR decision workflow");
|
|
246
|
+
console.log(" • receiving-code-review - Responding to feedback");
|
|
247
|
+
console.log(" • requesting-code-review - Pre-review checklist");
|
|
248
|
+
console.log(" • subagent-driven-development - Fast iteration with two-stage review");
|
|
249
|
+
console.log(" • systematic-debugging - 4-phase root cause process");
|
|
250
|
+
console.log(" • test-driven-development - RED-GREEN-REFACTOR cycle");
|
|
251
|
+
console.log(" • using-git-worktrees - Parallel development branches");
|
|
252
|
+
console.log(" • using-superpowers - Introduction to the skills system");
|
|
253
|
+
console.log(" • verification-before-completion - Ensure it's actually fixed");
|
|
254
|
+
console.log(" • writing-plans - Detailed implementation plans");
|
|
255
|
+
console.log(" • writing-skills - Create new skills");
|
|
256
|
+
console.log("");
|
|
257
|
+
console.log(
|
|
258
|
+
`${LOG_COLORS.dim}Chạy "npx superpower_setup update" để cập nhật lên phiên bản mới nhất.${LOG_COLORS.reset}`
|
|
259
|
+
);
|
|
260
|
+
console.log("");
|
|
261
|
+
}
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
|
|
5
|
+
// ─── Console colors ─────────────────────────────────────────────────
|
|
6
|
+
export const LOG_COLORS = {
|
|
7
|
+
reset: "\x1b[0m",
|
|
8
|
+
red: "\x1b[31m",
|
|
9
|
+
green: "\x1b[32m",
|
|
10
|
+
yellow: "\x1b[33m",
|
|
11
|
+
blue: "\x1b[34m",
|
|
12
|
+
magenta: "\x1b[35m",
|
|
13
|
+
cyan: "\x1b[36m",
|
|
14
|
+
dim: "\x1b[2m",
|
|
15
|
+
bold: "\x1b[1m",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// ─── Logging helpers ────────────────────────────────────────────────
|
|
19
|
+
export function logInfo(message) {
|
|
20
|
+
console.log(`${LOG_COLORS.blue}ℹ${LOG_COLORS.reset} ${message}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function logSuccess(message) {
|
|
24
|
+
console.log(`${LOG_COLORS.green}✔${LOG_COLORS.reset} ${message}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function logWarning(message) {
|
|
28
|
+
console.log(`${LOG_COLORS.yellow}⚠${LOG_COLORS.reset} ${message}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function logError(message) {
|
|
32
|
+
console.error(`${LOG_COLORS.red}✖${LOG_COLORS.reset} ${message}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function logStep(step_number, total, message) {
|
|
36
|
+
console.log(
|
|
37
|
+
`\n${LOG_COLORS.cyan}[${step_number}/${total}]${LOG_COLORS.reset} ${LOG_COLORS.bold}${message}${LOG_COLORS.reset}`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─── File system helpers ────────────────────────────────────────────
|
|
42
|
+
export function ensureDir(dir_path) {
|
|
43
|
+
if (!existsSync(dir_path)) {
|
|
44
|
+
mkdirSync(dir_path, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function copyDirRecursive(source, destination) {
|
|
49
|
+
ensureDir(destination);
|
|
50
|
+
|
|
51
|
+
const entries = readdirSync(source);
|
|
52
|
+
let copied_count = 0;
|
|
53
|
+
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const source_path = join(source, entry);
|
|
56
|
+
const dest_path = join(destination, entry);
|
|
57
|
+
const stat = statSync(source_path);
|
|
58
|
+
|
|
59
|
+
if (stat.isDirectory()) {
|
|
60
|
+
copied_count += copyDirRecursive(source_path, dest_path);
|
|
61
|
+
} else {
|
|
62
|
+
copyFileSync(source_path, dest_path);
|
|
63
|
+
copied_count++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return copied_count;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function cleanUp(temp_dir) {
|
|
71
|
+
if (existsSync(temp_dir)) {
|
|
72
|
+
rmSync(temp_dir, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ─── Git helpers ────────────────────────────────────────────────────
|
|
77
|
+
export function checkGitInstalled() {
|
|
78
|
+
try {
|
|
79
|
+
execSync("git --version", { stdio: "pipe" });
|
|
80
|
+
return true;
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function cloneRepo({ repo_url, target_dir, branch }) {
|
|
87
|
+
execSync(
|
|
88
|
+
`git clone --depth 1 --branch ${branch} --single-branch "${repo_url}" "${target_dir}"`,
|
|
89
|
+
{ stdio: "pipe" }
|
|
90
|
+
);
|
|
91
|
+
}
|