create-adk-agent 0.0.1 โ†’ 0.0.5

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.
Files changed (37) hide show
  1. package/README.md +77 -25
  2. package/bin/create-adk-agent.js +364 -0
  3. package/dist/generators/init/files/.env.example.template +16 -0
  4. package/dist/generators/init/files/.eslintrc.json.template +20 -0
  5. package/dist/generators/init/files/.gitignore.template +27 -0
  6. package/dist/generators/init/files/.prettierrc.template +7 -0
  7. package/dist/generators/init/files/README.md.template +243 -0
  8. package/dist/generators/init/files/jest.config.ts.template +7 -0
  9. package/dist/generators/init/files/package.json.template +41 -0
  10. package/dist/generators/init/files/src/agents/basic/agent.ts.template +34 -0
  11. package/dist/generators/init/files/src/agents/multi-tool/agent.ts.template +83 -0
  12. package/dist/generators/init/files/src/agents/streaming/agent.ts.template +36 -0
  13. package/dist/generators/init/files/src/agents/team/farewell-agent.ts.template +43 -0
  14. package/dist/generators/init/files/src/agents/team/greeting-agent.ts.template +43 -0
  15. package/dist/generators/init/files/src/agents/team/root-agent.ts.template +18 -0
  16. package/dist/generators/init/files/src/agents/workflow/agent.ts.template +69 -0
  17. package/dist/generators/init/files/src/index.ts.template +61 -0
  18. package/dist/generators/init/files/tests/agents.test.ts.template +80 -0
  19. package/dist/generators/init/files/tsconfig.json.template +20 -0
  20. package/dist/generators/init/files/vite.config.ts.template +36 -0
  21. package/dist/generators/init/generator.js +3 -0
  22. package/dist/generators/init/generator.js.map +1 -1
  23. package/dist/generators/init/schema.json +124 -0
  24. package/package.json +25 -5
  25. package/src/generators/init/files/README.md.template +3 -2
  26. package/src/generators/init/files/package.json.template +8 -6
  27. package/src/generators/init/files/vite.config.ts.template +36 -0
  28. package/templates/basic/.env.example +16 -0
  29. package/templates/basic/.eslintrc.json +13 -0
  30. package/templates/basic/.prettierrc +5 -0
  31. package/templates/basic/README.md +155 -0
  32. package/templates/basic/_gitignore +8 -0
  33. package/templates/basic/jest.config.ts +8 -0
  34. package/templates/basic/package.json +41 -0
  35. package/templates/basic/src/index.ts +60 -0
  36. package/templates/basic/tests/agents.test.ts +19 -0
  37. package/templates/basic/tsconfig.json +21 -0
package/README.md CHANGED
@@ -1,31 +1,57 @@
1
- # @adk-ts-new/create-adk-agent
1
+ # create-adk-agent
2
2
 
3
- > Nx generator for scaffolding ADK (Agent Development Kit) TypeScript projects with multiple templates, multi-model support, and modern tooling.
3
+ > **The fastest way to start building with Google's Agent Development Kit (ADK)**
4
4
 
