@take-out/cli 0.4.3 → 0.4.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 (69) hide show
  1. package/dist/cjs/cli.cjs +53 -35
  2. package/dist/cjs/commands/changed.cjs +133 -95
  3. package/dist/cjs/commands/docs.cjs +276 -203
  4. package/dist/cjs/commands/env-setup.cjs +45 -33
  5. package/dist/cjs/commands/onboard.cjs +668 -224
  6. package/dist/cjs/commands/run-all.cjs +54 -45
  7. package/dist/cjs/commands/run.cjs +80 -65
  8. package/dist/cjs/commands/script.cjs +263 -187
  9. package/dist/cjs/commands/skills.cjs +174 -118
  10. package/dist/cjs/commands/sync.cjs +193 -93
  11. package/dist/cjs/constants/ascii.cjs +14 -12
  12. package/dist/cjs/index.cjs +12 -10
  13. package/dist/cjs/types.cjs +7 -5
  14. package/dist/cjs/utils/env-categories.cjs +53 -48
  15. package/dist/cjs/utils/env-setup.cjs +214 -106
  16. package/dist/cjs/utils/env.cjs +65 -44
  17. package/dist/cjs/utils/files.cjs +186 -113
  18. package/dist/cjs/utils/parallel-runner.cjs +125 -75
  19. package/dist/cjs/utils/ports.cjs +21 -21
  20. package/dist/cjs/utils/prerequisites.cjs +42 -34
  21. package/dist/cjs/utils/prompts.cjs +66 -41
  22. package/dist/cjs/utils/script-listing.cjs +130 -60
  23. package/dist/cjs/utils/script-utils.cjs +29 -19
  24. package/dist/cjs/utils/sync.cjs +67 -45
  25. package/dist/esm/cli.mjs +40 -24
  26. package/dist/esm/cli.mjs.map +1 -1
  27. package/dist/esm/commands/changed.mjs +104 -68
  28. package/dist/esm/commands/changed.mjs.map +1 -1
  29. package/dist/esm/commands/docs.mjs +245 -174
  30. package/dist/esm/commands/docs.mjs.map +1 -1
  31. package/dist/esm/commands/env-setup.mjs +18 -8
  32. package/dist/esm/commands/env-setup.mjs.map +1 -1
  33. package/dist/esm/commands/onboard.mjs +631 -189
  34. package/dist/esm/commands/onboard.mjs.map +1 -1
  35. package/dist/esm/commands/run-all.mjs +26 -19
  36. package/dist/esm/commands/run-all.mjs.map +1 -1
  37. package/dist/esm/commands/run.mjs +52 -39
  38. package/dist/esm/commands/run.mjs.map +1 -1
  39. package/dist/esm/commands/script.mjs +230 -156
  40. package/dist/esm/commands/script.mjs.map +1 -1
  41. package/dist/esm/commands/skills.mjs +143 -89
  42. package/dist/esm/commands/skills.mjs.map +1 -1
  43. package/dist/esm/commands/sync.mjs +160 -62
  44. package/dist/esm/commands/sync.mjs.map +1 -1
  45. package/dist/esm/constants/ascii.mjs +2 -2
  46. package/dist/esm/constants/ascii.mjs.map +1 -1
  47. package/dist/esm/utils/env-categories.mjs +29 -26
  48. package/dist/esm/utils/env-categories.mjs.map +1 -1
  49. package/dist/esm/utils/env-setup.mjs +184 -78
  50. package/dist/esm/utils/env-setup.mjs.map +1 -1
  51. package/dist/esm/utils/env.mjs +50 -31
  52. package/dist/esm/utils/env.mjs.map +1 -1
  53. package/dist/esm/utils/files.mjs +171 -100
  54. package/dist/esm/utils/files.mjs.map +1 -1
  55. package/dist/esm/utils/parallel-runner.mjs +111 -63
  56. package/dist/esm/utils/parallel-runner.mjs.map +1 -1
  57. package/dist/esm/utils/ports.mjs +9 -11
  58. package/dist/esm/utils/ports.mjs.map +1 -1
  59. package/dist/esm/utils/prerequisites.mjs +30 -24
  60. package/dist/esm/utils/prerequisites.mjs.map +1 -1
  61. package/dist/esm/utils/prompts.mjs +40 -17
  62. package/dist/esm/utils/prompts.mjs.map +1 -1
  63. package/dist/esm/utils/script-listing.mjs +101 -33
  64. package/dist/esm/utils/script-listing.mjs.map +1 -1
  65. package/dist/esm/utils/script-utils.mjs +14 -6
  66. package/dist/esm/utils/script-utils.mjs.map +1 -1
  67. package/dist/esm/utils/sync.mjs +38 -18
  68. package/dist/esm/utils/sync.mjs.map +1 -1
  69. package/package.json +5 -5
