create-dokio 0.1.17 → 0.1.18
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 +20 -0
- package/dist/index.js +157 -77
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,6 +113,26 @@ cp tools/changelog/.env.example tools/changelog/.env
|
|
|
113
113
|
|
|
114
114
|
---
|
|
115
115
|
|
|
116
|
+
### `create-dokio repair`
|
|
117
|
+
|
|
118
|
+
**Run this once after cloning a hub repo.** Hooks live in `.githooks/`, but Git activates them via `core.hooksPath` — a setting stored in `.git/config`, which is **never committed or cloned**. So a fresh clone has the hook files but they don't run: the commit-message check is skipped and changelogs stop auto-updating. Git cannot enable repo hooks automatically on clone (security), so every machine must opt in once.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# from inside a cloned hub repo (e.g. bupa-sam-templates/)
|
|
122
|
+
npx --yes create-dokio@latest repair
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**What it does:**
|
|
126
|
+
- Sets `git config core.hooksPath .githooks` for this clone (the actual fix)
|
|
127
|
+
- Re-writes the managed tooling to the latest version (`.githooks/commit-msg`, `.githooks/post-commit`, `tools/changelog/update_changelog.py`)
|
|
128
|
+
- Ensures `.vscode/settings.json`, `tools/changelog/.env.example`, and `.gitignore` entries exist
|
|
129
|
+
|
|
130
|
+
Safe to re-run any time — it never touches your template content or `tools/changelog/.env`.
|
|
131
|
+
|
|
132
|
+
> **Teammates:** if your commit messages aren't being checked, or template `CHANGELOG.md` files aren't updating on commit, you haven't run `repair` on your clone yet.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
116
136
|
## Template types
|
|
117
137
|
|
|
118
138
|
### PDF
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import prompts3 from "prompts";
|
|
5
|
-
import
|
|
5
|
+
import kleur7 from "kleur";
|
|
6
6
|
import { createRequire } from "module";
|
|
7
7
|
|
|
8
8
|
// src/template.ts
|
|
9
|
-
import { join as
|
|
10
|
-
import
|
|
9
|
+
import { join as join4 } from "path";
|
|
10
|
+
import fse4 from "fs-extra";
|
|
11
11
|
import kleur4 from "kleur";
|
|
12
12
|
|
|
13
13
|
// src/prompts.ts
|
|
@@ -878,10 +878,15 @@ function buildFiles(config) {
|
|
|
878
878
|
}
|
|
879
879
|
|
|
880
880
|
// src/git.ts
|
|
881
|
-
import { join, basename } from "path";
|
|
881
|
+
import { join as join2, basename } from "path";
|
|
882
|
+
import { execSync as execSync2 } from "child_process";
|
|
883
|
+
import fse2 from "fs-extra";
|
|
884
|
+
import kleur2 from "kleur";
|
|
885
|
+
|
|
886
|
+
// src/hubSetup.ts
|
|
887
|
+
import { join } from "path";
|
|
882
888
|
import { execSync } from "child_process";
|
|
883
889
|
import fse from "fs-extra";
|
|
884
|
-
import kleur2 from "kleur";
|
|
885
890
|
|
|
886
891
|
// src/templates/changelog.ts
|
|
887
892
|
function changelogScript() {
|
|
@@ -1092,91 +1097,112 @@ function changelogEnvExample() {
|
|
|
1092
1097
|
`;
|
|
1093
1098
|
}
|
|
1094
1099
|
|
|
1100
|
+
// src/hubSetup.ts
|
|
1101
|
+
function vscodeSettings() {
|
|
1102
|
+
return JSON.stringify({ "scss.validate": false, "css.validate": false }, null, 2) + "\n";
|
|
1103
|
+
}
|
|
1104
|
+
var REQUIRED_IGNORES = [".DS_Store", "node_modules/", "*.log", "tools/changelog/.env"];
|
|
1105
|
+
var MANAGED = [
|
|
1106
|
+
{ rel: ".githooks/commit-msg", content: commitMsgHook, exec: true },
|
|
1107
|
+
{ rel: ".githooks/post-commit", content: changelogHook, exec: true },
|
|
1108
|
+
{ rel: "tools/changelog/update_changelog.py", content: changelogScript, exec: true }
|
|
1109
|
+
];
|
|
1110
|
+
var ENSURE = [
|
|
1111
|
+
{ rel: "tools/changelog/.env.example", content: changelogEnvExample },
|
|
1112
|
+
{ rel: ".vscode/settings.json", content: vscodeSettings }
|
|
1113
|
+
];
|
|
1114
|
+
async function writeFile(hubDir, file) {
|
|
1115
|
+
const fullPath = join(hubDir, file.rel);
|
|
1116
|
+
await fse.ensureDir(join(fullPath, ".."));
|
|
1117
|
+
await fse.writeFile(fullPath, file.content(), "utf8");
|
|
1118
|
+
if (file.exec) await fse.chmod(fullPath, 493);
|
|
1119
|
+
}
|
|
1120
|
+
async function syncHubFiles(hubDir, opts) {
|
|
1121
|
+
const written = [];
|
|
1122
|
+
for (const file of MANAGED) {
|
|
1123
|
+
const exists = await fse.pathExists(join(hubDir, file.rel));
|
|
1124
|
+
if (exists && !opts.force) continue;
|
|
1125
|
+
await writeFile(hubDir, file);
|
|
1126
|
+
written.push(`${exists ? "~" : "+"} ${file.rel}`);
|
|
1127
|
+
}
|
|
1128
|
+
for (const file of ENSURE) {
|
|
1129
|
+
if (await fse.pathExists(join(hubDir, file.rel))) continue;
|
|
1130
|
+
await writeFile(hubDir, file);
|
|
1131
|
+
written.push(`+ ${file.rel}`);
|
|
1132
|
+
}
|
|
1133
|
+
const gitignorePath = join(hubDir, ".gitignore");
|
|
1134
|
+
if (!await fse.pathExists(gitignorePath)) {
|
|
1135
|
+
await fse.writeFile(gitignorePath, REQUIRED_IGNORES.join("\n") + "\n", "utf8");
|
|
1136
|
+
written.push("+ .gitignore");
|
|
1137
|
+
} else {
|
|
1138
|
+
const existing = await fse.readFile(gitignorePath, "utf8");
|
|
1139
|
+
const missing = REQUIRED_IGNORES.filter((e) => !existing.includes(e));
|
|
1140
|
+
if (missing.length) {
|
|
1141
|
+
await fse.appendFile(gitignorePath, missing.join("\n") + "\n");
|
|
1142
|
+
written.push(`~ .gitignore (added: ${missing.join(", ")})`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return { written };
|
|
1146
|
+
}
|
|
1147
|
+
function setHooksPath(hubDir) {
|
|
1148
|
+
execSync("git config core.hooksPath .githooks", { cwd: hubDir, stdio: "ignore" });
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1095
1151
|
// src/git.ts
|
|
1096
1152
|
async function ensureHubRepo(hubId) {
|
|
1097
1153
|
const cwd = process.cwd();
|
|
1098
1154
|
const dirName = hubRepoDirName(hubId);
|
|
1099
1155
|
const alreadyInside = basename(cwd) === dirName;
|
|
1100
|
-
const hubDir = alreadyInside ? cwd :
|
|
1101
|
-
if (alreadyInside || await
|
|
1156
|
+
const hubDir = alreadyInside ? cwd : join2(cwd, dirName);
|
|
1157
|
+
if (alreadyInside || await fse2.pathExists(hubDir)) {
|
|
1102
1158
|
console.log(kleur2.dim(`
|
|
1103
1159
|
\u21BB Pulling latest ${dirName}...`));
|
|
1104
|
-
|
|
1160
|
+
execSync2("git pull", { cwd: hubDir, stdio: "ignore" });
|
|
1105
1161
|
} else {
|
|
1106
1162
|
console.log(kleur2.dim(`
|
|
1107
1163
|
\u2193 Cloning ${hubRepoUrl(hubId)}...`));
|
|
1108
|
-
|
|
1164
|
+
execSync2(`git clone ${hubRepoUrl(hubId)}`, { stdio: "inherit" });
|
|
1109
1165
|
}
|
|
1110
1166
|
return hubDir;
|
|
1111
1167
|
}
|
|
1112
1168
|
async function setupHooks(hubDir) {
|
|
1113
|
-
const
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
await fse.chmod(commitMsgPath, 493);
|
|
1118
|
-
console.log(kleur2.dim(` + .githooks/commit-msg`));
|
|
1119
|
-
}
|
|
1120
|
-
const postCommitPath = join(hubDir, ".githooks", "post-commit");
|
|
1121
|
-
const changelogScriptPath = join(hubDir, "tools", "changelog", "update_changelog.py");
|
|
1122
|
-
if (!await fse.pathExists(changelogScriptPath)) {
|
|
1123
|
-
await fse.ensureDir(join(changelogScriptPath, ".."));
|
|
1124
|
-
await fse.writeFile(changelogScriptPath, changelogScript(), "utf8");
|
|
1125
|
-
await fse.chmod(changelogScriptPath, 493);
|
|
1126
|
-
console.log(kleur2.dim(` + tools/changelog/update_changelog.py`));
|
|
1127
|
-
const envExamplePath = join(hubDir, "tools", "changelog", ".env.example");
|
|
1128
|
-
await fse.writeFile(envExamplePath, changelogEnvExample(), "utf8");
|
|
1129
|
-
console.log(kleur2.dim(` + tools/changelog/.env.example`));
|
|
1130
|
-
if (!await fse.pathExists(postCommitPath)) {
|
|
1131
|
-
await fse.writeFile(postCommitPath, changelogHook(), "utf8");
|
|
1132
|
-
await fse.chmod(postCommitPath, 493);
|
|
1133
|
-
console.log(kleur2.dim(` + .githooks/post-commit`));
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
const vscodePath = join(hubDir, ".vscode", "settings.json");
|
|
1137
|
-
if (!await fse.pathExists(vscodePath)) {
|
|
1138
|
-
await fse.ensureDir(join(vscodePath, ".."));
|
|
1139
|
-
await fse.writeFile(vscodePath, JSON.stringify({ "scss.validate": false, "css.validate": false }, null, 2) + "\n", "utf8");
|
|
1140
|
-
console.log(kleur2.dim(` + .vscode/settings.json`));
|
|
1141
|
-
}
|
|
1142
|
-
const gitignorePath = join(hubDir, ".gitignore");
|
|
1143
|
-
const requiredIgnores = [".DS_Store", "node_modules/", "*.log", "tools/changelog/.env"];
|
|
1144
|
-
if (!await fse.pathExists(gitignorePath)) {
|
|
1145
|
-
await fse.writeFile(gitignorePath, requiredIgnores.join("\n") + "\n", "utf8");
|
|
1146
|
-
console.log(kleur2.dim(` + .gitignore`));
|
|
1147
|
-
} else {
|
|
1148
|
-
const existing = await fse.readFile(gitignorePath, "utf8");
|
|
1149
|
-
const missing = requiredIgnores.filter((e) => !existing.includes(e));
|
|
1150
|
-
if (missing.length) {
|
|
1151
|
-
await fse.appendFile(gitignorePath, missing.join("\n") + "\n");
|
|
1152
|
-
console.log(kleur2.dim(` ~ .gitignore (added: ${missing.join(", ")})`));
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
const readmePath = join(hubDir, "README.md");
|
|
1156
|
-
if (!await fse.pathExists(readmePath)) {
|
|
1169
|
+
const { written } = await syncHubFiles(hubDir, { force: false });
|
|
1170
|
+
for (const line of written) console.log(kleur2.dim(` ${line}`));
|
|
1171
|
+
const readmePath = join2(hubDir, "README.md");
|
|
1172
|
+
if (!await fse2.pathExists(readmePath)) {
|
|
1157
1173
|
const hubName = basename(hubDir);
|
|
1158
|
-
await
|
|
1174
|
+
await fse2.writeFile(readmePath, `# ${hubName}
|
|
1159
1175
|
|
|
1160
1176
|
Templates for ${hubName} on Dokio.
|
|
1161
1177
|
|
|
1178
|
+
## After cloning (required, once per clone)
|
|
1179
|
+
|
|
1180
|
+
Git hooks (commit-message check + auto-changelog) are not active until you run:
|
|
1181
|
+
|
|
1182
|
+
\`\`\`
|
|
1183
|
+
npx create-dokio repair
|
|
1184
|
+
\`\`\`
|
|
1185
|
+
|
|
1186
|
+
Git cannot enable repo hooks automatically on clone, so every teammate must run this once.
|
|
1187
|
+
|
|
1162
1188
|
## Creating a new template
|
|
1163
1189
|
|
|
1164
1190
|
Run \`create-dokio template\` from inside this repo.
|
|
1165
1191
|
`, "utf8");
|
|
1166
1192
|
console.log(kleur2.dim(` + README.md`));
|
|
1167
1193
|
}
|
|
1168
|
-
|
|
1194
|
+
setHooksPath(hubDir);
|
|
1169
1195
|
}
|
|
1170
1196
|
|
|
1171
1197
|
// src/scaffold.ts
|
|
1172
|
-
import { join as
|
|
1173
|
-
import
|
|
1198
|
+
import { join as join3 } from "path";
|
|
1199
|
+
import fse3 from "fs-extra";
|
|
1174
1200
|
import kleur3 from "kleur";
|
|
1175
1201
|
async function writeFiles(outDir, files, fullName) {
|
|
1176
1202
|
for (const [rel, content] of Object.entries(files)) {
|
|
1177
|
-
const fullPath =
|
|
1178
|
-
await
|
|
1179
|
-
await
|
|
1203
|
+
const fullPath = join3(outDir, rel);
|
|
1204
|
+
await fse3.ensureDir(join3(fullPath, ".."));
|
|
1205
|
+
await fse3.writeFile(fullPath, content, "utf8");
|
|
1180
1206
|
console.log(kleur3.dim(` + ${fullName}/${rel}`));
|
|
1181
1207
|
}
|
|
1182
1208
|
}
|
|
@@ -1188,8 +1214,8 @@ async function runTemplate(nameArg) {
|
|
|
1188
1214
|
const files = buildFiles(config);
|
|
1189
1215
|
const hubDir = await ensureHubRepo(config.hubId);
|
|
1190
1216
|
const hubDirName = hubRepoDirName(config.hubId);
|
|
1191
|
-
const outDir =
|
|
1192
|
-
if (await
|
|
1217
|
+
const outDir = join4(hubDir, "templates", config.fullName);
|
|
1218
|
+
if (await fse4.pathExists(outDir)) {
|
|
1193
1219
|
console.error(kleur4.red(`
|
|
1194
1220
|
Error: "${config.fullName}" already exists in ${hubDirName}/templates/.
|
|
1195
1221
|
`));
|
|
@@ -1220,9 +1246,9 @@ async function runTemplate(nameArg) {
|
|
|
1220
1246
|
}
|
|
1221
1247
|
|
|
1222
1248
|
// src/hub.ts
|
|
1223
|
-
import { join as
|
|
1224
|
-
import { execSync as
|
|
1225
|
-
import
|
|
1249
|
+
import { join as join5 } from "path";
|
|
1250
|
+
import { execSync as execSync3 } from "child_process";
|
|
1251
|
+
import fse5 from "fs-extra";
|
|
1226
1252
|
import kleur5 from "kleur";
|
|
1227
1253
|
import prompts2 from "prompts";
|
|
1228
1254
|
var onCancel2 = () => {
|
|
@@ -1251,8 +1277,8 @@ async function runHub() {
|
|
|
1251
1277
|
const hubId = answers.hubId.trim();
|
|
1252
1278
|
const hubName = answers.hubName.trim();
|
|
1253
1279
|
const dirName = `${hubId}-templates`;
|
|
1254
|
-
const outDir =
|
|
1255
|
-
if (await
|
|
1280
|
+
const outDir = join5(process.cwd(), dirName);
|
|
1281
|
+
if (await fse5.pathExists(outDir)) {
|
|
1256
1282
|
console.error(kleur5.red(`
|
|
1257
1283
|
Error: "${dirName}" already exists.
|
|
1258
1284
|
`));
|
|
@@ -1274,6 +1300,16 @@ tools/changelog/.env
|
|
|
1274
1300
|
|
|
1275
1301
|
Templates for ${hubName} on Dokio.
|
|
1276
1302
|
|
|
1303
|
+
## After cloning (required, once per clone)
|
|
1304
|
+
|
|
1305
|
+
Git hooks (commit-message check + auto-changelog) are not active until you run:
|
|
1306
|
+
|
|
1307
|
+
\`\`\`
|
|
1308
|
+
npx create-dokio repair
|
|
1309
|
+
\`\`\`
|
|
1310
|
+
|
|
1311
|
+
Git cannot enable repo hooks automatically on clone, so every teammate must run this once.
|
|
1312
|
+
|
|
1277
1313
|
## Creating a new template
|
|
1278
1314
|
|
|
1279
1315
|
Run \`create-dokio template\` from inside this repo.
|
|
@@ -1281,16 +1317,16 @@ Run \`create-dokio template\` from inside this repo.
|
|
|
1281
1317
|
};
|
|
1282
1318
|
console.log("");
|
|
1283
1319
|
for (const [rel, content] of Object.entries(files)) {
|
|
1284
|
-
const fullPath =
|
|
1285
|
-
await
|
|
1286
|
-
await
|
|
1287
|
-
if (rel === ".githooks/commit-msg" || rel === ".githooks/post-commit" || rel === "tools/changelog/update_changelog.py") await
|
|
1320
|
+
const fullPath = join5(outDir, rel);
|
|
1321
|
+
await fse5.ensureDir(join5(fullPath, ".."));
|
|
1322
|
+
await fse5.writeFile(fullPath, content, "utf8");
|
|
1323
|
+
if (rel === ".githooks/commit-msg" || rel === ".githooks/post-commit" || rel === "tools/changelog/update_changelog.py") await fse5.chmod(fullPath, 493);
|
|
1288
1324
|
console.log(kleur5.dim(` + ${rel}`));
|
|
1289
1325
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1326
|
+
execSync3("git init", { cwd: outDir, stdio: "ignore" });
|
|
1327
|
+
execSync3("git config core.hooksPath .githooks", { cwd: outDir, stdio: "ignore" });
|
|
1328
|
+
execSync3("git add .", { cwd: outDir, stdio: "ignore" });
|
|
1329
|
+
execSync3('git commit -m "chore: init Dokio Hub"', { cwd: outDir, stdio: "ignore" });
|
|
1294
1330
|
console.log(kleur5.green(`
|
|
1295
1331
|
\u2713 Created ${kleur5.bold(dirName)}
|
|
1296
1332
|
`));
|
|
@@ -1300,12 +1336,53 @@ Run \`create-dokio template\` from inside this repo.
|
|
|
1300
1336
|
console.log(kleur5.dim(` git remote add origin https://github.com/dokioco/${dirName}`));
|
|
1301
1337
|
console.log(kleur5.dim(` git push -u origin main`));
|
|
1302
1338
|
console.log("");
|
|
1339
|
+
console.log(kleur5.dim(` Teammates \u2014 after cloning, enable git hooks once:`));
|
|
1340
|
+
console.log(kleur5.dim(` npx create-dokio repair`));
|
|
1341
|
+
console.log("");
|
|
1303
1342
|
console.log(kleur5.dim(` Changelog (optional \u2014 for AI descriptions):`));
|
|
1304
1343
|
console.log(kleur5.dim(` cp tools/changelog/.env.example tools/changelog/.env`));
|
|
1305
1344
|
console.log(kleur5.dim(` # Add your ANTHROPIC_API_KEY to tools/changelog/.env`));
|
|
1306
1345
|
console.log("");
|
|
1307
1346
|
}
|
|
1308
1347
|
|
|
1348
|
+
// src/repair.ts
|
|
1349
|
+
import { execSync as execSync4 } from "child_process";
|
|
1350
|
+
import { basename as basename2 } from "path";
|
|
1351
|
+
import kleur6 from "kleur";
|
|
1352
|
+
function repoRoot() {
|
|
1353
|
+
try {
|
|
1354
|
+
return execSync4("git rev-parse --show-toplevel", {
|
|
1355
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1356
|
+
}).toString().trim();
|
|
1357
|
+
} catch {
|
|
1358
|
+
return null;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
async function runRepair() {
|
|
1362
|
+
console.log(kleur6.bold().cyan("\n \u25C6 dokio repair\n"));
|
|
1363
|
+
const hubDir = repoRoot();
|
|
1364
|
+
if (!hubDir) {
|
|
1365
|
+
console.error(kleur6.red(" Not a git repository.\n"));
|
|
1366
|
+
console.error(kleur6.dim(" Run this from inside a cloned hub repo (e.g. bupa-sam-templates/).\n"));
|
|
1367
|
+
process.exit(1);
|
|
1368
|
+
}
|
|
1369
|
+
const { written } = await syncHubFiles(hubDir, { force: true });
|
|
1370
|
+
setHooksPath(hubDir);
|
|
1371
|
+
for (const line of written) console.log(kleur6.dim(` ${line}`));
|
|
1372
|
+
console.log(kleur6.dim(" \u2713 git config core.hooksPath .githooks"));
|
|
1373
|
+
console.log(kleur6.green(`
|
|
1374
|
+
\u2713 Repaired ${kleur6.bold(basename2(hubDir))}
|
|
1375
|
+
`));
|
|
1376
|
+
console.log(kleur6.dim(" Git hooks are now active for this clone:"));
|
|
1377
|
+
console.log(kleur6.dim(" \u2022 commit-msg \u2192 enforces Conventional Commits"));
|
|
1378
|
+
console.log(kleur6.dim(" \u2022 post-commit \u2192 auto-updates template CHANGELOG.md"));
|
|
1379
|
+
console.log("");
|
|
1380
|
+
console.log(kleur6.dim(" For AI changelog descriptions (optional):"));
|
|
1381
|
+
console.log(kleur6.dim(" cp tools/changelog/.env.example tools/changelog/.env"));
|
|
1382
|
+
console.log(kleur6.dim(" # add ANTHROPIC_API_KEY to tools/changelog/.env"));
|
|
1383
|
+
console.log("");
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1309
1386
|
// src/index.ts
|
|
1310
1387
|
var require2 = createRequire(import.meta.url);
|
|
1311
1388
|
async function main(argv) {
|
|
@@ -1321,7 +1398,10 @@ async function main(argv) {
|
|
|
1321
1398
|
if (subcommand === "hub") {
|
|
1322
1399
|
return runHub();
|
|
1323
1400
|
}
|
|
1324
|
-
|
|
1401
|
+
if (subcommand === "repair") {
|
|
1402
|
+
return runRepair();
|
|
1403
|
+
}
|
|
1404
|
+
console.log(kleur7.bold().cyan("\n \u25C6 dokio create\n"));
|
|
1325
1405
|
const { action } = await prompts3(
|
|
1326
1406
|
{
|
|
1327
1407
|
type: "select",
|
|
@@ -1334,7 +1414,7 @@ async function main(argv) {
|
|
|
1334
1414
|
},
|
|
1335
1415
|
{
|
|
1336
1416
|
onCancel: () => {
|
|
1337
|
-
console.log(
|
|
1417
|
+
console.log(kleur7.yellow("\n Cancelled.\n"));
|
|
1338
1418
|
process.exit(0);
|
|
1339
1419
|
}
|
|
1340
1420
|
}
|