5
- ## ๐Ÿš€ Quick Start
5
+ Scaffold production-ready ADK TypeScript projects in seconds with best practices, multiple templates, and zero configuration.
6
+
7
+ **What is ADK?** The [Agent Development Kit](https://google.github.io/adk-docs/) is Google's framework for building AI agents. This tool makes it easy to get started.
6
8
 
7
- ### Using npx (Recommended)
9
+ ## ๐Ÿš€ Quick Start
8
10
 
9
11
  ```bash
10
- npx @adk-ts-new/create-adk-agent my-agent
12
+ npx create-adk-agent my-agent
11
13
  ```
12
14
 
13
- ### Using Nx workspace
15
+ Or use it non-interactively:
14
16
 
15
17
  ```bash
16
- nx g @adk-ts-new/create-adk-agent:init my-agent
18
+ npx create-adk-agent my-agent --template=basic --modelProvider=gemini --model=gemini-2.0-flash
17
19
  ```
18
20
 
19
- ## โœจ Features
21
+ That's it! You'll get a fully configured ADK project with:
22
+
23
+ - โœ… TypeScript configured for ADK (ES2022, NodeNext)
24
+ - โœ… Environment setup with API key validation
25
+ - โœ… Working agent examples from official docs
26
+ - โœ… Hot reload development with tsx
27
+ - โœ… Testing setup with Jest
28
+ - โœ… All the tooling (ESLint, Prettier, etc.)
29
+
30
+ ## ๐Ÿ’ก Why Use This?
31
+
32
+ Instead of manually setting up TypeScript, configuring ESM, managing API keys, and copying examples from docs, `create-adk-agent` does it all for you in one command.
33
+
34
+ **Perfect for:**
20
35
 
21
- - ๐Ÿค– **Multiple Agent Templates** - Choose from 5 different agent templates from official ADK docs
22
- - ๐Ÿ”Œ **Multi-Model Support** - Works with Gemini, OpenAI, and Anthropic models
23
- - โšก **tsx Development** - Instant TypeScript execution with hot reload (no build step)
24
- - ๐Ÿ” **Security First** - Built-in `.env` management with clear security warnings
25
- - ๐Ÿงช **Testing Ready** - Pre-configured Jest testing setup
26
- - ๐Ÿ“ฆ **Modern Stack** - TypeScript, ESLint, Prettier, Zod validation
36
+ - ๐ŸŽ“ Learning ADK quickly with working examples
37
+ - ๐Ÿš€ Starting new ADK projects without boilerplate hassle
38
+ - ๐Ÿ“ฆ Getting ADK best practices out of the box
39
+ - ๐Ÿ”„ Experimenting with different agent patterns
27
40
 
28
- ## ๐Ÿ“‹ Agent Templates
41
+ ## โœจ What You Get
42
+
43
+ ## โœจ What You Get
44
+
45
+ - ๐Ÿค– **5 Agent Templates** - Pre-built examples from [official ADK docs](https://google.github.io/adk-docs/) (basic, multi-tool, team, streaming, workflow)
46
+ - ๐Ÿ”Œ **Multi-Model Ready** - Pre-configured for Gemini, OpenAI, and Anthropic
47
+ - โšก **Hot Reload** - Instant TypeScript execution with tsx (no build step needed)
48
+ - ๐Ÿ” **Security Built-in** - Proper `.env` handling with validation and git-ignore
49
+ - ๐Ÿงช **Testing Included** - Jest configured and ready to go
50
+ - ๐Ÿ“ฆ **Best Practices** - TypeScript, ESLint, Prettier, Zod validation
51
+
52
+ ## ๐Ÿ“š Agent Templates
53
+
54
+ All templates are based on [official ADK documentation examples](https://google.github.io/adk-docs/):
29
55
 
30
56
  ### Basic Agent
31
57
 
@@ -49,28 +75,31 @@ Sequential workflow patterns with validation, transformation, and saving steps.
49
75
 
50
76
  ## ๐ŸŽฏ Usage
51
77
 
52
- ### Interactive Mode
78
+ ### Simple (Interactive)
79
+
80
+ Just run the command and answer a few questions:
53
81
 
54
82
  ```bash
55
- npx @adk-ts-new/create-adk-agent my-agent
83
+ npx create-adk-agent my-agent
56
84
  ```
57
85
 
58
- You'll be prompted for:
86
+ You'll choose:
59
87
 
60
- - Agent templates to include
61
- - Model provider (Gemini/OpenAI/Anthropic)
62
- - Whether to install dependencies
88
+ - Which agent templates to include
89
+ - Your preferred model provider (Gemini, OpenAI, or Anthropic)
90
+ - Whether to install dependencies now
63
91
  - Whether to initialize git
64
92
 
65
- ### Non-Interactive Mode
93
+ ### Advanced (Non-Interactive)
94
+
95
+ Skip prompts by providing options:
66
96
 
67
97
  ```bash
68
- npx @adk-ts-new/create-adk-agent my-agent \
98
+ npx create-adk-agent my-agent \
69
99
  --templates=basic,multi-tool \
70
100
  --modelProvider=gemini \
71
101
  --model=gemini-3.0-flash \
72
102
  --description="My custom agent" \
73
- --directory=apps \
74
103
  --installDependencies \
75
104
  --no-interactive
76
105
  ```
@@ -114,7 +143,30 @@ npx @adk-ts-new/create-adk-agent my-agent \
114
143
 
115
144
  **Note:** You can change to any model after project generation. The list above is for initial setup convenience.
116
145
 
117
- ## ๐Ÿ“ฆ Generated Project Structure
146
+ ## ๐ŸŽฌ Getting Started Workflow
147
+
148
+ ```bash
149
+ # 1. Create your project (takes ~10 seconds)
150
+ npx create-adk-agent my-agent
151
+
152
+ # 2. Navigate to project
153
+ cd my-agent
154
+
155
+ # 3. Add your API key
156
+ cp .env.example .env
157
+ # Edit .env and add your API key (get it from links in the file)
158
+
159
+ # 4. Start coding! (hot reload enabled)
160
+ npm run dev
161
+
162
+ # 5. Or use ADK DevTools
163
+ npm run adk:web # Beautiful web UI
164
+ npm run adk:run # CLI runner
165
+ ```
166
+
167
+ **That's it!** You're now building with ADK. No complex setup, no configuration headaches.
168
+
169
+ ## ๐Ÿ”— Learn More About ADK
118
170
 
119
171
  ```
120
172
  my-agent/
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/env node
2
+
3
+ // @ts-check
4
+ import { blue, cyan, green, red, reset, yellow } from 'kolorist';
5
+ import minimist from 'minimist';
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import prompts from 'prompts';
10
+
11
+ const argv = minimist(process.argv.slice(2), { string: ['_'] });
12
+ const cwd = process.cwd();
13
+
14
+ // Template configurations
15
+ const TEMPLATES = [
16
+ {
17
+ name: 'basic',
18
+ display: 'Basic Agent',
19
+ description: 'Single agent with one tool (time example)',
20
+ color: green,
21
+ },
22
+ {
23
+ name: 'multi-tool',
24
+ display: 'Multi-Tool Agent',
25
+ description: 'Agent with multiple tools (recommended)',
26
+ color: blue,
27
+ },
28
+ {
29
+ name: 'streaming',
30
+ display: 'Streaming Agent',
31
+ description: 'Agent with Live API streaming support',
32
+ color: cyan,
33
+ },
34
+ {
35
+ name: 'team',
36
+ display: 'Multi-Agent Team',
37
+ description: 'Multiple agents working together',
38
+ color: yellow,
39
+ },
40
+ {
41
+ name: 'workflow',
42
+ display: 'Workflow Agent',
43
+ description: 'Sequential and parallel execution patterns',
44
+ color: yellow,
45
+ },
46
+ ];
47
+
48
+ // Model provider configurations
49
+ const MODEL_PROVIDERS = {
50
+ gemini: {
51
+ name: 'Google Gemini',
52
+ models: [
53
+ 'gemini-2.0-flash',
54
+ 'gemini-2.0-flash-thinking-exp-01-21',
55
+ 'gemini-1.5-pro',
56
+ ],
57
+ apiKeyVar: 'GEMINI_API_KEY',
58
+ importStatement: "import { LlmAgent, FunctionTool } from '@google/adk';",
59
+ modelConfig: (model) => `'${model}'`,
60
+ },
61
+ openai: {
62
+ name: 'OpenAI',
63
+ models: ['openai/gpt-4o', 'openai/gpt-4o-mini', 'openai/gpt-4-turbo'],
64
+ apiKeyVar: 'OPENAI_API_KEY',
65
+ importStatement:
66
+ "import { LlmAgent, FunctionTool, LiteLlm } from '@google/adk';",
67
+ modelConfig: (model) => `new LiteLlm({ model: '${model}' })`,
68
+ },
69
+ anthropic: {
70
+ name: 'Anthropic (Claude)',
71
+ models: [
72
+ 'anthropic/claude-3-5-sonnet',
73
+ 'anthropic/claude-3-opus',
74
+ 'anthropic/claude-3-haiku',
75
+ ],
76
+ apiKeyVar: 'ANTHROPIC_API_KEY',
77
+ importStatement:
78
+ "import { LlmAgent, FunctionTool, LiteLlm } from '@google/adk';",
79
+ modelConfig: (model) => `new LiteLlm({ model: '${model}' })`,
80
+ },
81
+ };
82
+
83
+ const renameFiles = {
84
+ _gitignore: '.gitignore',
85
+ };
86
+
87
+ function formatTargetDir(targetDir) {
88
+ return targetDir?.trim().replace(/\/+$/g, '');
89
+ }
90
+
91
+ function isValidPackageName(projectName) {
92
+ return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(
93
+ projectName,
94
+ );
95
+ }
96
+
97
+ function toValidPackageName(projectName) {
98
+ return projectName
99
+ .trim()
100
+ .toLowerCase()
101
+ .replace(/\s+/g, '-')
102
+ .replace(/^[._]/, '')
103
+ .replace(/[^a-z0-9-~]+/g, '-');
104
+ }
105
+
106
+ function copy(src, dest) {
107
+ const stat = fs.statSync(src);
108
+ if (stat.isDirectory()) {
109
+ copyDir(src, dest);
110
+ } else {
111
+ fs.copyFileSync(src, dest);
112
+ }
113
+ }
114
+
115
+ function copyDir(srcDir, destDir) {
116
+ fs.mkdirSync(destDir, { recursive: true });
117
+ for (const file of fs.readdirSync(srcDir)) {
118
+ const srcFile = path.resolve(srcDir, file);
119
+ const destFile = path.resolve(destDir, file);
120
+ copy(srcFile, destFile);
121
+ }
122
+ }
123
+
124
+ function isEmpty(pathToCheck) {
125
+ const files = fs.readdirSync(pathToCheck);
126
+ return files.length === 0 || (files.length === 1 && files[0] === '.git');
127
+ }
128
+
129
+ function emptyDir(dir) {
130
+ if (!fs.existsSync(dir)) {
131
+ return;
132
+ }
133
+ for (const file of fs.readdirSync(dir)) {
134
+ fs.rmSync(path.resolve(dir, file), { recursive: true, force: true });
135
+ }
136
+ }
137
+
138
+ function replacePlaceholders(root, files, config) {
139
+ for (const file of Array.isArray(files) ? files : [files]) {
140
+ const filePath = path.join(root, file);
141
+ if (!fs.existsSync(filePath)) continue;
142
+
143
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
144
+ const newFileContent = Object.keys(config).reduce(
145
+ (content, placeholder) =>
146
+ content.replace(new RegExp(placeholder, 'g'), config[placeholder]),
147
+ fileContent,
148
+ );
149
+ fs.writeFileSync(filePath, newFileContent);
150
+ }
151
+ }
152
+
153
+ async function init() {
154
+ let targetDir = formatTargetDir(argv._[0]);
155
+ let template = argv.template || argv.t;
156
+ let modelProvider = argv.modelProvider || argv.mp;
157
+ let model = argv.model || argv.m;
158
+ let description = argv.description || argv.d;
159
+
160
+ const defaultTargetDir = 'my-adk-agent';
161
+ const getProjectName = () =>
162
+ targetDir === '.' ? path.basename(path.resolve()) : targetDir;
163
+
164
+ let result = {};
165
+
166
+ try {
167
+ result = await prompts(
168
+ [
169
+ {
170
+ type: targetDir ? null : 'text',
171
+ name: 'projectName',
172
+ message: reset('Project name:'),
173
+ initial: defaultTargetDir,
174
+ onState: (state) => {
175
+ targetDir = formatTargetDir(state.value) || defaultTargetDir;
176
+ },
177
+ },
178
+ {
179
+ type: () =>
180
+ !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm',
181
+ name: 'overwrite',
182
+ message: () =>
183
+ (targetDir === '.'
184
+ ? 'Current directory'
185
+ : `Target directory "${targetDir}"`) +
186
+ ` is not empty. Remove existing files and continue?`,
187
+ },
188
+ {
189
+ type: (_, { overwrite } = {}) => {
190
+ if (overwrite === false) {
191
+ throw new Error(red('โœ–') + ' Operation cancelled');
192
+ }
193
+ return null;
194
+ },
195
+ name: 'overwriteChecker',
196
+ },
197
+ {
198
+ type: () => (isValidPackageName(getProjectName()) ? null : 'text'),
199
+ name: 'packageName',
200
+ message: reset('Package name:'),
201
+ initial: () => toValidPackageName(getProjectName()),
202
+ validate: (dir) =>
203
+ isValidPackageName(dir) || 'Invalid package.json name',
204
+ },
205
+ {
206
+ type: description ? null : 'text',
207
+ name: 'description',
208
+ message: reset('Project description:'),
209
+ initial: 'My ADK Agent',
210
+ },
211
+ {
212
+ type: template ? null : 'select',
213
+ name: 'template',
214
+ message: reset('Select a template:'),
215
+ choices: TEMPLATES.map((t) => ({
216
+ title: `${t.color(t.display)} - ${t.description}`,
217
+ value: t.name,
218
+ })),
219
+ },
220
+ {
221
+ type: modelProvider ? null : 'select',
222
+ name: 'modelProvider',
223
+ message: reset('Select LLM provider:'),
224
+ choices: Object.entries(MODEL_PROVIDERS).map(([key, value]) => ({
225
+ title: value.name,
226
+ value: key,
227
+ })),
228
+ },
229
+ {
230
+ type: (prev, values) => {
231
+ const provider = modelProvider || values.modelProvider;
232
+ return model || !provider ? null : 'select';
233
+ },
234
+ name: 'model',
235
+ message: reset('Select model:'),
236
+ choices: (prev, values) => {
237
+ const provider = modelProvider || values.modelProvider;
238
+ return MODEL_PROVIDERS[provider].models.map((m) => ({
239
+ title: m,
240
+ value: m,
241
+ }));
242
+ },
243
+ },
244
+ ],
245
+ {
246
+ onCancel: () => {
247
+ throw new Error(red('โœ–') + ' Operation cancelled');
248
+ },
249
+ },
250
+ );
251
+ } catch (cancelled) {
252
+ console.log(cancelled.message);
253
+ return;
254
+ }
255
+
256
+ // Extract values from prompts
257
+ const {
258
+ overwrite,
259
+ packageName,
260
+ description: promptDescription,
261
+ template: promptTemplate,
262
+ modelProvider: promptModelProvider,
263
+ model: promptModel,
264
+ } = result;
265
+
266
+ // Use CLI args or prompt values
267
+ template = template || promptTemplate || 'basic';
268
+ modelProvider = modelProvider || promptModelProvider || 'gemini';
269
+ model = model || promptModel || MODEL_PROVIDERS[modelProvider].models[0];
270
+ description = description || promptDescription || 'My ADK Agent';
271
+
272
+ const root = path.join(cwd, targetDir);
273
+
274
+ if (overwrite) {
275
+ emptyDir(root);
276
+ } else if (!fs.existsSync(root)) {
277
+ fs.mkdirSync(root, { recursive: true });
278
+ }
279
+
280
+ console.log(`\n${green('โœ“')} Scaffolding project in ${root}...\n`);
281
+
282
+ const templateDir = path.resolve(
283
+ fileURLToPath(import.meta.url),
284
+ '..',
285
+ '..',
286
+ 'templates',
287
+ template,
288
+ );
289
+
290
+ if (!fs.existsSync(templateDir)) {
291
+ console.error(red(`โœ– Error: Template "${template}" not found!`));
292
+ process.exit(1);
293
+ }
294
+
295
+ const write = (file, content) => {
296
+ const targetPath = renameFiles[file]
297
+ ? path.join(root, renameFiles[file])
298
+ : path.join(root, file);
299
+
300
+ if (content) {
301
+ fs.writeFileSync(targetPath, content);
302
+ } else {
303
+ copy(path.join(templateDir, file), targetPath);
304
+ }
305
+ };
306
+
307
+ // Copy all template files
308
+ const files = fs.readdirSync(templateDir);
309
+ for (const file of files.filter((f) => f !== 'package.json')) {
310
+ write(file);
311
+ }
312
+
313
+ // Handle package.json separately
314
+ const pkg = JSON.parse(
315
+ fs.readFileSync(path.join(templateDir, 'package.json'), 'utf-8'),
316
+ );
317
+ pkg.name = packageName || getProjectName();
318
+ pkg.description = description;
319
+
320
+ write('package.json', JSON.stringify(pkg, null, 2));
321
+
322
+ // Replace placeholders
323
+ const providerConfig = MODEL_PROVIDERS[modelProvider];
324
+ const modelConfig = providerConfig.modelConfig(model);
325
+
326
+ replacePlaceholders(root, 'README.md', {
327
+ __PROJECT_NAME__: pkg.name,
328
+ __DESCRIPTION__: description,
329
+ });
330
+
331
+ replacePlaceholders(root, 'src/index.ts', {
332
+ __MODEL_CONFIG__: modelConfig,
333
+ });
334
+
335
+ // Update imports if needed (for LiteLLM)
336
+ if (modelProvider !== 'gemini') {
337
+ replacePlaceholders(root, 'src/index.ts', {
338
+ "import { LlmAgent, FunctionTool } from '@google/adk';":
339
+ providerConfig.importStatement,
340
+ });
341
+ }
342
+
343
+ console.log(`${green('โœ“')} Project created successfully!\n`);
344
+ console.log(`${cyan('Next steps:')}\n`);
345
+
346
+ if (root !== cwd) {
347
+ console.log(` cd ${path.relative(cwd, root)}`);
348
+ }
349
+
350
+ console.log(` npm install`);
351
+ console.log(` cp .env.example .env`);
352
+ console.log(` ${yellow('# Edit .env and add your API key')}`);
353
+ console.log(` npm run dev\n`);
354
+
355
+ console.log(`${cyan('Configuration:')}`);
356
+ console.log(` Template: ${green(template)}`);
357
+ console.log(` Provider: ${green(providerConfig.name)}`);
358
+ console.log(` Model: ${green(model)}`);
359
+ console.log(` API Key: ${yellow(providerConfig.apiKeyVar)}\n`);
360
+ }
361
+
362
+ init().catch((e) => {
363
+ console.error(e);
364
+ });
@@ -0,0 +1,16 @@
1
+ # Google Gemini API Key
2
+ # Get your key from: https://aistudio.google.com/apikey
3
+ GEMINI_API_KEY=your_google_api_key_here
4
+
5
+ # OR use Vertex AI (for Google Cloud)
6
+ # GOOGLE_GENAI_USE_VERTEXAI=true
7
+ # GOOGLE_CLOUD_PROJECT=your-project-id
8
+ # GOOGLE_CLOUD_LOCATION=us-central1
9
+
10
+ # OpenAI API Key (if using OpenAI models)
11
+ # Get your key from: https://platform.openai.com/api-keys
12
+ # OPENAI_API_KEY=your_openai_api_key_here
13
+
14
+ # Anthropic API Key (if using Claude models)
15
+ # Get your key from: https://console.anthropic.com/settings/keys
16
+ # ANTHROPIC_API_KEY=your_anthropic_api_key_here
@@ -0,0 +1,20 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "extends": [
4
+ "eslint:recommended",
5
+ "plugin:@typescript-eslint/recommended"
6
+ ],
7
+ "plugins": ["@typescript-eslint"],
8
+ "env": {
9
+ "node": true,
10
+ "es2022": true
11
+ },
12
+ "parserOptions": {
13
+ "ecmaVersion": 2022,
14
+ "sourceType": "module"
15
+ },
16
+ "rules": {
17
+ "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
18
+ "@typescript-eslint/no-explicit-any": "warn"
19
+ }
20
+ }
@@ -0,0 +1,27 @@
1
+ # Environment files - NEVER commit these!
2
+ .env
3
+ .env.local
4
+ .env*.local
5
+
6
+ # Dependencies
7
+ node_modules/
8
+
9
+ # Build output
10
+ dist/
11
+
12
+ # IDE
13
+ .vscode/
14
+ .idea/
15
+
16
+ # OS
17
+ .DS_Store
18
+ Thumbs.db
19
+
20
+ # Test coverage
21
+ coverage/
22
+
23
+ # Logs
24
+ *.log
25
+ npm-debug.log*
26
+ yarn-debug.log*
27
+ yarn-error.log*
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": true,
3
+ "trailingComma": "es5",
4
+ "singleQuote": true,
5
+ "printWidth": 80,
6
+ "tabWidth": 2
7
+ }