forgedock 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/LICENSE +244 -0
- package/README.md +251 -0
- package/bin/forgedock.mjs +232 -0
- package/commands/analytics.md +777 -0
- package/commands/audit-agents.md +410 -0
- package/commands/audit.md +410 -0
- package/commands/autopilot.md +432 -0
- package/commands/cleanup.md +264 -0
- package/commands/deploy-info.md +292 -0
- package/commands/failure-recon.md +375 -0
- package/commands/forge-stats.md +183 -0
- package/commands/geo-audit.md +343 -0
- package/commands/incident-response.md +384 -0
- package/commands/issue.md +506 -0
- package/commands/milestone.md +599 -0
- package/commands/orchestrate.md +1044 -0
- package/commands/pipeline-health.md +2343 -0
- package/commands/qa-sweep.md +237 -0
- package/commands/quality-gate.md +777 -0
- package/commands/review-pr-agents.md +1711 -0
- package/commands/review-pr-staging.md +325 -0
- package/commands/review-pr.md +888 -0
- package/commands/rollback.md +253 -0
- package/commands/security-audit.md +529 -0
- package/commands/sync-ecosystem.md +527 -0
- package/commands/validate.md +131 -0
- package/commands/work-on/build/architect.md +291 -0
- package/commands/work-on/build/context.md +349 -0
- package/commands/work-on/build/implement.md +280 -0
- package/commands/work-on/build/validate.md +292 -0
- package/commands/work-on/build.md +262 -0
- package/commands/work-on/close.md +350 -0
- package/commands/work-on/decompose.md +254 -0
- package/commands/work-on/investigate.md +437 -0
- package/commands/work-on/review.md +245 -0
- package/commands/work-on-monolithic.md +298 -0
- package/commands/work-on.md +1089 -0
- package/docs/CODEX.md +92 -0
- package/docs/WORKFLOW.md +104 -0
- package/package.json +45 -0
- package/scripts/verify-env-vars.sh +201 -0
- package/scripts/verify-host-headers.sh +117 -0
- package/scripts/verify-route-registration.sh +118 -0
- package/scripts/verify-sops-chain.sh +163 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname, join, relative } from "path";
|
|
5
|
+
import { mkdir, symlink, readlink, lstat, readdir, stat } from "fs/promises";
|
|
6
|
+
import { existsSync, appendFileSync, readFileSync } from "fs";
|
|
7
|
+
import { execSync } from "child_process";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const FORGE_HOME = dirname(__dirname);
|
|
12
|
+
const COMMANDS_DIR = join(FORGE_HOME, "commands");
|
|
13
|
+
const TARGET_DIR = join(process.env.HOME, ".claude", "commands");
|
|
14
|
+
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
const command = args[0] || "install";
|
|
17
|
+
|
|
18
|
+
const BOLD = "\x1b[1m";
|
|
19
|
+
const GREEN = "\x1b[32m";
|
|
20
|
+
const YELLOW = "\x1b[33m";
|
|
21
|
+
const CYAN = "\x1b[36m";
|
|
22
|
+
const RED = "\x1b[31m";
|
|
23
|
+
const RESET = "\x1b[0m";
|
|
24
|
+
|
|
25
|
+
async function findMarkdownFiles(dir) {
|
|
26
|
+
const results = [];
|
|
27
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const full = join(dir, entry.name);
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
results.push(...(await findMarkdownFiles(full)));
|
|
32
|
+
} else if (entry.name.endsWith(".md")) {
|
|
33
|
+
results.push(full);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return results.sort();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function install() {
|
|
40
|
+
console.log("");
|
|
41
|
+
console.log(`${BOLD}ForgeDock${RESET} — Installing pipeline commands`);
|
|
42
|
+
console.log(` Source: ${CYAN}${COMMANDS_DIR}/${RESET}`);
|
|
43
|
+
console.log(` Target: ${CYAN}${TARGET_DIR}/${RESET}`);
|
|
44
|
+
console.log("");
|
|
45
|
+
|
|
46
|
+
await mkdir(TARGET_DIR, { recursive: true });
|
|
47
|
+
|
|
48
|
+
const files = await findMarkdownFiles(COMMANDS_DIR);
|
|
49
|
+
let installed = 0;
|
|
50
|
+
let updated = 0;
|
|
51
|
+
let skipped = 0;
|
|
52
|
+
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
const rel = relative(COMMANDS_DIR, file);
|
|
55
|
+
const target = join(TARGET_DIR, rel);
|
|
56
|
+
const targetDir = dirname(target);
|
|
57
|
+
|
|
58
|
+
await mkdir(targetDir, { recursive: true });
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const stats = await lstat(target);
|
|
62
|
+
|
|
63
|
+
if (stats.isSymbolicLink()) {
|
|
64
|
+
const current = await readlink(target);
|
|
65
|
+
if (current === file) {
|
|
66
|
+
skipped++;
|
|
67
|
+
} else {
|
|
68
|
+
await symlink(file, target + ".tmp");
|
|
69
|
+
const { rename } = await import("fs/promises");
|
|
70
|
+
await rename(target + ".tmp", target);
|
|
71
|
+
console.log(` ${YELLOW}Updated${RESET}: ${rel}`);
|
|
72
|
+
updated++;
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
console.log(
|
|
76
|
+
` ${YELLOW}WARNING${RESET}: ${rel} is a regular file — skipping (remove it manually to let ForgeDock manage it)`
|
|
77
|
+
);
|
|
78
|
+
skipped++;
|
|
79
|
+
}
|
|
80
|
+
} catch {
|
|
81
|
+
// Doesn't exist — create symlink
|
|
82
|
+
await symlink(file, target);
|
|
83
|
+
console.log(` ${GREEN}Installed${RESET}: ${rel}`);
|
|
84
|
+
installed++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log("");
|
|
89
|
+
console.log(
|
|
90
|
+
`Done. ${GREEN}Installed: ${installed}${RESET}, Updated: ${updated}, Skipped: ${skipped}`
|
|
91
|
+
);
|
|
92
|
+
console.log("");
|
|
93
|
+
|
|
94
|
+
// Set FORGE_HOME in shell profiles
|
|
95
|
+
let profileUpdated = false;
|
|
96
|
+
for (const profile of [
|
|
97
|
+
join(process.env.HOME, ".bashrc"),
|
|
98
|
+
join(process.env.HOME, ".zshrc"),
|
|
99
|
+
]) {
|
|
100
|
+
if (existsSync(profile)) {
|
|
101
|
+
const content = readFileSync(profile, "utf-8");
|
|
102
|
+
if (!content.includes("FORGE_HOME")) {
|
|
103
|
+
appendFileSync(
|
|
104
|
+
profile,
|
|
105
|
+
`\n# ForgeDock — autonomous development pipeline\nexport FORGE_HOME="${FORGE_HOME}"\n`
|
|
106
|
+
);
|
|
107
|
+
console.log(` Added FORGE_HOME to ${profile}`);
|
|
108
|
+
profileUpdated = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(
|
|
114
|
+
`${GREEN}ForgeDock commands are now available as slash commands in any Claude Code session.${RESET}`
|
|
115
|
+
);
|
|
116
|
+
console.log("");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function uninstall() {
|
|
120
|
+
console.log("");
|
|
121
|
+
console.log(`${BOLD}ForgeDock${RESET} — Removing pipeline commands`);
|
|
122
|
+
console.log("");
|
|
123
|
+
|
|
124
|
+
const files = await findMarkdownFiles(COMMANDS_DIR);
|
|
125
|
+
let removed = 0;
|
|
126
|
+
|
|
127
|
+
for (const file of files) {
|
|
128
|
+
const rel = relative(COMMANDS_DIR, file);
|
|
129
|
+
const target = join(TARGET_DIR, rel);
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const stats = await lstat(target);
|
|
133
|
+
if (stats.isSymbolicLink()) {
|
|
134
|
+
const current = await readlink(target);
|
|
135
|
+
if (current === file) {
|
|
136
|
+
const { unlink } = await import("fs/promises");
|
|
137
|
+
await unlink(target);
|
|
138
|
+
console.log(` ${RED}Removed${RESET}: ${rel}`);
|
|
139
|
+
removed++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
// Doesn't exist — nothing to do
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log("");
|
|
148
|
+
console.log(`Done. Removed: ${removed} commands.`);
|
|
149
|
+
console.log("");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function update() {
|
|
153
|
+
console.log("");
|
|
154
|
+
console.log(`${BOLD}ForgeDock${RESET} — Checking for updates`);
|
|
155
|
+
console.log("");
|
|
156
|
+
|
|
157
|
+
// Check if installed via npm (no .git directory) or via git clone
|
|
158
|
+
const gitDir = join(FORGE_HOME, ".git");
|
|
159
|
+
if (existsSync(gitDir)) {
|
|
160
|
+
try {
|
|
161
|
+
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
162
|
+
cwd: FORGE_HOME,
|
|
163
|
+
encoding: "utf-8",
|
|
164
|
+
}).trim();
|
|
165
|
+
if (branch !== "main") {
|
|
166
|
+
console.log(` Not on main branch (${branch}) — skipping`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const before = execSync("git rev-parse HEAD", {
|
|
171
|
+
cwd: FORGE_HOME,
|
|
172
|
+
encoding: "utf-8",
|
|
173
|
+
}).trim();
|
|
174
|
+
execSync("git fetch origin main --quiet", { cwd: FORGE_HOME });
|
|
175
|
+
execSync("git merge --ff-only origin/main --quiet", {
|
|
176
|
+
cwd: FORGE_HOME,
|
|
177
|
+
});
|
|
178
|
+
const after = execSync("git rev-parse HEAD", {
|
|
179
|
+
cwd: FORGE_HOME,
|
|
180
|
+
encoding: "utf-8",
|
|
181
|
+
}).trim();
|
|
182
|
+
|
|
183
|
+
if (before === after) {
|
|
184
|
+
console.log(` Already up to date.`);
|
|
185
|
+
} else {
|
|
186
|
+
console.log(` ${GREEN}Updated to latest.${RESET}`);
|
|
187
|
+
await install();
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
console.log(
|
|
191
|
+
` ${YELLOW}Cannot fast-forward — local changes exist. Skipping.${RESET}`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
console.log(` Installed via npm. Run ${CYAN}npm update -g forgedock${RESET} to update.`);
|
|
196
|
+
}
|
|
197
|
+
console.log("");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function help() {
|
|
201
|
+
console.log("");
|
|
202
|
+
console.log(`${BOLD}ForgeDock${RESET} — GitHub as a knowledge graph for AI agents`);
|
|
203
|
+
console.log("");
|
|
204
|
+
console.log("Usage:");
|
|
205
|
+
console.log(` ${CYAN}npx forgedock${RESET} Install commands (default)`);
|
|
206
|
+
console.log(` ${CYAN}npx forgedock install${RESET} Install commands`);
|
|
207
|
+
console.log(` ${CYAN}npx forgedock uninstall${RESET} Remove commands`);
|
|
208
|
+
console.log(` ${CYAN}npx forgedock update${RESET} Pull latest & reinstall`);
|
|
209
|
+
console.log(` ${CYAN}npx forgedock help${RESET} Show this help`);
|
|
210
|
+
console.log("");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
switch (command) {
|
|
214
|
+
case "install":
|
|
215
|
+
await install();
|
|
216
|
+
break;
|
|
217
|
+
case "uninstall":
|
|
218
|
+
await uninstall();
|
|
219
|
+
break;
|
|
220
|
+
case "update":
|
|
221
|
+
await update();
|
|
222
|
+
break;
|
|
223
|
+
case "help":
|
|
224
|
+
case "--help":
|
|
225
|
+
case "-h":
|
|
226
|
+
help();
|
|
227
|
+
break;
|
|
228
|
+
default:
|
|
229
|
+
console.log(`${RED}Unknown command: ${command}${RESET}`);
|
|
230
|
+
help();
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|