oh-my-customcode 0.9.2 → 0.9.4
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 +25 -30
- package/dist/cli/index.js +1315 -568
- package/dist/index.js +234 -17
- package/package.json +1 -1
- package/templates/.claude/agents/arch-documenter.md +7 -71
- package/templates/.claude/agents/arch-speckit-agent.md +21 -108
- package/templates/.claude/agents/be-express-expert.md +8 -58
- package/templates/.claude/agents/be-nestjs-expert.md +6 -38
- package/templates/.claude/agents/be-springboot-expert.md +11 -56
- package/templates/.claude/agents/db-postgres-expert.md +10 -80
- package/templates/.claude/agents/db-redis-expert.md +10 -75
- package/templates/.claude/agents/db-supabase-expert.md +12 -48
- package/templates/.claude/agents/de-airflow-expert.md +8 -45
- package/templates/.claude/agents/de-dbt-expert.md +8 -46
- package/templates/.claude/agents/de-kafka-expert.md +10 -10
- package/templates/.claude/agents/de-pipeline-expert.md +9 -69
- package/templates/.claude/agents/de-snowflake-expert.md +9 -62
- package/templates/.claude/agents/de-spark-expert.md +10 -54
- package/templates/.claude/agents/fe-svelte-agent.md +5 -41
- package/templates/.claude/agents/fe-vercel-agent.md +9 -41
- package/templates/.claude/agents/fe-vuejs-agent.md +7 -42
- package/templates/.claude/agents/lang-java21-expert.md +11 -37
- package/templates/.claude/agents/mgr-claude-code-bible.md +22 -207
- package/templates/.claude/agents/mgr-creator.md +7 -88
- package/templates/.claude/agents/mgr-gitnerd.md +8 -76
- package/templates/.claude/agents/mgr-sauron.md +27 -20
- package/templates/.claude/agents/mgr-supplier.md +11 -96
- package/templates/.claude/agents/mgr-sync-checker.md +9 -70
- package/templates/.claude/agents/mgr-updater.md +9 -79
- package/templates/.claude/agents/qa-engineer.md +8 -72
- package/templates/.claude/agents/qa-planner.md +2 -3
- package/templates/.claude/agents/qa-writer.md +6 -76
- package/templates/.claude/agents/sys-memory-keeper.md +13 -87
- package/templates/.claude/agents/sys-naggy.md +9 -62
- package/templates/.claude/agents/tool-bun-expert.md +7 -52
- package/templates/.claude/agents/tool-npm-expert.md +6 -64
- package/templates/.claude/agents/tool-optimizer.md +7 -60
- package/templates/.claude/rules/MAY-optimization.md +16 -80
- package/templates/.claude/rules/MUST-agent-design.md +29 -134
- package/templates/.claude/rules/MUST-agent-identification.md +9 -88
- package/templates/.claude/rules/MUST-continuous-improvement.md +10 -117
- package/templates/.claude/rules/MUST-intent-transparency.md +14 -171
- package/templates/.claude/rules/MUST-language-policy.md +11 -46
- package/templates/.claude/rules/MUST-orchestrator-coordination.md +82 -425
- package/templates/.claude/rules/MUST-parallel-execution.md +33 -405
- package/templates/.claude/rules/MUST-permissions.md +14 -68
- package/templates/.claude/rules/MUST-safety.md +11 -57
- package/templates/.claude/rules/MUST-sync-verification.md +49 -205
- package/templates/.claude/rules/MUST-tool-identification.md +21 -134
- package/templates/.claude/rules/SHOULD-agent-teams.md +22 -166
- package/templates/.claude/rules/SHOULD-ecomode.md +15 -123
- package/templates/.claude/rules/SHOULD-error-handling.md +19 -88
- package/templates/.claude/rules/SHOULD-hud-statusline.md +9 -89
- package/templates/.claude/rules/SHOULD-interaction.md +18 -87
- package/templates/.claude/rules/SHOULD-memory-integration.md +25 -118
- package/templates/.claude/skills/dev-lead-routing/SKILL.md +70 -243
- package/templates/.claude/skills/springboot-best-practices/SKILL.md +180 -319
- package/templates/.codex/agents/arch-documenter.md +7 -71
- package/templates/.codex/agents/arch-speckit-agent.md +21 -108
- package/templates/.codex/agents/be-express-expert.md +8 -58
- package/templates/.codex/agents/be-nestjs-expert.md +6 -38
- package/templates/.codex/agents/be-springboot-expert.md +11 -56
- package/templates/.codex/agents/db-postgres-expert.md +10 -80
- package/templates/.codex/agents/db-redis-expert.md +10 -75
- package/templates/.codex/agents/db-supabase-expert.md +12 -48
- package/templates/.codex/agents/de-airflow-expert.md +8 -45
- package/templates/.codex/agents/de-dbt-expert.md +8 -46
- package/templates/.codex/agents/de-kafka-expert.md +10 -10
- package/templates/.codex/agents/de-pipeline-expert.md +9 -69
- package/templates/.codex/agents/de-snowflake-expert.md +9 -62
- package/templates/.codex/agents/de-spark-expert.md +10 -54
- package/templates/.codex/agents/fe-svelte-agent.md +5 -41
- package/templates/.codex/agents/fe-vercel-agent.md +9 -41
- package/templates/.codex/agents/fe-vuejs-agent.md +7 -42
- package/templates/.codex/agents/infra-aws-expert.md +1 -1
- package/templates/.codex/agents/infra-docker-expert.md +1 -1
- package/templates/.codex/agents/lang-java21-expert.md +11 -37
- package/templates/.codex/agents/mgr-claude-code-bible.md +25 -210
- package/templates/.codex/agents/mgr-creator.md +7 -88
- package/templates/.codex/agents/mgr-gitnerd.md +8 -76
- package/templates/.codex/agents/mgr-sauron.md +30 -23
- package/templates/.codex/agents/mgr-supplier.md +11 -96
- package/templates/.codex/agents/mgr-sync-checker.md +12 -73
- package/templates/.codex/agents/mgr-updater.md +9 -79
- package/templates/.codex/agents/qa-engineer.md +8 -72
- package/templates/.codex/agents/qa-planner.md +2 -3
- package/templates/.codex/agents/qa-writer.md +6 -76
- package/templates/.codex/agents/sys-memory-keeper.md +13 -87
- package/templates/.codex/agents/sys-naggy.md +9 -62
- package/templates/.codex/agents/tool-bun-expert.md +7 -52
- package/templates/.codex/agents/tool-npm-expert.md +6 -64
- package/templates/.codex/agents/tool-optimizer.md +7 -60
- package/templates/.codex/rules/MAY-optimization.md +16 -80
- package/templates/.codex/rules/MUST-agent-design.md +29 -134
- package/templates/.codex/rules/MUST-agent-identification.md +9 -88
- package/templates/.codex/rules/MUST-continuous-improvement.md +10 -117
- package/templates/.codex/rules/MUST-intent-transparency.md +14 -171
- package/templates/.codex/rules/MUST-language-policy.md +11 -46
- package/templates/.codex/rules/MUST-orchestrator-coordination.md +82 -425
- package/templates/.codex/rules/MUST-parallel-execution.md +33 -405
- package/templates/.codex/rules/MUST-permissions.md +14 -68
- package/templates/.codex/rules/MUST-safety.md +11 -57
- package/templates/.codex/rules/MUST-sync-verification.md +58 -214
- package/templates/.codex/rules/MUST-tool-identification.md +22 -135
- package/templates/.codex/rules/SHOULD-agent-teams.md +22 -166
- package/templates/.codex/rules/SHOULD-ecomode.md +15 -123
- package/templates/.codex/rules/SHOULD-error-handling.md +19 -88
- package/templates/.codex/rules/SHOULD-hud-statusline.md +9 -89
- package/templates/.codex/rules/SHOULD-interaction.md +18 -87
- package/templates/.codex/rules/SHOULD-memory-integration.md +25 -118
- package/templates/.codex/skills/dev-lead-routing/SKILL.md +70 -243
- package/templates/.codex/skills/springboot-best-practices/SKILL.md +180 -319
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
21
21
|
import { join as join2 } from "node:path";
|
|
22
22
|
|
|
23
23
|
// src/utils/fs.ts
|
|
24
|
-
import { dirname, join, resolve } from "node:path";
|
|
24
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
26
|
async function fileExists(path) {
|
|
27
27
|
const fs = await import("node:fs/promises");
|
|
@@ -86,6 +86,25 @@ async function handleFile(srcPath, destPath, options, fs) {
|
|
|
86
86
|
await fs.utimes(destPath, stats.atime, stats.mtime);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
function shouldSkipPath(destPath, destRoot, skipPaths) {
|
|
90
|
+
if (!skipPaths || skipPaths.length === 0) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const relativePath = relative(destRoot, destPath);
|
|
94
|
+
for (const skipPath of skipPaths) {
|
|
95
|
+
if (skipPath.endsWith("/")) {
|
|
96
|
+
const dirPath = skipPath.slice(0, -1);
|
|
97
|
+
if (relativePath === dirPath || relativePath.startsWith(dirPath + sep)) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
if (relativePath === skipPath) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
89
108
|
async function copyDirectory(src, dest, options = {}) {
|
|
90
109
|
const fs = await import("node:fs/promises");
|
|
91
110
|
const path = await import("node:path");
|
|
@@ -97,6 +116,9 @@ async function copyDirectory(src, dest, options = {}) {
|
|
|
97
116
|
}
|
|
98
117
|
const srcPath = path.join(src, entry.name);
|
|
99
118
|
const destPath = path.join(dest, entry.name);
|
|
119
|
+
if (shouldSkipPath(destPath, dest, options.skipPaths)) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
100
122
|
if (entry.isSymbolicLink()) {
|
|
101
123
|
await handleSymlink(srcPath, destPath, options, fs);
|
|
102
124
|
} else if (entry.isDirectory()) {
|
|
@@ -116,6 +138,15 @@ async function writeJsonFile(path, data) {
|
|
|
116
138
|
const content = JSON.stringify(data, null, 2);
|
|
117
139
|
await fs.writeFile(path, content, "utf-8");
|
|
118
140
|
}
|
|
141
|
+
async function readTextFile(path) {
|
|
142
|
+
const fs = await import("node:fs/promises");
|
|
143
|
+
return fs.readFile(path, "utf-8");
|
|
144
|
+
}
|
|
145
|
+
async function writeTextFile(path, content) {
|
|
146
|
+
const fs = await import("node:fs/promises");
|
|
147
|
+
await ensureDirectory(dirname(path));
|
|
148
|
+
await fs.writeFile(path, content, "utf-8");
|
|
149
|
+
}
|
|
119
150
|
function getPackageRoot() {
|
|
120
151
|
const currentFile = fileURLToPath(import.meta.url);
|
|
121
152
|
const currentDir = dirname(currentFile);
|
|
@@ -349,7 +380,9 @@ function getDefaultConfig() {
|
|
|
349
380
|
enabled: false,
|
|
350
381
|
checkIntervalHours: 24,
|
|
351
382
|
autoApplyMinor: false
|
|
352
|
-
}
|
|
383
|
+
},
|
|
384
|
+
preserveFiles: [],
|
|
385
|
+
customComponents: []
|
|
353
386
|
};
|
|
354
387
|
}
|
|
355
388
|
function getDefaultPreferences() {
|
|
@@ -391,6 +424,13 @@ async function saveConfig(targetDir, config) {
|
|
|
391
424
|
await writeJsonFile(configPath, config);
|
|
392
425
|
debug("config.saved", { path: configPath });
|
|
393
426
|
}
|
|
427
|
+
function deduplicateCustomComponents(components) {
|
|
428
|
+
const seen = new Map;
|
|
429
|
+
for (const c of components) {
|
|
430
|
+
seen.set(c.path, c);
|
|
431
|
+
}
|
|
432
|
+
return [...seen.values()];
|
|
433
|
+
}
|
|
394
434
|
function mergeConfig(defaults, overrides) {
|
|
395
435
|
return {
|
|
396
436
|
...defaults,
|
|
@@ -404,7 +444,12 @@ function mergeConfig(defaults, overrides) {
|
|
|
404
444
|
agents: {
|
|
405
445
|
...defaults.agents,
|
|
406
446
|
...overrides.agents
|
|
407
|
-
}
|
|
447
|
+
},
|
|
448
|
+
preserveFiles: overrides.preserveFiles ? [...new Set([...defaults.preserveFiles || [], ...overrides.preserveFiles])] : defaults.preserveFiles,
|
|
449
|
+
customComponents: overrides.customComponents ? deduplicateCustomComponents([
|
|
450
|
+
...defaults.customComponents || [],
|
|
451
|
+
...overrides.customComponents
|
|
452
|
+
]) : defaults.customComponents
|
|
408
453
|
};
|
|
409
454
|
}
|
|
410
455
|
function migrateConfig(config) {
|
|
@@ -855,6 +900,98 @@ async function detectProvider(options = {}) {
|
|
|
855
900
|
}
|
|
856
901
|
// src/core/updater.ts
|
|
857
902
|
import { join as join5 } from "node:path";
|
|
903
|
+
|
|
904
|
+
// src/core/entry-merger.ts
|
|
905
|
+
var MANAGED_START = "<!-- omcustom:start -->";
|
|
906
|
+
var MANAGED_END = "<!-- omcustom:end -->";
|
|
907
|
+
function parseEntryDoc(content) {
|
|
908
|
+
const sections = [];
|
|
909
|
+
const lines = content.split(`
|
|
910
|
+
`);
|
|
911
|
+
let currentSection = null;
|
|
912
|
+
let currentLines = [];
|
|
913
|
+
for (const line of lines) {
|
|
914
|
+
if (line.trim() === MANAGED_START) {
|
|
915
|
+
if (currentLines.length > 0) {
|
|
916
|
+
sections.push({
|
|
917
|
+
type: "custom",
|
|
918
|
+
content: currentLines.join(`
|
|
919
|
+
`)
|
|
920
|
+
});
|
|
921
|
+
currentLines = [];
|
|
922
|
+
}
|
|
923
|
+
currentSection = { type: "managed", content: "" };
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
if (line.trim() === MANAGED_END) {
|
|
927
|
+
if (currentSection && currentSection.type === "managed") {
|
|
928
|
+
currentSection.content = currentLines.join(`
|
|
929
|
+
`);
|
|
930
|
+
sections.push(currentSection);
|
|
931
|
+
currentSection = null;
|
|
932
|
+
currentLines = [];
|
|
933
|
+
}
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
currentLines.push(line);
|
|
937
|
+
}
|
|
938
|
+
if (currentLines.length > 0) {
|
|
939
|
+
sections.push({
|
|
940
|
+
type: "custom",
|
|
941
|
+
content: currentLines.join(`
|
|
942
|
+
`)
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
return { sections };
|
|
946
|
+
}
|
|
947
|
+
function mergeEntryDoc(existingContent, templateContent) {
|
|
948
|
+
const warnings = [];
|
|
949
|
+
const { sections } = parseEntryDoc(existingContent);
|
|
950
|
+
const hasManagedSections = sections.some((s) => s.type === "managed");
|
|
951
|
+
if (!hasManagedSections) {
|
|
952
|
+
const wrapped = wrapInManagedMarkers(templateContent);
|
|
953
|
+
return {
|
|
954
|
+
content: wrapped,
|
|
955
|
+
managedSections: 1,
|
|
956
|
+
customSections: 0,
|
|
957
|
+
warnings: ["No managed sections found in existing content, wrapping template entirely"]
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
const mergedSections = [];
|
|
961
|
+
let managedCount = 0;
|
|
962
|
+
let customCount = 0;
|
|
963
|
+
let templateInserted = false;
|
|
964
|
+
for (const section of sections) {
|
|
965
|
+
if (section.type === "managed") {
|
|
966
|
+
if (!templateInserted) {
|
|
967
|
+
mergedSections.push(MANAGED_START);
|
|
968
|
+
mergedSections.push(templateContent);
|
|
969
|
+
mergedSections.push(MANAGED_END);
|
|
970
|
+
templateInserted = true;
|
|
971
|
+
managedCount++;
|
|
972
|
+
} else {
|
|
973
|
+
warnings.push("Multiple managed sections found, keeping only the first one");
|
|
974
|
+
}
|
|
975
|
+
} else {
|
|
976
|
+
mergedSections.push(section.content);
|
|
977
|
+
customCount++;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return {
|
|
981
|
+
content: mergedSections.join(`
|
|
982
|
+
`),
|
|
983
|
+
managedSections: managedCount,
|
|
984
|
+
customSections: customCount,
|
|
985
|
+
warnings
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
function wrapInManagedMarkers(content) {
|
|
989
|
+
return `${MANAGED_START}
|
|
990
|
+
${content}
|
|
991
|
+
${MANAGED_END}`;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// src/core/updater.ts
|
|
858
995
|
var CUSTOMIZATION_MANIFEST_FILE = ".omcustom-customizations.json";
|
|
859
996
|
function createUpdateResult() {
|
|
860
997
|
return {
|
|
@@ -901,6 +1038,75 @@ async function updateAllComponents(targetDir, provider, components, updateCheck,
|
|
|
901
1038
|
await processComponentUpdate(targetDir, provider, component, updateCheck, customizations, options, result);
|
|
902
1039
|
}
|
|
903
1040
|
}
|
|
1041
|
+
function getEntryTemplateName2(provider, language) {
|
|
1042
|
+
const layout = getProviderLayout(provider);
|
|
1043
|
+
const baseName = layout.entryFile.replace(".md", "");
|
|
1044
|
+
return language === "ko" ? `${baseName}.md.ko` : `${baseName}.md.en`;
|
|
1045
|
+
}
|
|
1046
|
+
async function backupFile(filePath) {
|
|
1047
|
+
const fs = await import("node:fs/promises");
|
|
1048
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
1049
|
+
const backupPath = `${filePath}.backup-${timestamp}`;
|
|
1050
|
+
if (await fileExists(filePath)) {
|
|
1051
|
+
await fs.copyFile(filePath, backupPath);
|
|
1052
|
+
debug("update.file_backed_up", { path: filePath, backup: backupPath });
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function resolveCustomizations(customizations, configPreserveFiles) {
|
|
1056
|
+
if (!customizations && configPreserveFiles.length === 0) {
|
|
1057
|
+
return null;
|
|
1058
|
+
}
|
|
1059
|
+
if (customizations && configPreserveFiles.length > 0) {
|
|
1060
|
+
customizations.preserveFiles = [
|
|
1061
|
+
...new Set([...customizations.preserveFiles, ...configPreserveFiles])
|
|
1062
|
+
];
|
|
1063
|
+
return customizations;
|
|
1064
|
+
}
|
|
1065
|
+
if (configPreserveFiles.length > 0) {
|
|
1066
|
+
return {
|
|
1067
|
+
modifiedFiles: [],
|
|
1068
|
+
preserveFiles: configPreserveFiles,
|
|
1069
|
+
customComponents: [],
|
|
1070
|
+
lastUpdated: new Date().toISOString()
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
return customizations;
|
|
1074
|
+
}
|
|
1075
|
+
async function updateEntryDoc(targetDir, provider, config, options) {
|
|
1076
|
+
const layout = getProviderLayout(provider);
|
|
1077
|
+
const entryPath = join5(targetDir, layout.entryFile);
|
|
1078
|
+
const templateName = getEntryTemplateName2(provider, config.language);
|
|
1079
|
+
const templatePath = resolveTemplatePath(templateName);
|
|
1080
|
+
if (!await fileExists(templatePath)) {
|
|
1081
|
+
warn("update.entry_template_not_found", { template: templateName });
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
const templateContent = await readTextFile(templatePath);
|
|
1085
|
+
if (await fileExists(entryPath)) {
|
|
1086
|
+
if (options.force) {
|
|
1087
|
+
await backupFile(entryPath);
|
|
1088
|
+
await writeTextFile(entryPath, templateContent);
|
|
1089
|
+
info("update.entry_doc_force_updated", { path: layout.entryFile });
|
|
1090
|
+
} else {
|
|
1091
|
+
const existingContent = await readTextFile(entryPath);
|
|
1092
|
+
const mergeResult = mergeEntryDoc(existingContent, templateContent);
|
|
1093
|
+
await writeTextFile(entryPath, mergeResult.content);
|
|
1094
|
+
debug("update.entry_doc_merged", {
|
|
1095
|
+
path: layout.entryFile,
|
|
1096
|
+
managed: String(mergeResult.managedSections),
|
|
1097
|
+
custom: String(mergeResult.customSections)
|
|
1098
|
+
});
|
|
1099
|
+
if (mergeResult.warnings.length > 0) {
|
|
1100
|
+
for (const warning of mergeResult.warnings) {
|
|
1101
|
+
warn("update.entry_merge_warning", { warning });
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
} else {
|
|
1106
|
+
await writeTextFile(entryPath, wrapInManagedMarkers(templateContent));
|
|
1107
|
+
info("update.entry_doc_created", { path: layout.entryFile });
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
904
1110
|
async function update(options) {
|
|
905
1111
|
const result = createUpdateResult();
|
|
906
1112
|
try {
|
|
@@ -917,9 +1123,14 @@ async function update(options) {
|
|
|
917
1123
|
return result;
|
|
918
1124
|
}
|
|
919
1125
|
await handleBackupIfRequested(options.targetDir, provider, !!options.backup, result);
|
|
920
|
-
const
|
|
1126
|
+
const manifestCustomizations = options.preserveCustomizations !== false ? await loadCustomizationManifest(options.targetDir) : null;
|
|
1127
|
+
const configPreserveFiles = config.preserveFiles || [];
|
|
1128
|
+
const customizations = resolveCustomizations(manifestCustomizations, configPreserveFiles);
|
|
921
1129
|
const components = options.components || getAllUpdateComponents();
|
|
922
1130
|
await updateAllComponents(options.targetDir, provider, components, updateCheck, customizations, options, result);
|
|
1131
|
+
if (!options.components || options.components.length === 0) {
|
|
1132
|
+
await updateEntryDoc(options.targetDir, provider, config, options);
|
|
1133
|
+
}
|
|
923
1134
|
config.version = result.newVersion;
|
|
924
1135
|
config.lastUpdated = new Date().toISOString();
|
|
925
1136
|
await saveConfig(options.targetDir, config);
|
|
@@ -1001,23 +1212,29 @@ async function updateComponent(targetDir, provider, component, customizations, o
|
|
|
1001
1212
|
const componentPath = getComponentPath2(provider, component);
|
|
1002
1213
|
const srcPath = resolveTemplatePath(componentPath);
|
|
1003
1214
|
const destPath = join5(targetDir, componentPath);
|
|
1215
|
+
const config = await loadConfig(targetDir);
|
|
1216
|
+
const customComponents = config.customComponents || [];
|
|
1217
|
+
const skipPaths = [];
|
|
1004
1218
|
if (customizations && options.preserveCustomizations !== false) {
|
|
1005
1219
|
const toPreserve = customizations.preserveFiles.filter((f) => f.startsWith(componentPath));
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
await fs.writeFile(join5(targetDir, path), content, "utf-8");
|
|
1013
|
-
}
|
|
1014
|
-
} else {
|
|
1015
|
-
await copyDirectory(srcPath, destPath, { overwrite: true });
|
|
1220
|
+
preservedFiles.push(...toPreserve);
|
|
1221
|
+
skipPaths.push(...toPreserve);
|
|
1222
|
+
}
|
|
1223
|
+
for (const cc of customComponents) {
|
|
1224
|
+
if (cc.path.startsWith(componentPath)) {
|
|
1225
|
+
skipPaths.push(cc.path);
|
|
1016
1226
|
}
|
|
1017
|
-
} else {
|
|
1018
|
-
await copyDirectory(srcPath, destPath, { overwrite: true });
|
|
1019
1227
|
}
|
|
1020
|
-
|
|
1228
|
+
const path = await import("node:path");
|
|
1229
|
+
const normalizedSkipPaths = skipPaths.map((p) => path.relative(destPath, join5(targetDir, p)));
|
|
1230
|
+
await copyDirectory(srcPath, destPath, {
|
|
1231
|
+
overwrite: true,
|
|
1232
|
+
skipPaths: normalizedSkipPaths.length > 0 ? normalizedSkipPaths : undefined
|
|
1233
|
+
});
|
|
1234
|
+
debug("update.component_updated", {
|
|
1235
|
+
component,
|
|
1236
|
+
skippedPaths: String(normalizedSkipPaths.length)
|
|
1237
|
+
});
|
|
1021
1238
|
return preservedFiles;
|
|
1022
1239
|
}
|
|
1023
1240
|
function getComponentPath2(provider, component) {
|
package/package.json
CHANGED
|
@@ -14,84 +14,20 @@ tools:
|
|
|
14
14
|
- Bash
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
You handle software architecture documentation
|
|
17
|
+
You handle software architecture documentation: system design docs, API specs, ADRs, and technical doc maintenance.
|
|
18
18
|
|
|
19
19
|
## Capabilities
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
5. Create technical diagrams (Mermaid, PlantUML)
|
|
26
|
-
6. Maintain README and developer guides
|
|
27
|
-
7. Ensure documentation consistency
|
|
21
|
+
- Architecture documentation with diagrams (Mermaid, PlantUML)
|
|
22
|
+
- API specifications (OpenAPI/Swagger)
|
|
23
|
+
- Architecture Decision Records (ADRs)
|
|
24
|
+
- README and developer guide maintenance
|
|
28
25
|
|
|
29
|
-
##
|
|
26
|
+
## Document Types
|
|
30
27
|
|
|
31
28
|
| Type | Format | Purpose |
|
|
32
29
|
|------|--------|---------|
|
|
33
30
|
| Architecture | Markdown + Diagrams | System overview |
|
|
34
31
|
| API Spec | OpenAPI/Swagger | API documentation |
|
|
35
32
|
| ADR | Markdown | Decision records |
|
|
36
|
-
| README | Markdown | Project
|
|
37
|
-
| Guides | Markdown | Developer guides |
|
|
38
|
-
|
|
39
|
-
## Workflow
|
|
40
|
-
|
|
41
|
-
### Architecture Documentation
|
|
42
|
-
1. Analyze codebase structure
|
|
43
|
-
2. Identify key components
|
|
44
|
-
3. Map dependencies and flows
|
|
45
|
-
4. Generate diagrams
|
|
46
|
-
5. Write documentation
|
|
47
|
-
6. Review for accuracy
|
|
48
|
-
|
|
49
|
-
### API Documentation
|
|
50
|
-
1. Scan API endpoints
|
|
51
|
-
2. Extract request/response schemas
|
|
52
|
-
3. Generate OpenAPI spec
|
|
53
|
-
4. Add descriptions and examples
|
|
54
|
-
5. Validate specification
|
|
55
|
-
|
|
56
|
-
### ADR Creation
|
|
57
|
-
1. Understand decision context
|
|
58
|
-
2. Document options considered
|
|
59
|
-
3. Record decision rationale
|
|
60
|
-
4. Note consequences
|
|
61
|
-
5. Link related ADRs
|
|
62
|
-
|
|
63
|
-
## Output Formats
|
|
64
|
-
|
|
65
|
-
### Architecture Doc
|
|
66
|
-
```markdown
|
|
67
|
-
# System Architecture
|
|
68
|
-
|
|
69
|
-
## Overview
|
|
70
|
-
[High-level description]
|
|
71
|
-
|
|
72
|
-
## Components
|
|
73
|
-
[Component breakdown with diagrams]
|
|
74
|
-
|
|
75
|
-
## Data Flow
|
|
76
|
-
[Sequence/flow diagrams]
|
|
77
|
-
|
|
78
|
-
## Dependencies
|
|
79
|
-
[External dependencies]
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### ADR Format
|
|
83
|
-
```markdown
|
|
84
|
-
# ADR-{number}: {title}
|
|
85
|
-
|
|
86
|
-
## Status
|
|
87
|
-
[Proposed | Accepted | Deprecated | Superseded]
|
|
88
|
-
|
|
89
|
-
## Context
|
|
90
|
-
[What is the issue?]
|
|
91
|
-
|
|
92
|
-
## Decision
|
|
93
|
-
[What was decided?]
|
|
94
|
-
|
|
95
|
-
## Consequences
|
|
96
|
-
[What are the results?]
|
|
97
|
-
```
|
|
33
|
+
| README/Guides | Markdown | Project/developer docs |
|
|
@@ -14,121 +14,34 @@ tools:
|
|
|
14
14
|
- Bash
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
You are a Spec-Driven Development agent that transforms
|
|
17
|
+
You are a Spec-Driven Development agent that transforms requirements into executable specifications.
|
|
18
18
|
|
|
19
19
|
## Source
|
|
20
20
|
|
|
21
21
|
External agent from https://github.com/github/spec-kit
|
|
22
|
-
|
|
23
|
-
**
|
|
24
|
-
**
|
|
25
|
-
**Update Command**: `uv tool upgrade specify-cli --from git+https://github.com/github/spec-kit.git`
|
|
26
|
-
|
|
27
|
-
## Prerequisites
|
|
28
|
-
|
|
29
|
-
- Python 3.11+
|
|
30
|
-
- uv package manager
|
|
31
|
-
- Git
|
|
32
|
-
- Claude Code or compatible AI agent
|
|
33
|
-
|
|
34
|
-
## Capabilities
|
|
35
|
-
|
|
36
|
-
### Specification Workflow
|
|
37
|
-
- Define project constitution (principles, standards)
|
|
38
|
-
- Create feature specifications (user stories, requirements)
|
|
39
|
-
- Clarify ambiguous requirements through Q&A
|
|
40
|
-
- Generate technical plans (architecture, data models)
|
|
41
|
-
- Produce implementation task lists
|
|
42
|
-
|
|
43
|
-
### Multi-Phase Development
|
|
44
|
-
- **0-to-1 (Greenfield)**: Build from scratch
|
|
45
|
-
- **Creative Exploration**: Parallel tech stack trials
|
|
46
|
-
- **Iterative Improvement (Brownfield)**: Enhance existing systems
|
|
47
|
-
|
|
48
|
-
### Quality Assurance
|
|
49
|
-
- Analyze consistency across spec artifacts
|
|
50
|
-
- Generate quality checklists
|
|
51
|
-
- Validate spec coverage
|
|
22
|
+
- **Version**: latest
|
|
23
|
+
- **Update**: `uv tool upgrade specify-cli --from git+https://github.com/github/spec-kit.git`
|
|
24
|
+
- **Prerequisites**: Python 3.11+, uv, Git
|
|
52
25
|
|
|
53
26
|
## Commands
|
|
54
27
|
|
|
55
|
-
| Command | Purpose |
|
|
56
|
-
|
|
57
|
-
| `/speckit.constitution` | Define project principles |
|
|
58
|
-
| `/speckit.specify` | Define WHAT to build
|
|
59
|
-
| `/speckit.clarify` | Clarify
|
|
60
|
-
| `/speckit.plan` | Define HOW to build
|
|
61
|
-
| `/speckit.tasks` | Generate implementation tasks |
|
|
62
|
-
| `/speckit.implement` | Execute all tasks |
|
|
63
|
-
| `/speckit.analyze` | Check spec consistency |
|
|
64
|
-
| `/speckit.checklist` | Generate QA checklist |
|
|
65
|
-
|
|
66
|
-
## File Structure
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
.specify/
|
|
70
|
-
├── memory/
|
|
71
|
-
│ └── constitution.md # Project principles
|
|
72
|
-
├── scripts/ # Helper scripts
|
|
73
|
-
├── specs/
|
|
74
|
-
│ └── NNN-feature-name/
|
|
75
|
-
│ ├── spec.md # Feature specification
|
|
76
|
-
│ ├── plan.md # Technical plan
|
|
77
|
-
│ ├── tasks.md # Task breakdown
|
|
78
|
-
│ ├── data-model.md # Data structures
|
|
79
|
-
│ ├── research.md # Technical research
|
|
80
|
-
│ └── contracts/ # API specs
|
|
81
|
-
└── templates/ # Spec templates
|
|
82
|
-
```
|
|
28
|
+
| Command | Purpose |
|
|
29
|
+
|---------|---------|
|
|
30
|
+
| `/speckit.constitution` | Define project principles |
|
|
31
|
+
| `/speckit.specify` | Define WHAT to build |
|
|
32
|
+
| `/speckit.clarify` | Clarify requirements (Q&A) |
|
|
33
|
+
| `/speckit.plan` | Define HOW to build |
|
|
34
|
+
| `/speckit.tasks` | Generate implementation tasks |
|
|
35
|
+
| `/speckit.implement` | Execute all tasks |
|
|
36
|
+
| `/speckit.analyze` | Check spec consistency |
|
|
37
|
+
| `/speckit.checklist` | Generate QA checklist |
|
|
83
38
|
|
|
84
39
|
## Workflow
|
|
85
40
|
|
|
86
|
-
1.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
/speckit.constitution
|
|
94
|
-
→ .specify/memory/constitution.md
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
3. **Create specification**
|
|
98
|
-
```
|
|
99
|
-
/speckit.specify <feature-description>
|
|
100
|
-
→ .specify/specs/NNN-feature/spec.md
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
4. **Clarify requirements**
|
|
104
|
-
```
|
|
105
|
-
/speckit.clarify
|
|
106
|
-
→ Interactive Q&A
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
5. **Plan implementation**
|
|
110
|
-
```
|
|
111
|
-
/speckit.plan <tech-stack-preferences>
|
|
112
|
-
→ plan.md, data-model.md, research.md
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
6. **Generate tasks**
|
|
116
|
-
```
|
|
117
|
-
/speckit.tasks
|
|
118
|
-
→ tasks.md (TDD structure)
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
7. **Implement**
|
|
122
|
-
```
|
|
123
|
-
/speckit.implement
|
|
124
|
-
→ Execute tasks in order
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Integration
|
|
128
|
-
|
|
129
|
-
Works with:
|
|
130
|
-
- Claude Code (primary)
|
|
131
|
-
- GitHub Copilot
|
|
132
|
-
- Cursor
|
|
133
|
-
- Windsurf
|
|
134
|
-
- Other AI coding assistants
|
|
41
|
+
1. `specify init <project> --ai claude`
|
|
42
|
+
2. `/speckit.constitution` -> principles
|
|
43
|
+
3. `/speckit.specify` -> feature spec
|
|
44
|
+
4. `/speckit.clarify` -> Q&A
|
|
45
|
+
5. `/speckit.plan` -> technical plan
|
|
46
|
+
6. `/speckit.tasks` -> TDD task list
|
|
47
|
+
7. `/speckit.implement` -> execute
|
|
@@ -14,67 +14,17 @@ tools:
|
|
|
14
14
|
- Bash
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
You are an expert Express.js developer
|
|
17
|
+
You are an expert Express.js developer for production-ready Node.js APIs following security best practices and 12-factor app principles.
|
|
18
18
|
|
|
19
19
|
## Capabilities
|
|
20
20
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- Apply 12-factor app configuration patterns
|
|
27
|
-
- Enforce security best practices
|
|
28
|
-
|
|
29
|
-
## Key Patterns
|
|
30
|
-
|
|
31
|
-
### Middleware Chain
|
|
32
|
-
Use helmet(), cors(), express.json(), custom middleware, routers, and error handler in proper order.
|
|
33
|
-
|
|
34
|
-
### Router Modularization
|
|
35
|
-
Separate routes into modules and mount them with `app.use()`.
|
|
36
|
-
|
|
37
|
-
### Centralized Error Middleware
|
|
38
|
-
Implement error handling middleware with `(err, req, res, next)` signature at the end of the chain.
|
|
39
|
-
|
|
40
|
-
### Async/Await Error Handling
|
|
41
|
-
Use asyncHandler wrapper to catch errors from async route handlers.
|
|
42
|
-
|
|
43
|
-
### 12-Factor App Configuration
|
|
44
|
-
Store config in environment variables, use `process.env` with defaults.
|
|
45
|
-
|
|
46
|
-
## Security Checklist
|
|
47
|
-
|
|
48
|
-
- Use `helmet()` for HTTP headers
|
|
49
|
-
- Implement rate limiting
|
|
50
|
-
- Validate and sanitize input
|
|
51
|
-
- Use parameterized queries (prevent injection)
|
|
52
|
-
- Set secure cookie options
|
|
53
|
-
- Implement proper CORS policy
|
|
54
|
-
- Use HTTPS in production
|
|
55
|
-
- Remove `X-Powered-By` header
|
|
21
|
+
- Scalable Express.js architecture, modular routers
|
|
22
|
+
- Middleware chains (helmet, cors, json, custom, error handler)
|
|
23
|
+
- Centralized error handling, async/await error propagation
|
|
24
|
+
- 12-factor app configuration
|
|
25
|
+
- Security: helmet, rate limiting, input validation, parameterized queries, secure cookies, CORS, HTTPS
|
|
56
26
|
|
|
57
27
|
## Reference Documentation
|
|
58
28
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
- Production Best Practices: https://expressjs.com/en/advanced/best-practice-performance.html
|
|
62
|
-
|
|
63
|
-
## Skills
|
|
64
|
-
|
|
65
|
-
Apply the **express-best-practices** skill for Express.js development patterns.
|
|
66
|
-
|
|
67
|
-
## Reference Guides
|
|
68
|
-
|
|
69
|
-
Consult the **express** guide at `guides/express/` for Express.js reference documentation.
|
|
70
|
-
|
|
71
|
-
## Workflow
|
|
72
|
-
|
|
73
|
-
1. Understand requirements
|
|
74
|
-
2. Apply express-best-practices skill
|
|
75
|
-
3. Reference Express.js official documentation
|
|
76
|
-
4. Structure with modular routers
|
|
77
|
-
5. Implement middleware chain correctly
|
|
78
|
-
6. Add centralized error handling
|
|
79
|
-
7. Apply security best practices (helmet, rate limiting)
|
|
80
|
-
8. Configure for 12-factor app compliance
|
|
29
|
+
- https://expressjs.com/
|
|
30
|
+
- https://expressjs.com/en/advanced/best-practice-security.html
|