@bleedingdev/modern-js-create 3.2.0-ultramodern.85 → 3.2.0-ultramodern.86
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 +90 -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: {
|
|
@@ -4876,7 +4877,7 @@ assert(rootPackage.scripts?.['cloudflare:deploy'] === expectedCloudflareDeploySc
|
|
|
4876
4877
|
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
4878
|
assert(rootPackage.scripts?.['skills:install'] === 'node ./scripts/bootstrap-agent-skills.mjs', 'Root must expose skills:install');
|
|
4878
4879
|
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
|
|
4880
|
+
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
4881
|
|
|
4881
4882
|
const expectedAppIds = ['shell-super-app', ...fullStackVerticals.map(vertical => vertical.id)];
|
|
4882
4883
|
const expectedCloudflareCompatibilityFlags = ['nodejs_compat', 'global_fetch_strictly_public'];
|
|
@@ -6236,6 +6237,91 @@ function writeSingleAppPackageSourceEvidence(targetDir, packageSource, useWorksp
|
|
|
6236
6237
|
});
|
|
6237
6238
|
node_fs.writeFileSync(evidencePath, `${JSON.stringify(createSingleAppPackageSourceEvidence(packageSource, useWorkspaceProtocol), null, 2)}\n`);
|
|
6238
6239
|
}
|
|
6240
|
+
function runSetupCommand(command, args, options = {}) {
|
|
6241
|
+
return execFileSync(command, args, {
|
|
6242
|
+
cwd: options.cwd,
|
|
6243
|
+
encoding: 'utf-8',
|
|
6244
|
+
stdio: options.stdio ?? [
|
|
6245
|
+
'ignore',
|
|
6246
|
+
'pipe',
|
|
6247
|
+
'pipe'
|
|
6248
|
+
]
|
|
6249
|
+
});
|
|
6250
|
+
}
|
|
6251
|
+
function commandExists(command) {
|
|
6252
|
+
try {
|
|
6253
|
+
runSetupCommand(command, [
|
|
6254
|
+
'--version'
|
|
6255
|
+
], {
|
|
6256
|
+
stdio: 'ignore'
|
|
6257
|
+
});
|
|
6258
|
+
return true;
|
|
6259
|
+
} catch {
|
|
6260
|
+
return false;
|
|
6261
|
+
}
|
|
6262
|
+
}
|
|
6263
|
+
function installGitForGeneratedProject() {
|
|
6264
|
+
if (commandExists('git')) return;
|
|
6265
|
+
const runShell = (script)=>runSetupCommand('sh', [
|
|
6266
|
+
'-lc',
|
|
6267
|
+
script
|
|
6268
|
+
], {
|
|
6269
|
+
stdio: 'inherit'
|
|
6270
|
+
});
|
|
6271
|
+
const sudo = 'function' == typeof process.getuid && 0 === process.getuid() ? '' : 'sudo ';
|
|
6272
|
+
if (commandExists('brew')) runSetupCommand('brew', [
|
|
6273
|
+
'install',
|
|
6274
|
+
'git'
|
|
6275
|
+
], {
|
|
6276
|
+
stdio: 'inherit'
|
|
6277
|
+
});
|
|
6278
|
+
else if ('linux' === process.platform && commandExists('apt-get')) runShell(`${sudo}apt-get update && ${sudo}apt-get install -y git`);
|
|
6279
|
+
else if ('linux' === process.platform && commandExists('dnf')) runShell(`${sudo}dnf install -y git`);
|
|
6280
|
+
else if ('linux' === process.platform && commandExists('yum')) runShell(`${sudo}yum install -y git`);
|
|
6281
|
+
else if ('linux' === process.platform && commandExists('apk')) runShell('apk add --no-cache git');
|
|
6282
|
+
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.');
|
|
6283
|
+
}
|
|
6284
|
+
function isInsideGitWorkTree(targetDir) {
|
|
6285
|
+
try {
|
|
6286
|
+
return 'true' === runSetupCommand('git', [
|
|
6287
|
+
'rev-parse',
|
|
6288
|
+
'--is-inside-work-tree'
|
|
6289
|
+
], {
|
|
6290
|
+
cwd: targetDir
|
|
6291
|
+
}).trim();
|
|
6292
|
+
} catch {
|
|
6293
|
+
return false;
|
|
6294
|
+
}
|
|
6295
|
+
}
|
|
6296
|
+
function initializeGeneratedGitRepository(targetDir) {
|
|
6297
|
+
installGitForGeneratedProject();
|
|
6298
|
+
if (isInsideGitWorkTree(targetDir)) return;
|
|
6299
|
+
try {
|
|
6300
|
+
runSetupCommand('git', [
|
|
6301
|
+
'init',
|
|
6302
|
+
'-b',
|
|
6303
|
+
'main'
|
|
6304
|
+
], {
|
|
6305
|
+
cwd: targetDir,
|
|
6306
|
+
stdio: 'inherit'
|
|
6307
|
+
});
|
|
6308
|
+
} catch {
|
|
6309
|
+
runSetupCommand('git', [
|
|
6310
|
+
'init'
|
|
6311
|
+
], {
|
|
6312
|
+
cwd: targetDir,
|
|
6313
|
+
stdio: 'inherit'
|
|
6314
|
+
});
|
|
6315
|
+
runSetupCommand('git', [
|
|
6316
|
+
'branch',
|
|
6317
|
+
'-M',
|
|
6318
|
+
'main'
|
|
6319
|
+
], {
|
|
6320
|
+
cwd: targetDir,
|
|
6321
|
+
stdio: 'inherit'
|
|
6322
|
+
});
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6239
6325
|
function isDirectoryEmpty(dirPath) {
|
|
6240
6326
|
if (!node_fs.existsSync(dirPath)) return false;
|
|
6241
6327
|
try {
|
|
@@ -6361,6 +6447,7 @@ async function main() {
|
|
|
6361
6447
|
enableTailwind: detectTailwindFlag(),
|
|
6362
6448
|
packageSource: detectUltramodernPackageSource(args, ultramodernPackageVersion, createPackage)
|
|
6363
6449
|
});
|
|
6450
|
+
initializeGeneratedGitRepository(targetDir);
|
|
6364
6451
|
const dim = '\x1b[2m\x1b[3m';
|
|
6365
6452
|
const reset = '\x1b[0m';
|
|
6366
6453
|
console.log(`${i18n.t(localeKeys.message.success)}\n`);
|
|
@@ -6445,6 +6532,7 @@ async function main() {
|
|
|
6445
6532
|
node_fs.writeFileSync(targetPackageJson, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
6446
6533
|
writeTemplateManifestEvidence(targetDir, templateManifest);
|
|
6447
6534
|
writeSingleAppPackageSourceEvidence(targetDir, packageSource, useWorkspaceProtocol);
|
|
6535
|
+
if (!isSubproject) initializeGeneratedGitRepository(targetDir);
|
|
6448
6536
|
const dim = '\x1b[2m\x1b[3m';
|
|
6449
6537
|
const reset = '\x1b[0m';
|
|
6450
6538
|
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.86",
|
|
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.86"
|
|
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.86"
|
|
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();
|