@bleedingdev/modern-js-create 3.2.0-ultramodern.85 → 3.2.0-ultramodern.87
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/dist/index.js +93 -2
- package/package.json +3 -3
- package/template/api/effect/index.ts.handlebars +19 -8
- package/template/scripts/bootstrap-agent-skills.mjs +25 -6
- package/template/src/routes/[lang]/page.tsx.handlebars +4 -1
- package/template-workspace/AGENTS.md +1 -1
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +124 -23
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
1
2
|
import node_crypto from "node:crypto";
|
|
2
3
|
import node_fs from "node:fs";
|
|
3
4
|
import node_path from "node:path";
|
|
@@ -1010,7 +1011,7 @@ function createRootPackageJson(scope, packageSource, remotes = []) {
|
|
|
1010
1011
|
'ultramodern:assert-mf-types': "node ./scripts/assert-mf-types.mjs",
|
|
1011
1012
|
'ultramodern:check': "node ./scripts/validate-ultramodern-workspace.mjs",
|
|
1012
1013
|
'ultramodern:i18n-boundaries': "node ./scripts/check-ultramodern-i18n-boundaries.mjs",
|
|
1013
|
-
postinstall: "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mjs && node ./scripts/setup-agent-reference-repos.mjs
|
|
1014
|
+
postinstall: "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mjs && node ./scripts/setup-agent-reference-repos.mjs",
|
|
1014
1015
|
check: 'pnpm format:check && pnpm lint && pnpm typecheck && pnpm skills:check && pnpm ultramodern:i18n-boundaries && pnpm ultramodern:check'
|
|
1015
1016
|
},
|
|
1016
1017
|
engines: {
|
|
@@ -1178,6 +1179,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
1178
1179
|
private: true,
|
|
1179
1180
|
name: ultramodern_workspace_packageName(scope, app.packageSuffix),
|
|
1180
1181
|
version: '0.1.0',
|
|
1182
|
+
type: 'module',
|
|
1181
1183
|
scripts: {
|
|
1182
1184
|
dev: 'modern dev',
|
|
1183
1185
|
build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mjs` : 'ULTRAMODERN_ZEPHYR=false modern build',
|
|
@@ -4876,7 +4878,7 @@ assert(rootPackage.scripts?.['cloudflare:deploy'] === expectedCloudflareDeploySc
|
|
|
4876
4878
|
assert(rootPackage.scripts?.['cloudflare:proof'] === 'node ./scripts/proof-cloudflare-version.mjs --out .codex/reports/cloudflare-version-proof/public-url-proof.json', 'Root must expose cloudflare:proof');
|
|
4877
4879
|
assert(rootPackage.scripts?.['skills:install'] === 'node ./scripts/bootstrap-agent-skills.mjs', 'Root must expose skills:install');
|
|
4878
4880
|
assert(rootPackage.scripts?.['skills:check'] === 'node ./scripts/bootstrap-agent-skills.mjs --check', 'Root must expose skills:check');
|
|
4879
|
-
assert(rootPackage.scripts?.postinstall === "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mjs && node ./scripts/setup-agent-reference-repos.mjs
|
|
4881
|
+
assert(rootPackage.scripts?.postinstall === "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mjs && node ./scripts/setup-agent-reference-repos.mjs", 'Root postinstall must format, bootstrap agent skills, initialize git/hooks, and install reference repositories');
|
|
4880
4882
|
|
|
4881
4883
|
const expectedAppIds = ['shell-super-app', ...fullStackVerticals.map(vertical => vertical.id)];
|
|
4882
4884
|
const expectedCloudflareCompatibilityFlags = ['nodejs_compat', 'global_fetch_strictly_public'];
|
|
@@ -4906,6 +4908,7 @@ assert(
|
|
|
4906
4908
|
JSON.stringify(expectedZephyrDependencies),
|
|
4907
4909
|
'Shell Zephyr dependencies must reference every vertical package',
|
|
4908
4910
|
);
|
|
4911
|
+
assert(shellPackage.type === 'module', 'Shell package must use ESM module mode');
|
|
4909
4912
|
const shellContract = generatedContract.apps?.find(app => app.id === 'shell-super-app');
|
|
4910
4913
|
assert(shellContract?.deploy?.cloudflare?.workerName === expectedWorkerName('shell-super-app'), 'Shell Cloudflare workerName is incorrect');
|
|
4911
4914
|
assert(shellContract?.deploy?.cloudflare?.publicUrlEnv === 'ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP', 'Shell Cloudflare public URL env is incorrect');
|
|
@@ -4932,6 +4935,7 @@ assert(!('effectServices' in topology), 'Default APIs must be vertical-owned, no
|
|
|
4932
4935
|
for (const vertical of fullStackVerticals) {
|
|
4933
4936
|
const packageJson = readJson(\`\${vertical.path}/package.json\`);
|
|
4934
4937
|
assert(packageJson.name === vertical.packageName, \`\${vertical.id} package name is incorrect\`);
|
|
4938
|
+
assert(packageJson.type === 'module', \`\${vertical.id} package must use ESM module mode\`);
|
|
4935
4939
|
assert(packageJson.scripts?.['cloudflare:deploy'] === 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json', \`\${vertical.id} must expose cloudflare:deploy\`);
|
|
4936
4940
|
assert(packageJson.scripts?.['cloudflare:proof']?.includes(\`--app \${vertical.id}\`), \`\${vertical.id} must expose cloudflare:proof\`);
|
|
4937
4941
|
assert(packageJson.dependencies?.['@modern-js/plugin-bff'], \`\${vertical.id} must depend on plugin-bff\`);
|
|
@@ -6236,6 +6240,91 @@ function writeSingleAppPackageSourceEvidence(targetDir, packageSource, useWorksp
|
|
|
6236
6240
|
});
|
|
6237
6241
|
node_fs.writeFileSync(evidencePath, `${JSON.stringify(createSingleAppPackageSourceEvidence(packageSource, useWorkspaceProtocol), null, 2)}\n`);
|
|
6238
6242
|
}
|
|
6243
|
+
function runSetupCommand(command, args, options = {}) {
|
|
6244
|
+
return execFileSync(command, args, {
|
|
6245
|
+
cwd: options.cwd,
|
|
6246
|
+
encoding: 'utf-8',
|
|
6247
|
+
stdio: options.stdio ?? [
|
|
6248
|
+
'ignore',
|
|
6249
|
+
'pipe',
|
|
6250
|
+
'pipe'
|
|
6251
|
+
]
|
|
6252
|
+
});
|
|
6253
|
+
}
|
|
6254
|
+
function commandExists(command) {
|
|
6255
|
+
try {
|
|
6256
|
+
runSetupCommand(command, [
|
|
6257
|
+
'--version'
|
|
6258
|
+
], {
|
|
6259
|
+
stdio: 'ignore'
|
|
6260
|
+
});
|
|
6261
|
+
return true;
|
|
6262
|
+
} catch {
|
|
6263
|
+
return false;
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
function installGitForGeneratedProject() {
|
|
6267
|
+
if (commandExists('git')) return;
|
|
6268
|
+
const runShell = (script)=>runSetupCommand('sh', [
|
|
6269
|
+
'-lc',
|
|
6270
|
+
script
|
|
6271
|
+
], {
|
|
6272
|
+
stdio: 'inherit'
|
|
6273
|
+
});
|
|
6274
|
+
const sudo = 'function' == typeof process.getuid && 0 === process.getuid() ? '' : 'sudo ';
|
|
6275
|
+
if (commandExists('brew')) runSetupCommand('brew', [
|
|
6276
|
+
'install',
|
|
6277
|
+
'git'
|
|
6278
|
+
], {
|
|
6279
|
+
stdio: 'inherit'
|
|
6280
|
+
});
|
|
6281
|
+
else if ('linux' === process.platform && commandExists('apt-get')) runShell(`${sudo}apt-get update && ${sudo}apt-get install -y git`);
|
|
6282
|
+
else if ('linux' === process.platform && commandExists('dnf')) runShell(`${sudo}dnf install -y git`);
|
|
6283
|
+
else if ('linux' === process.platform && commandExists('yum')) runShell(`${sudo}yum install -y git`);
|
|
6284
|
+
else if ('linux' === process.platform && commandExists('apk')) runShell('apk add --no-cache git');
|
|
6285
|
+
if (!commandExists('git')) throw new Error('Git is required for UltraModern setup. Install git and rerun create, or run pnpm skills:install after installing git.');
|
|
6286
|
+
}
|
|
6287
|
+
function isInsideGitWorkTree(targetDir) {
|
|
6288
|
+
try {
|
|
6289
|
+
return 'true' === runSetupCommand('git', [
|
|
6290
|
+
'rev-parse',
|
|
6291
|
+
'--is-inside-work-tree'
|
|
6292
|
+
], {
|
|
6293
|
+
cwd: targetDir
|
|
6294
|
+
}).trim();
|
|
6295
|
+
} catch {
|
|
6296
|
+
return false;
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
function initializeGeneratedGitRepository(targetDir) {
|
|
6300
|
+
installGitForGeneratedProject();
|
|
6301
|
+
if (isInsideGitWorkTree(targetDir)) return;
|
|
6302
|
+
try {
|
|
6303
|
+
runSetupCommand('git', [
|
|
6304
|
+
'init',
|
|
6305
|
+
'-b',
|
|
6306
|
+
'main'
|
|
6307
|
+
], {
|
|
6308
|
+
cwd: targetDir,
|
|
6309
|
+
stdio: 'inherit'
|
|
6310
|
+
});
|
|
6311
|
+
} catch {
|
|
6312
|
+
runSetupCommand('git', [
|
|
6313
|
+
'init'
|
|
6314
|
+
], {
|
|
6315
|
+
cwd: targetDir,
|
|
6316
|
+
stdio: 'inherit'
|
|
6317
|
+
});
|
|
6318
|
+
runSetupCommand('git', [
|
|
6319
|
+
'branch',
|
|
6320
|
+
'-M',
|
|
6321
|
+
'main'
|
|
6322
|
+
], {
|
|
6323
|
+
cwd: targetDir,
|
|
6324
|
+
stdio: 'inherit'
|
|
6325
|
+
});
|
|
6326
|
+
}
|
|
6327
|
+
}
|
|
6239
6328
|
function isDirectoryEmpty(dirPath) {
|
|
6240
6329
|
if (!node_fs.existsSync(dirPath)) return false;
|
|
6241
6330
|
try {
|
|
@@ -6361,6 +6450,7 @@ async function main() {
|
|
|
6361
6450
|
enableTailwind: detectTailwindFlag(),
|
|
6362
6451
|
packageSource: detectUltramodernPackageSource(args, ultramodernPackageVersion, createPackage)
|
|
6363
6452
|
});
|
|
6453
|
+
initializeGeneratedGitRepository(targetDir);
|
|
6364
6454
|
const dim = '\x1b[2m\x1b[3m';
|
|
6365
6455
|
const reset = '\x1b[0m';
|
|
6366
6456
|
console.log(`${i18n.t(localeKeys.message.success)}\n`);
|
|
@@ -6445,6 +6535,7 @@ async function main() {
|
|
|
6445
6535
|
node_fs.writeFileSync(targetPackageJson, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
6446
6536
|
writeTemplateManifestEvidence(targetDir, templateManifest);
|
|
6447
6537
|
writeSingleAppPackageSourceEvidence(targetDir, packageSource, useWorkspaceProtocol);
|
|
6538
|
+
if (!isSubproject) initializeGeneratedGitRepository(targetDir);
|
|
6448
6539
|
const dim = '\x1b[2m\x1b[3m';
|
|
6449
6540
|
const reset = '\x1b[0m';
|
|
6450
6541
|
console.log(`${i18n.t(localeKeys.message.success)}\n`);
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
|
-
"version": "3.2.0-ultramodern.
|
|
24
|
+
"version": "3.2.0-ultramodern.87",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"main": "./dist/index.js",
|
|
27
27
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/node": "^25.9.1",
|
|
42
42
|
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
43
43
|
"tsx": "^4.22.3",
|
|
44
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.
|
|
44
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.87"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"start": "node ./dist/index.js"
|
|
55
55
|
},
|
|
56
56
|
"ultramodern": {
|
|
57
|
-
"frameworkVersion": "3.2.0-ultramodern.
|
|
57
|
+
"frameworkVersion": "3.2.0-ultramodern.87"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -4,18 +4,29 @@
|
|
|
4
4
|
Layer,
|
|
5
5
|
defineEffectBff,
|
|
6
6
|
} from '@modern-js/plugin-bff/effect-server';
|
|
7
|
+
import type { HttpApi, HttpApiGroup } from '@modern-js/plugin-bff/effect-server';
|
|
7
8
|
import { bffEffectApi } from '../../shared/effect/api';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
type ApiGroups<TApi> = TApi extends HttpApi.HttpApi<string, infer TGroups> ? TGroups : never;
|
|
11
|
+
type GreetingsHandlers = HttpApiBuilder.Handlers.FromGroup<
|
|
12
|
+
HttpApiGroup.WithName<ApiGroups<typeof bffEffectApi>, 'greetings'>
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
const greetingsLayer = HttpApiBuilder.group(
|
|
16
|
+
bffEffectApi,
|
|
17
|
+
'greetings',
|
|
18
|
+
(handlers: GreetingsHandlers) =>
|
|
19
|
+
handlers.handle('hello', () =>
|
|
20
|
+
Effect.succeed({
|
|
21
|
+
message: 'Hello from Effect HttpApi',
|
|
22
|
+
runtime: 'effect' as const,
|
|
23
|
+
}),
|
|
24
|
+
),
|
|
16
25
|
);
|
|
17
26
|
|
|
18
|
-
const layer = HttpApiBuilder.layer(bffEffectApi).pipe(
|
|
27
|
+
const layer = HttpApiBuilder.layer(bffEffectApi).pipe(
|
|
28
|
+
Layer.provide(greetingsLayer),
|
|
29
|
+
);
|
|
19
30
|
|
|
20
31
|
export default defineEffectBff({
|
|
21
32
|
api: bffEffectApi,
|
|
@@ -96,15 +96,34 @@ const removeTree = (dir) =>
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
const cloneSource = (source, targetDir) => {
|
|
99
|
+
if (source.commit) {
|
|
100
|
+
run('git', ['init', targetDir]);
|
|
101
|
+
run('git', ['remote', 'add', 'origin', source.repository], {
|
|
102
|
+
cwd: targetDir,
|
|
103
|
+
});
|
|
104
|
+
run('git', ['fetch', '--depth', '1', '--quiet', 'origin', source.commit], {
|
|
105
|
+
cwd: targetDir,
|
|
106
|
+
});
|
|
107
|
+
run(
|
|
108
|
+
'git',
|
|
109
|
+
[
|
|
110
|
+
'-c',
|
|
111
|
+
'advice.detachedHead=false',
|
|
112
|
+
'checkout',
|
|
113
|
+
'--detach',
|
|
114
|
+
'--quiet',
|
|
115
|
+
'FETCH_HEAD',
|
|
116
|
+
],
|
|
117
|
+
{ cwd: targetDir },
|
|
118
|
+
);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
99
122
|
const repo = source.repository.replace(/^https:\/\/github.com\//u, '');
|
|
100
123
|
try {
|
|
101
|
-
run('gh', ['repo', 'clone', repo, targetDir, '--', '--depth', '1'
|
|
102
|
-
stdio: 'inherit',
|
|
103
|
-
});
|
|
124
|
+
run('gh', ['repo', 'clone', repo, targetDir, '--', '--depth', '1', '--quiet']);
|
|
104
125
|
} catch {
|
|
105
|
-
run('git', ['clone', '--depth', '1', source.repository, targetDir]
|
|
106
|
-
stdio: 'inherit',
|
|
107
|
-
});
|
|
126
|
+
run('git', ['clone', '--depth', '1', '--quiet', source.repository, targetDir]);
|
|
108
127
|
}
|
|
109
128
|
};
|
|
110
129
|
|
|
@@ -7,6 +7,9 @@ import { useEffect, useState } from 'react';
|
|
|
7
7
|
{{/if}}
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
|
|
10
|
+
{{#if useEffectBff}}type GreetingResponse = Awaited<ReturnType<typeof effectBff.client.greetings.hello>>;
|
|
11
|
+
|
|
12
|
+
{{/if}}
|
|
10
13
|
const fallbackLanguage = 'en';
|
|
11
14
|
const supportedLanguages = ['en', 'cs'] as const;
|
|
12
15
|
type SupportedLanguage = (typeof supportedLanguages)[number];
|
|
@@ -62,7 +65,7 @@ const Index = () => {
|
|
|
62
65
|
let mounted = true;
|
|
63
66
|
Effect.runFork(
|
|
64
67
|
Effect.promise(() => effectBff.client.greetings.hello({})).pipe(
|
|
65
|
-
Effect.tap((data) =>
|
|
68
|
+
Effect.tap((data: GreetingResponse) =>
|
|
66
69
|
Effect.sync(() => {
|
|
67
70
|
if (mounted) {
|
|
68
71
|
setEffectMessage(data.message);
|
|
@@ -11,7 +11,7 @@ instructions, not optional reading.
|
|
|
11
11
|
- `pnpm typecheck` runs effect-tsgo as the TypeScript checker.
|
|
12
12
|
- `pnpm check` runs formatting, linting, effect-tsgo, private-skill availability checks, and the generated workspace contract.
|
|
13
13
|
- Generated Codex stop hooks and subagent-stop hooks run `pnpm format && pnpm lint:fix && pnpm check`.
|
|
14
|
-
- `postinstall` formats the generated tree, installs agent skills and reference repos, then installs `lefthook
|
|
14
|
+
- `postinstall` formats the generated tree, initializes Git when needed, installs agent skills and reference repos, then installs `lefthook`. Generated `lefthook.yml` runs `pnpm format && pnpm lint:fix && pnpm check` on pre-commit; pre-push runs `pnpm check`.
|
|
15
15
|
|
|
16
16
|
## Localized Routes
|
|
17
17
|
|
|
@@ -17,6 +17,85 @@ const run = (command, args, options = {}) =>
|
|
|
17
17
|
stdio: options.stdio ?? ['ignore', 'pipe', 'pipe'],
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
+
const commandExists = command => {
|
|
21
|
+
try {
|
|
22
|
+
run(command, ['--version'], { stdio: 'ignore' });
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const runShell = script =>
|
|
30
|
+
run('sh', ['-lc', script], {
|
|
31
|
+
stdio: 'inherit',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const installGit = () => {
|
|
35
|
+
if (commandExists('git')) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (commandExists('brew')) {
|
|
40
|
+
run('brew', ['install', 'git'], { stdio: 'inherit' });
|
|
41
|
+
} else if (process.platform === 'linux' && commandExists('apt-get')) {
|
|
42
|
+
const sudo =
|
|
43
|
+
typeof process.getuid === 'function' && process.getuid() === 0
|
|
44
|
+
? ''
|
|
45
|
+
: 'sudo ';
|
|
46
|
+
runShell(`${sudo}apt-get update && ${sudo}apt-get install -y git`);
|
|
47
|
+
} else if (process.platform === 'linux' && commandExists('dnf')) {
|
|
48
|
+
const sudo =
|
|
49
|
+
typeof process.getuid === 'function' && process.getuid() === 0
|
|
50
|
+
? ''
|
|
51
|
+
: 'sudo ';
|
|
52
|
+
runShell(`${sudo}dnf install -y git`);
|
|
53
|
+
} else if (process.platform === 'linux' && commandExists('yum')) {
|
|
54
|
+
const sudo =
|
|
55
|
+
typeof process.getuid === 'function' && process.getuid() === 0
|
|
56
|
+
? ''
|
|
57
|
+
: 'sudo ';
|
|
58
|
+
runShell(`${sudo}yum install -y git`);
|
|
59
|
+
} else if (process.platform === 'linux' && commandExists('apk')) {
|
|
60
|
+
runShell('apk add --no-cache git');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!commandExists('git')) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
'Git is required for UltraModern setup. Install git and run pnpm skills:install again.',
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const isInsideGitWorkTree = () => {
|
|
71
|
+
try {
|
|
72
|
+
return run('git', ['rev-parse', '--is-inside-work-tree']).trim() === 'true';
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const initializeGitRepository = () => {
|
|
79
|
+
if (isInsideGitWorkTree()) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
run('git', ['init', '-b', 'main'], { stdio: 'inherit' });
|
|
85
|
+
} catch {
|
|
86
|
+
run('git', ['init'], { stdio: 'inherit' });
|
|
87
|
+
run('git', ['branch', '-M', 'main'], { stdio: 'inherit' });
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const installLefthook = () => {
|
|
92
|
+
try {
|
|
93
|
+
run('lefthook', ['install'], { stdio: 'inherit' });
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.warn(`Unable to install lefthook hooks: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
20
99
|
const removeTree = dir =>
|
|
21
100
|
fs.rmSync(dir, {
|
|
22
101
|
force: true,
|
|
@@ -26,32 +105,50 @@ const removeTree = dir =>
|
|
|
26
105
|
});
|
|
27
106
|
|
|
28
107
|
const cloneSource = (source, targetDir) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
run('
|
|
32
|
-
|
|
108
|
+
if (source.commit) {
|
|
109
|
+
run('git', ['init', targetDir]);
|
|
110
|
+
run('git', ['remote', 'add', 'origin', source.repository], {
|
|
111
|
+
cwd: targetDir,
|
|
33
112
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
stdio: 'inherit',
|
|
113
|
+
run('git', ['fetch', '--depth', '1', '--quiet', 'origin', source.commit], {
|
|
114
|
+
cwd: targetDir,
|
|
37
115
|
});
|
|
116
|
+
run(
|
|
117
|
+
'git',
|
|
118
|
+
[
|
|
119
|
+
'-c',
|
|
120
|
+
'advice.detachedHead=false',
|
|
121
|
+
'checkout',
|
|
122
|
+
'--detach',
|
|
123
|
+
'--quiet',
|
|
124
|
+
'FETCH_HEAD',
|
|
125
|
+
],
|
|
126
|
+
{ cwd: targetDir },
|
|
127
|
+
);
|
|
128
|
+
return;
|
|
38
129
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
130
|
+
|
|
131
|
+
const repo = source.repository.replace(/^https:\/\/github.com\//u, '');
|
|
132
|
+
try {
|
|
133
|
+
run('gh', [
|
|
134
|
+
'repo',
|
|
135
|
+
'clone',
|
|
136
|
+
repo,
|
|
137
|
+
targetDir,
|
|
138
|
+
'--',
|
|
139
|
+
'--depth',
|
|
140
|
+
'1',
|
|
141
|
+
'--quiet',
|
|
142
|
+
]);
|
|
143
|
+
} catch {
|
|
144
|
+
run('git', [
|
|
145
|
+
'clone',
|
|
146
|
+
'--depth',
|
|
147
|
+
'1',
|
|
148
|
+
'--quiet',
|
|
149
|
+
source.repository,
|
|
150
|
+
targetDir,
|
|
151
|
+
]);
|
|
55
152
|
}
|
|
56
153
|
};
|
|
57
154
|
|
|
@@ -124,6 +221,8 @@ if (checkOnly) {
|
|
|
124
221
|
}
|
|
125
222
|
|
|
126
223
|
fs.mkdirSync(installDir, { recursive: true });
|
|
224
|
+
installGit();
|
|
225
|
+
initializeGitRepository();
|
|
127
226
|
|
|
128
227
|
for (const source of [...requiredCloneSources, ...optionalCloneSources]) {
|
|
129
228
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ultramodern-skills-'));
|
|
@@ -161,3 +260,5 @@ for (const source of [...requiredCloneSources, ...optionalCloneSources]) {
|
|
|
161
260
|
removeTree(tempDir);
|
|
162
261
|
}
|
|
163
262
|
}
|
|
263
|
+
|
|
264
|
+
installLefthook();
|