@@ -2,45 +2,47 @@ var __create = Object.create;
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf,
6
- __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
7
  var __export = (target, all) => {
8
- for (var name in all) __defProp(target, name, {
9
- get: all[name],
10
- enumerable: !0
11
- });
12
- },
13
- __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
15
16
  get: () => from[key],
16
17
  enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
18
  });
18
- return to;
19
- };
19
+ }
20
+ return to;
21
+ };
20
22
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
- value: mod,
27
- enumerable: !0
28
- }) : target, mod)),
29
- __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
30
- value: !0
31
- }), mod);
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
28
+ value: mod,
29
+ enumerable: true
30
+ }) : target, mod));
31
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
32
+ value: true
33
+ }), mod);
32
34
  var skills_exports = {};
33
35
  __export(skills_exports, {
34
36
  skillsCommand: () => skillsCommand
35
37
  });
36
38
  module.exports = __toCommonJS(skills_exports);
37
- var import_node_fs = require("node:fs"),
38
- import_node_module = require("node:module"),
39
- import_node_path = require("node:path"),
40
- import_citty = require("citty"),
41
- import_picocolors = __toESM(require("picocolors"), 1);
42
- const import_meta = {},
43
- require2 = (0, import_node_module.createRequire)(import_meta.url);
39
+ var import_node_fs = require("node:fs");
40
+ var import_node_module = require("node:module");
41
+ var import_node_path = require("node:path");
42
+ var import_citty = require("citty");
43
+ var import_picocolors = __toESM(require("picocolors"), 1);
44
+ const import_meta = {};
45
+ const require2 = (0, import_node_module.createRequire)(import_meta.url);
44
46
  let DOCS_DIR;
45
47
  try {
46
48
  DOCS_DIR = (0, import_node_path.dirname)(require2.resolve("@take-out/docs/package.json"));
@@ -49,23 +51,23 @@ try {
49
51
  }
50
52
  const SKILL_PREFIX = "takeout-";
51
53
  function hasSkillFrontmatter(content) {
52
- if (!content.startsWith("---")) return !1;
54
+ if (!content.startsWith("---")) return false;
53
55
  const endIndex = content.indexOf("---", 3);
54
- if (endIndex === -1) return !1;
56
+ if (endIndex === -1) return false;
55
57
  const frontmatter = content.slice(3, endIndex);
56
58
  return frontmatter.includes("name:") && frontmatter.includes("description:");
57
59
  }
58
60
  function isDevOnly(content) {
59
- if (!content.startsWith("---")) return !1;
61
+ if (!content.startsWith("---")) return false;
60
62
  const endIndex = content.indexOf("---", 3);
61
- if (endIndex === -1) return !1;
63
+ if (endIndex === -1) return false;
62
64
  const frontmatter = content.slice(3, endIndex);
63
65
  return /\bdev:\s*true\b/.test(frontmatter);
64
66
  }
65
67
  function collectAllDocs(cwd) {
66
- const docs = [],
67
- seen = /* @__PURE__ */new Set(),
68
- localDocsDir = (0, import_node_path.join)(cwd, "docs");
68
+ const docs = [];
69
+ const seen = /* @__PURE__ */new Set();
70
+ const localDocsDir = (0, import_node_path.join)(cwd, "docs");
69
71
  if ((0, import_node_fs.existsSync)(localDocsDir)) {
70
72
  const files = (0, import_node_fs.readdirSync)(localDocsDir).filter(f => f.endsWith(".md"));
71
73
  for (const file of files) {
@@ -74,41 +76,55 @@ function collectAllDocs(cwd) {
74
76
  name,
75
77
  path: (0, import_node_path.join)(localDocsDir, file),
76
78
  source: "local"
77
- }), seen.add(name);
79
+ });
80
+ seen.add(name);
78
81
  }
79
82
  }
80
83
  if (DOCS_DIR && (0, import_node_fs.existsSync)(DOCS_DIR)) {
81
84
  const files = (0, import_node_fs.readdirSync)(DOCS_DIR).filter(f => f.endsWith(".md"));
82
85
  for (const file of files) {
83
86
  const name = file.replace(/\.md$/, "");
84
- seen.has(name) || docs.push({
85
- name,
86
- path: (0, import_node_path.join)(DOCS_DIR, file),
87
- source: "package"
88
- });
87
+ if (!seen.has(name)) {
88
+ docs.push({
89
+ name,
90
+ path: (0, import_node_path.join)(DOCS_DIR, file),
91
+ source: "package"
92
+ });
93
+ }
89
94
  }
90
95
  }
91
96
  return docs;
92
97
  }
93
98
  async function generateDocSkills(cwd, clean) {
94
- const skillsDir = (0, import_node_path.join)(cwd, ".claude", "skills"),
95
- docs = collectAllDocs(cwd),
96
- localDocsDir = (0, import_node_path.join)(cwd, "docs"),
97
- expectedSkillNames = /* @__PURE__ */new Set();
98
- if (docs.length === 0 ? console.info(import_picocolors.default.yellow("no documentation files found")) : console.info(import_picocolors.default.dim(`found ${docs.length} documentation files`)), clean && (0, import_node_fs.existsSync)(skillsDir)) {
99
+ const skillsDir = (0, import_node_path.join)(cwd, ".claude", "skills");
100
+ const docs = collectAllDocs(cwd);
101
+ const localDocsDir = (0, import_node_path.join)(cwd, "docs");
102
+ const expectedSkillNames = /* @__PURE__ */new Set();
103
+ if (docs.length === 0) {
104
+ console.info(import_picocolors.default.yellow("no documentation files found"));
105
+ } else {
106
+ console.info(import_picocolors.default.dim(`found ${docs.length} documentation files`));
107
+ }
108
+ if (clean && (0, import_node_fs.existsSync)(skillsDir)) {
99
109
  const existing = (0, import_node_fs.readdirSync)(skillsDir);
100
- for (const dir of existing) dir.startsWith(SKILL_PREFIX) && (0, import_node_fs.rmSync)((0, import_node_path.join)(skillsDir, dir), {
101
- recursive: !0
110
+ for (const dir of existing) {
111
+ if (dir.startsWith(SKILL_PREFIX)) {
112
+ (0, import_node_fs.rmSync)((0, import_node_path.join)(skillsDir, dir), {
113
+ recursive: true
114
+ });
115
+ }
116
+ }
117
+ }
118
+ if (!(0, import_node_fs.existsSync)(skillsDir)) {
119
+ (0, import_node_fs.mkdirSync)(skillsDir, {
120
+ recursive: true
102
121
  });
103
122
  }
104
- (0, import_node_fs.existsSync)(skillsDir) || (0, import_node_fs.mkdirSync)(skillsDir, {
105
- recursive: !0
106
- });
107
- let symlinked = 0,
108
- generated = 0,
109
- unchanged = 0,
110
- removed = 0,
111
- skipped = 0;
123
+ let symlinked = 0;
124
+ let generated = 0;
125
+ let unchanged = 0;
126
+ let removed = 0;
127
+ let skipped = 0;
112
128
  const isDev = !!process.env.IS_TAMAGUI_DEV;
113
129
  for (const doc of docs) {
114
130
  const content = (0, import_node_fs.readFileSync)(doc.path, "utf-8");
@@ -119,45 +135,70 @@ async function generateDocSkills(cwd, clean) {
119
135
  if (!nameMatch) continue;
120
136
  const skillName = nameMatch[1].trim();
121
137
  expectedSkillNames.add(skillName);
122
- const skillDir = (0, import_node_path.join)(skillsDir, skillName),
123
- skillFile = (0, import_node_path.join)(skillDir, "SKILL.md");
124
- (0, import_node_fs.existsSync)(skillDir) || (0, import_node_fs.mkdirSync)(skillDir, {
125
- recursive: !0
126
- });
138
+ const skillDir = (0, import_node_path.join)(skillsDir, skillName);
139
+ const skillFile = (0, import_node_path.join)(skillDir, "SKILL.md");
140
+ if (!(0, import_node_fs.existsSync)(skillDir)) {
141
+ (0, import_node_fs.mkdirSync)(skillDir, {
142
+ recursive: true
143
+ });
144
+ }
127
145
  const relativePath = (0, import_node_path.relative)(skillDir, doc.path);
128
- let shouldCreate = !0;
146
+ let shouldCreate = true;
129
147
  try {
130
- (0, import_node_fs.lstatSync)(skillFile).isSymbolicLink() && (0, import_node_fs.existsSync)(skillFile) && (0, import_node_fs.readFileSync)(skillFile, "utf-8") === content && (unchanged++, shouldCreate = !1), shouldCreate && (0, import_node_fs.unlinkSync)(skillFile);
148
+ const stat = (0, import_node_fs.lstatSync)(skillFile);
149
+ if (stat.isSymbolicLink() && (0, import_node_fs.existsSync)(skillFile)) {
150
+ const existingContent = (0, import_node_fs.readFileSync)(skillFile, "utf-8");
151
+ if (existingContent === content) {
152
+ unchanged++;
153
+ shouldCreate = false;
154
+ }
155
+ }
156
+ if (shouldCreate) {
157
+ (0, import_node_fs.unlinkSync)(skillFile);
158
+ }
131
159
  } catch {}
132
160
  if (!shouldCreate) continue;
133
- (0, import_node_fs.symlinkSync)(relativePath, skillFile), symlinked++;
161
+ (0, import_node_fs.symlinkSync)(relativePath, skillFile);
162
+ symlinked++;
134
163
  const sourceLabel = doc.source === "local" ? import_picocolors.default.blue("local") : import_picocolors.default.dim("package");
135
164
  console.info(` ${import_picocolors.default.green("\u27F7")} ${skillName} ${sourceLabel} ${import_picocolors.default.dim("(symlink)")}`);
136
- } else if (!hasFrontmatter) {
137
- skipped++, console.info(` ${import_picocolors.default.yellow("!")} skipped ${import_picocolors.default.dim(doc.name)} ${import_picocolors.default.dim("(missing skill frontmatter)")}`);
138
- continue;
165
+ } else {
166
+ if (!hasFrontmatter) {
167
+ skipped++;
168
+ console.info(` ${import_picocolors.default.yellow("!")} skipped ${import_picocolors.default.dim(doc.name)} ${import_picocolors.default.dim("(missing skill frontmatter)")}`);
169
+ continue;
170
+ }
139
171
  }
140
172
  }
141
173
  for (const dir of (0, import_node_fs.readdirSync)(skillsDir)) {
142
174
  if (expectedSkillNames.has(dir)) continue;
143
- const skillDir = (0, import_node_path.join)(skillsDir, dir),
144
- skillFile = (0, import_node_path.join)(skillDir, "SKILL.md");
175
+ const skillDir = (0, import_node_path.join)(skillsDir, dir);
176
+ const skillFile = (0, import_node_path.join)(skillDir, "SKILL.md");
145
177
  if (dir.startsWith(SKILL_PREFIX)) {
146
178
  (0, import_node_fs.rmSync)(skillDir, {
147
- recursive: !0,
148
- force: !0
149
- }), removed++, console.info(` ${import_picocolors.default.red("\u2715")} ${dir} ${import_picocolors.default.dim("(removed stale generated skill)")}`);
179
+ recursive: true,
180
+ force: true
181
+ });
182
+ removed++;
183
+ console.info(` ${import_picocolors.default.red("\u2715")} ${dir} ${import_picocolors.default.dim("(removed stale generated skill)")}`);
150
184
  continue;
151
185
  }
152
- let shouldUnlink = !1;
186
+ let shouldUnlink = false;
153
187
  try {
154
- if ((0, import_node_fs.lstatSync)(skillFile).isSymbolicLink()) {
155
- const linkTarget = (0, import_node_fs.readlinkSync)(skillFile),
156
- resolvedTarget = (0, import_node_path.resolve)(skillDir, linkTarget);
188
+ const stat = (0, import_node_fs.lstatSync)(skillFile);
189
+ if (stat.isSymbolicLink()) {
190
+ const linkTarget = (0, import_node_fs.readlinkSync)(skillFile);
191
+ const resolvedTarget = (0, import_node_path.resolve)(skillDir, linkTarget);
157
192
  shouldUnlink = resolvedTarget.startsWith(`${localDocsDir}/`) || !!DOCS_DIR && resolvedTarget.startsWith(`${DOCS_DIR}/`);
158
193
  }
159
194
  } catch {}
160
- shouldUnlink && ((0, import_node_fs.unlinkSync)(skillFile), (0, import_node_fs.readdirSync)(skillDir).length === 0 && (0, import_node_fs.rmdirSync)(skillDir), removed++, console.info(` ${import_picocolors.default.red("\u2715")} ${dir} ${import_picocolors.default.dim("(removed stale symlink)")}`));
195
+ if (!shouldUnlink) continue;
196
+ (0, import_node_fs.unlinkSync)(skillFile);
197
+ if ((0, import_node_fs.readdirSync)(skillDir).length === 0) {
198
+ (0, import_node_fs.rmdirSync)(skillDir);
199
+ }
200
+ removed++;
201
+ console.info(` ${import_picocolors.default.red("\u2715")} ${dir} ${import_picocolors.default.dim("(removed stale symlink)")}`);
161
202
  }
162
203
  return {
163
204
  symlinked,
@@ -168,46 +209,61 @@ async function generateDocSkills(cwd, clean) {
168
209
  };
169
210
  }
170
211
  const generateCommand = (0, import_citty.defineCommand)({
171
- meta: {
172
- name: "generate",
173
- description: "Generate Claude Code skills from documentation"
174
- },
175
- args: {
176
- clean: {
177
- type: "boolean",
178
- description: "Remove existing takeout-* skills before generating",
179
- default: !1
180
- },
181
- "skip-internal-docs": {
182
- type: "boolean",
183
- description: "Skip generating skills from internal documentation files",
184
- default: !1
185
- }
212
+ meta: {
213
+ name: "generate",
214
+ description: "Generate Claude Code skills from documentation"
215
+ },
216
+ args: {
217
+ clean: {
218
+ type: "boolean",
219
+ description: "Remove existing takeout-* skills before generating",
220
+ default: false
186
221
  },
187
- async run({
188
- args
189
- }) {
190
- const cwd = process.cwd(),
191
- skillsDir = (0, import_node_path.join)(cwd, ".claude", "skills");
192
- console.info(), console.info(import_picocolors.default.bold(import_picocolors.default.cyan("Generate all skills"))), console.info();
193
- let symlinked = 0,
194
- generated = 0,
195
- unchanged = 0,
196
- removed = 0,
197
- skipped = 0;
198
- if (!args["skip-internal-docs"]) {
199
- const docStats = await generateDocSkills(cwd, args.clean);
200
- symlinked = docStats.symlinked, generated = docStats.generated, unchanged = docStats.unchanged, removed = docStats.removed, skipped = docStats.skipped, console.info();
201
- }
202
- console.info(), console.info(import_picocolors.default.bold("summary:")), symlinked > 0 && console.info(` ${import_picocolors.default.green(`${symlinked} symlinked`)}`), generated > 0 && console.info(` ${import_picocolors.default.yellow(`${generated} generated`)} ${import_picocolors.default.dim("(add frontmatter to enable symlink)")}`), skipped > 0 && console.info(` ${import_picocolors.default.yellow(`${skipped} skipped`)} ${import_picocolors.default.dim("(missing skill frontmatter)")}`), unchanged > 0 && console.info(` ${import_picocolors.default.dim(`${unchanged} unchanged`)}`), removed > 0 && console.info(` ${import_picocolors.default.red(`${removed} removed`)}`), console.info(import_picocolors.default.dim(` skills in ${skillsDir}`)), console.info();
222
+ "skip-internal-docs": {
223
+ type: "boolean",
224
+ description: "Skip generating skills from internal documentation files",
225
+ default: false
203
226
  }
204
- }),
205
- skillsCommand = (0, import_citty.defineCommand)({
206
- meta: {
207
- name: "skills",
208
- description: "Manage Claude Code skills"
209
- },
210
- subCommands: {
211
- generate: generateCommand
227
+ },
228
+ async run({
229
+ args
230
+ }) {
231
+ const cwd = process.cwd();
232
+ const skillsDir = (0, import_node_path.join)(cwd, ".claude", "skills");
233
+ console.info();
234
+ console.info(import_picocolors.default.bold(import_picocolors.default.cyan("Generate all skills")));
235
+ console.info();
236
+ let symlinked = 0;
237
+ let generated = 0;
238
+ let unchanged = 0;
239
+ let removed = 0;
240
+ let skipped = 0;
241
+ if (!args["skip-internal-docs"]) {
242
+ const docStats = await generateDocSkills(cwd, args.clean);
243
+ symlinked = docStats.symlinked;
244
+ generated = docStats.generated;
245
+ unchanged = docStats.unchanged;
246
+ removed = docStats.removed;
247
+ skipped = docStats.skipped;
248
+ console.info();
212
249
  }
213
- });
250
+ console.info();
251
+ console.info(import_picocolors.default.bold("summary:"));
252
+ if (symlinked > 0) console.info(` ${import_picocolors.default.green(`${symlinked} symlinked`)}`);
253
+ if (generated > 0) console.info(` ${import_picocolors.default.yellow(`${generated} generated`)} ${import_picocolors.default.dim("(add frontmatter to enable symlink)")}`);
254
+ if (skipped > 0) console.info(` ${import_picocolors.default.yellow(`${skipped} skipped`)} ${import_picocolors.default.dim("(missing skill frontmatter)")}`);
255
+ if (unchanged > 0) console.info(` ${import_picocolors.default.dim(`${unchanged} unchanged`)}`);
256
+ if (removed > 0) console.info(` ${import_picocolors.default.red(`${removed} removed`)}`);
257
+ console.info(import_picocolors.default.dim(` skills in ${skillsDir}`));
258
+ console.info();
259
+ }
260
+ });
261
+ const skillsCommand = (0, import_citty.defineCommand)({
262
+ meta: {
263
+ name: "skills",
264
+ description: "Manage Claude Code skills"
265
+ },
266
+ subCommands: {
267
+ generate: generateCommand
268
+ }
269
+ });