@wellgrow/cli 0.1.0

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.
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/init.ts
4
+ import { cp, mkdir as mkdir2, readdir, access, appendFile } from "fs/promises";
5
+ import { join as join2 } from "path";
6
+ import { homedir as homedir2 } from "os";
7
+ import { fileURLToPath } from "url";
8
+
9
+ // src/ai/environment.ts
10
+ import { execFile } from "child_process";
11
+ import { readFile, writeFile, mkdir } from "fs/promises";
12
+ import { join } from "path";
13
+ import { homedir, platform, release, arch } from "os";
14
+ var WELLGROW_HOME = join(homedir(), ".wellgrow");
15
+ var CACHE_PATH = join(WELLGROW_HOME, ".environment-cache.json");
16
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
17
+ var PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
18
+ var CLI_TOOLS = [
19
+ "git",
20
+ "gh",
21
+ "python3",
22
+ "uv",
23
+ "deno",
24
+ "bun",
25
+ "jq",
26
+ "yq",
27
+ "fd",
28
+ "rg",
29
+ "xh",
30
+ "delta",
31
+ "claude",
32
+ "codex",
33
+ "gemini",
34
+ "openclaw",
35
+ "supabase",
36
+ "vercel",
37
+ "bird",
38
+ "oracle",
39
+ "gogcli",
40
+ "obsidian-cli"
41
+ ];
42
+ function execAsync(cmd, args, timeoutMs = 3e3) {
43
+ return new Promise((resolve, reject) => {
44
+ const child = execFile(cmd, args, { timeout: timeoutMs }, (err, stdout) => {
45
+ if (err) {
46
+ reject(err);
47
+ return;
48
+ }
49
+ resolve(stdout.trim());
50
+ });
51
+ child.stdin?.end();
52
+ });
53
+ }
54
+ function extractVersion(output) {
55
+ const match = output.split("\n")[0]?.match(/(\d+\.\d+(?:\.\d+)?)/);
56
+ return match?.[1] ?? null;
57
+ }
58
+ async function detectTool(name) {
59
+ try {
60
+ await execAsync("which", [name]);
61
+ } catch {
62
+ return null;
63
+ }
64
+ try {
65
+ const output = await execAsync(name, ["--version"]);
66
+ return { name, version: extractVersion(output) };
67
+ } catch {
68
+ return { name, version: null };
69
+ }
70
+ }
71
+ async function detectWsl() {
72
+ try {
73
+ const content = await readFile("/proc/version", "utf-8");
74
+ return /microsoft/i.test(content);
75
+ } catch {
76
+ return false;
77
+ }
78
+ }
79
+ async function loadCache() {
80
+ try {
81
+ const raw = await readFile(CACHE_PATH, "utf-8");
82
+ const data = JSON.parse(raw);
83
+ if (data.version !== 1) return null;
84
+ const age = Date.now() - new Date(data.created_at).getTime();
85
+ if (age > CACHE_TTL_MS) return null;
86
+ return data;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+ async function saveCache(cache) {
92
+ try {
93
+ await mkdir(WELLGROW_HOME, { recursive: true });
94
+ await writeFile(CACHE_PATH, JSON.stringify(cache, null, 2));
95
+ } catch {
96
+ }
97
+ }
98
+ async function detectStaticEnvironment() {
99
+ const cached = await loadCache();
100
+ if (cached) return cached;
101
+ const [isWsl, nodeVersion, ...toolResults] = await Promise.all([
102
+ detectWsl(),
103
+ execAsync("node", ["--version"]).then(extractVersion).catch(() => null),
104
+ ...PACKAGE_MANAGERS.map(detectTool),
105
+ ...CLI_TOOLS.map(detectTool)
106
+ ]);
107
+ const pmResults = toolResults.slice(0, PACKAGE_MANAGERS.length);
108
+ const cliResults = toolResults.slice(PACKAGE_MANAGERS.length);
109
+ const cache = {
110
+ version: 1,
111
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
112
+ os: {
113
+ platform: platform(),
114
+ release: release(),
115
+ arch: arch(),
116
+ is_wsl: isWsl
117
+ },
118
+ shell: process.env.SHELL ?? "unknown",
119
+ node_version: nodeVersion,
120
+ package_managers: pmResults.filter((t) => t !== null),
121
+ cli_tools: cliResults.filter((t) => t !== null)
122
+ };
123
+ await saveCache(cache);
124
+ return cache;
125
+ }
126
+ async function detectGit() {
127
+ try {
128
+ const branch = await execAsync("git", [
129
+ "branch",
130
+ "--show-current"
131
+ ]);
132
+ const status = await execAsync("git", ["status", "--short"]);
133
+ const modifiedCount = status ? status.split("\n").filter((l) => l.trim()).length : 0;
134
+ return { branch: branch || "HEAD (detached)", modifiedCount };
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+ function formatToolList(tools) {
140
+ return tools.map((t) => t.version ? `${t.name} ${t.version}` : t.name).join(", ");
141
+ }
142
+ function formatEnvironment(cache, git) {
143
+ const lines = [];
144
+ let osLine = `${cache.os.platform} ${cache.os.release} (${cache.os.arch}`;
145
+ if (cache.os.is_wsl) osLine += ", WSL";
146
+ osLine += ")";
147
+ lines.push(`OS: ${osLine}`);
148
+ lines.push(`Shell: ${cache.shell}`);
149
+ lines.push(`CWD: ${process.cwd()}`);
150
+ if (git) {
151
+ const suffix = git.modifiedCount > 0 ? ` (${git.modifiedCount} files modified)` : "";
152
+ lines.push(`Git: ${git.branch}${suffix}`);
153
+ } else {
154
+ lines.push("Git: (not a git repository)");
155
+ }
156
+ if (cache.node_version) {
157
+ lines.push(`Node: v${cache.node_version}`);
158
+ }
159
+ if (cache.package_managers.length > 0) {
160
+ lines.push(`Package Manager: ${formatToolList(cache.package_managers)}`);
161
+ }
162
+ if (cache.cli_tools.length > 0) {
163
+ lines.push(`CLI: ${formatToolList(cache.cli_tools)}`);
164
+ }
165
+ return lines.join("\n");
166
+ }
167
+ async function detectEnvironment() {
168
+ const [cache, git] = await Promise.all([
169
+ detectStaticEnvironment(),
170
+ detectGit()
171
+ ]);
172
+ return formatEnvironment(cache, git);
173
+ }
174
+
175
+ // src/config/recommended-tools.ts
176
+ var RECOMMENDED_TOOLS = [
177
+ {
178
+ label: "\u30C7\u30FC\u30BF\u51E6\u7406",
179
+ tools: [
180
+ { name: "jq", description: "JSON \u52A0\u5DE5\u30FB\u62BD\u51FA", install: { brew: "brew install jq", apt: "sudo apt install -y jq" } }
181
+ ]
182
+ },
183
+ {
184
+ label: "\u9AD8\u901F\u691C\u7D22",
185
+ tools: [
186
+ { name: "rg", description: "grep \u306E\u9AD8\u901F\u7248 (ripgrep)", install: { brew: "brew install ripgrep", apt: "sudo apt install -y ripgrep" } }
187
+ ]
188
+ },
189
+ {
190
+ label: "JS/TS \u5B9F\u884C",
191
+ tools: [
192
+ { name: "bun", description: "\u9AD8\u901F JS/TS \u30E9\u30F3\u30BF\u30A4\u30E0", install: { brew: "brew install bun", apt: "curl -fsSL https://bun.sh/install | bash" } }
193
+ ]
194
+ },
195
+ {
196
+ label: "Python \u5B9F\u884C",
197
+ tools: [
198
+ { name: "uv", description: "\u9AD8\u901F Python \u30D1\u30C3\u30B1\u30FC\u30B8\u5B9F\u884C", install: { brew: "brew install uv", apt: "curl -LsSf https://astral.sh/uv/install.sh | sh" } }
199
+ ]
200
+ },
201
+ {
202
+ label: "Git / GitHub",
203
+ tools: [
204
+ { name: "gh", description: "GitHub CLI\uFF08PR \u4F5C\u6210\u7B49\uFF09", install: { brew: "brew install gh", apt: "sudo apt install -y gh" } }
205
+ ]
206
+ },
207
+ {
208
+ label: "Google Apps Script",
209
+ tools: [
210
+ { name: "clasp", description: "Apps Script CLI\uFF08\u4F5C\u6210\u30FB\u30C7\u30D7\u30ED\u30A4\uFF09", install: { brew: "npm install -g @google/clasp", apt: "npm install -g @google/clasp" } }
211
+ ]
212
+ }
213
+ ];
214
+ function toMarkdown() {
215
+ const lines = [
216
+ "",
217
+ "---",
218
+ "",
219
+ "\u4EE5\u4E0B\u306F\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u306E\u57FA\u672C\u52D5\u4F5C\u306B\u5F79\u7ACB\u3064 CLI \u30C4\u30FC\u30EB\u3067\u3059\u3002`wellgrow doctor` \u3067\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u72B6\u6CC1\u3092\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002",
220
+ ""
221
+ ];
222
+ for (const cat of RECOMMENDED_TOOLS) {
223
+ for (const t of cat.tools) {
224
+ lines.push(`## ${t.name} \u2014 ${t.description}`, "");
225
+ lines.push(`\`${t.install.brew}\` / \`${t.install.apt}\``);
226
+ lines.push("");
227
+ }
228
+ }
229
+ return lines.join("\n");
230
+ }
231
+ async function checkRecommendedTools() {
232
+ const allTools = RECOMMENDED_TOOLS.flatMap((c) => c.tools);
233
+ const results = await Promise.all(
234
+ allTools.map(async (t) => {
235
+ const info = await detectTool(t.name);
236
+ return {
237
+ name: t.name,
238
+ description: t.description,
239
+ installed: info !== null,
240
+ version: info?.version ?? null,
241
+ install: t.install
242
+ };
243
+ })
244
+ );
245
+ let idx = 0;
246
+ const categories = RECOMMENDED_TOOLS.map((cat) => {
247
+ const catTools = cat.tools.map(() => results[idx++]);
248
+ return { label: cat.label, tools: catTools };
249
+ });
250
+ const installedCount = results.filter((r) => r.installed).length;
251
+ const missingCount = results.filter((r) => !r.installed).length;
252
+ return { categories, installedCount, missingCount };
253
+ }
254
+
255
+ // src/commands/init.ts
256
+ var WELLGROW_HOME2 = join2(homedir2(), ".wellgrow");
257
+ function getTemplatesDir() {
258
+ const thisDir = fileURLToPath(new URL(".", import.meta.url));
259
+ return join2(thisDir, "..", "templates");
260
+ }
261
+ var BUILTIN_AGENTS = ["joy", "wellgrow-onboarding"];
262
+ async function runInit() {
263
+ const templatesDir = getTemplatesDir();
264
+ await mkdir2(join2(WELLGROW_HOME2, "agents"), { recursive: true });
265
+ await mkdir2(join2(WELLGROW_HOME2, "skills"), { recursive: true });
266
+ await mkdir2(join2(WELLGROW_HOME2, "hooks"), { recursive: true });
267
+ await mkdir2(join2(WELLGROW_HOME2, "mcp"), { recursive: true });
268
+ for (const agentName of BUILTIN_AGENTS) {
269
+ const src = join2(templatesDir, "agents", agentName);
270
+ const dest = join2(WELLGROW_HOME2, "agents", agentName);
271
+ try {
272
+ await cp(src, dest, { recursive: true, force: true });
273
+ process.stdout.write(`\u2713 ${agentName} \u3092\u914D\u7F6E\u3057\u307E\u3057\u305F
274
+ `);
275
+ } catch (error) {
276
+ process.stderr.write(
277
+ `\u2717 ${agentName} \u306E\u914D\u7F6E\u306B\u5931\u6557: ${error instanceof Error ? error.message : String(error)}
278
+ `
279
+ );
280
+ }
281
+ }
282
+ const manualSrc = join2(templatesDir, "manual");
283
+ const manualDest = join2(WELLGROW_HOME2, "manual");
284
+ try {
285
+ await cp(manualSrc, manualDest, { recursive: true, force: true });
286
+ process.stdout.write("\u2713 manual/ \u3092\u914D\u7F6E\u3057\u307E\u3057\u305F\n");
287
+ } catch (error) {
288
+ process.stderr.write(
289
+ `\u2717 manual/ \u306E\u914D\u7F6E\u306B\u5931\u6557: ${error instanceof Error ? error.message : String(error)}
290
+ `
291
+ );
292
+ }
293
+ await appendFile(join2(WELLGROW_HOME2, "manual", "recommended-tool.md"), toMarkdown(), "utf-8");
294
+ const result = await checkRecommendedTools();
295
+ if (result.missingCount > 0) {
296
+ process.stdout.write(
297
+ `
298
+ \u{1F4A1} ${result.missingCount} \u500B\u306E\u63A8\u5968\u30C4\u30FC\u30EB\u304C\u672A\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3067\u3059\u3002
299
+ wellgrow doctor \u3067\u8A73\u7D30\u3092\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002
300
+ `
301
+ );
302
+ }
303
+ }
304
+ async function autoInitIfNeeded() {
305
+ const agentsDir = join2(WELLGROW_HOME2, "agents");
306
+ try {
307
+ await access(agentsDir);
308
+ const entries = await readdir(agentsDir);
309
+ if (entries.length > 0) return;
310
+ } catch {
311
+ }
312
+ await runInit();
313
+ }
314
+ function registerInitCommand(program) {
315
+ program.command("init").description("\u30D3\u30EB\u30C8\u30A4\u30F3\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u3068 manual/ \u3092\u914D\u7F6E/\u66F4\u65B0\u3059\u308B").action(async () => {
316
+ await runInit();
317
+ });
318
+ }
319
+
320
+ export {
321
+ detectEnvironment,
322
+ checkRecommendedTools,
323
+ runInit,
324
+ autoInitIfNeeded,
325
+ registerInitCommand
326
+ };
327
+ //# sourceMappingURL=chunk-NABEM5RB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/init.ts","../src/ai/environment.ts","../src/config/recommended-tools.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { cp, mkdir, readdir, access, appendFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { checkRecommendedTools, toMarkdown } from \"../config/recommended-tools.js\";\n\nconst WELLGROW_HOME = join(homedir(), \".wellgrow\");\n\nfunction getTemplatesDir(): string {\n const thisDir = fileURLToPath(new URL(\".\", import.meta.url));\n return join(thisDir, \"..\", \"templates\");\n}\n\nconst BUILTIN_AGENTS = [\"joy\", \"wellgrow-onboarding\"];\n\nexport async function runInit(): Promise<void> {\n const templatesDir = getTemplatesDir();\n\n await mkdir(join(WELLGROW_HOME, \"agents\"), { recursive: true });\n await mkdir(join(WELLGROW_HOME, \"skills\"), { recursive: true });\n await mkdir(join(WELLGROW_HOME, \"hooks\"), { recursive: true });\n await mkdir(join(WELLGROW_HOME, \"mcp\"), { recursive: true });\n\n for (const agentName of BUILTIN_AGENTS) {\n const src = join(templatesDir, \"agents\", agentName);\n const dest = join(WELLGROW_HOME, \"agents\", agentName);\n try {\n await cp(src, dest, { recursive: true, force: true });\n process.stdout.write(`✓ ${agentName} を配置しました\\n`);\n } catch (error) {\n process.stderr.write(\n `✗ ${agentName} の配置に失敗: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n }\n }\n\n const manualSrc = join(templatesDir, \"manual\");\n const manualDest = join(WELLGROW_HOME, \"manual\");\n try {\n await cp(manualSrc, manualDest, { recursive: true, force: true });\n process.stdout.write(\"✓ manual/ を配置しました\\n\");\n } catch (error) {\n process.stderr.write(\n `✗ manual/ の配置に失敗: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n }\n\n await appendFile(join(WELLGROW_HOME, \"manual\", \"recommended-tool.md\"), toMarkdown(), \"utf-8\");\n\n const result = await checkRecommendedTools();\n if (result.missingCount > 0) {\n process.stdout.write(\n `\\n💡 ${result.missingCount} 個の推奨ツールが未インストールです。\\n` +\n ` wellgrow doctor で詳細を確認できます。\\n`,\n );\n }\n}\n\nexport async function autoInitIfNeeded(): Promise<void> {\n const agentsDir = join(WELLGROW_HOME, \"agents\");\n try {\n await access(agentsDir);\n const entries = await readdir(agentsDir);\n if (entries.length > 0) return;\n } catch {\n // directory doesn't exist\n }\n\n await runInit();\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"ビルトインエージェントと manual/ を配置/更新する\")\n .action(async () => {\n await runInit();\n });\n}\n","import { execFile } from \"node:child_process\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir, platform, release, arch } from \"node:os\";\n\nconst WELLGROW_HOME = join(homedir(), \".wellgrow\");\nconst CACHE_PATH = join(WELLGROW_HOME, \".environment-cache.json\");\nconst CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\nconst PACKAGE_MANAGERS = [\"pnpm\", \"npm\", \"yarn\", \"bun\"] as const;\n\nconst CLI_TOOLS = [\n \"git\", \"gh\",\n \"python3\", \"uv\", \"deno\", \"bun\",\n \"jq\", \"yq\", \"fd\", \"rg\", \"xh\", \"delta\",\n \"claude\", \"codex\", \"gemini\", \"openclaw\",\n \"supabase\", \"vercel\",\n \"bird\", \"oracle\", \"gogcli\", \"obsidian-cli\",\n] as const;\n\n// ----- Types -----\n\ninterface ToolInfo {\n name: string;\n version: string | null;\n}\n\ninterface EnvironmentCache {\n version: 1;\n created_at: string;\n os: {\n platform: string;\n release: string;\n arch: string;\n is_wsl: boolean;\n };\n shell: string;\n node_version: string | null;\n package_managers: ToolInfo[];\n cli_tools: ToolInfo[];\n}\n\n// ----- Shell helpers -----\n\nfunction execAsync(\n cmd: string,\n args: string[],\n timeoutMs = 3000,\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = execFile(cmd, args, { timeout: timeoutMs }, (err, stdout) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(stdout.trim());\n });\n child.stdin?.end();\n });\n}\n\nfunction extractVersion(output: string): string | null {\n const match = output.split(\"\\n\")[0]?.match(/(\\d+\\.\\d+(?:\\.\\d+)?)/);\n return match?.[1] ?? null;\n}\n\nexport async function detectTool(name: string): Promise<ToolInfo | null> {\n try {\n await execAsync(\"which\", [name]);\n } catch {\n return null;\n }\n\n try {\n const output = await execAsync(name, [\"--version\"]);\n return { name, version: extractVersion(output) };\n } catch {\n return { name, version: null };\n }\n}\n\n// ----- WSL detection -----\n\nasync function detectWsl(): Promise<boolean> {\n try {\n const content = await readFile(\"/proc/version\", \"utf-8\");\n return /microsoft/i.test(content);\n } catch {\n return false;\n }\n}\n\n// ----- Cache -----\n\nasync function loadCache(): Promise<EnvironmentCache | null> {\n try {\n const raw = await readFile(CACHE_PATH, \"utf-8\");\n const data = JSON.parse(raw) as EnvironmentCache;\n if (data.version !== 1) return null;\n\n const age = Date.now() - new Date(data.created_at).getTime();\n if (age > CACHE_TTL_MS) return null;\n\n return data;\n } catch {\n return null;\n }\n}\n\nasync function saveCache(cache: EnvironmentCache): Promise<void> {\n try {\n await mkdir(WELLGROW_HOME, { recursive: true });\n await writeFile(CACHE_PATH, JSON.stringify(cache, null, 2));\n } catch {\n // best-effort\n }\n}\n\n// ----- Static detection (cacheable) -----\n\nasync function detectStaticEnvironment(): Promise<EnvironmentCache> {\n const cached = await loadCache();\n if (cached) return cached;\n\n const [isWsl, nodeVersion, ...toolResults] = await Promise.all([\n detectWsl(),\n execAsync(\"node\", [\"--version\"]).then(extractVersion).catch(() => null),\n ...PACKAGE_MANAGERS.map(detectTool),\n ...CLI_TOOLS.map(detectTool),\n ]);\n\n const pmResults = toolResults.slice(0, PACKAGE_MANAGERS.length);\n const cliResults = toolResults.slice(PACKAGE_MANAGERS.length);\n\n const cache: EnvironmentCache = {\n version: 1,\n created_at: new Date().toISOString(),\n os: {\n platform: platform(),\n release: release(),\n arch: arch(),\n is_wsl: isWsl,\n },\n shell: process.env.SHELL ?? \"unknown\",\n node_version: nodeVersion,\n package_managers: pmResults.filter((t): t is ToolInfo => t !== null),\n cli_tools: cliResults.filter((t): t is ToolInfo => t !== null),\n };\n\n await saveCache(cache);\n return cache;\n}\n\n// ----- Dynamic detection (per session) -----\n\ninterface GitInfo {\n branch: string;\n modifiedCount: number;\n}\n\nasync function detectGit(): Promise<GitInfo | null> {\n try {\n const branch = await execAsync(\"git\", [\n \"branch\",\n \"--show-current\",\n ]);\n const status = await execAsync(\"git\", [\"status\", \"--short\"]);\n const modifiedCount = status\n ? status.split(\"\\n\").filter((l) => l.trim()).length\n : 0;\n return { branch: branch || \"HEAD (detached)\", modifiedCount };\n } catch {\n return null;\n }\n}\n\n// ----- Formatting -----\n\nfunction formatToolList(tools: ToolInfo[]): string {\n return tools\n .map((t) => (t.version ? `${t.name} ${t.version}` : t.name))\n .join(\", \");\n}\n\nfunction formatEnvironment(\n cache: EnvironmentCache,\n git: GitInfo | null,\n): string {\n const lines: string[] = [];\n\n // OS\n let osLine = `${cache.os.platform} ${cache.os.release} (${cache.os.arch}`;\n if (cache.os.is_wsl) osLine += \", WSL\";\n osLine += \")\";\n lines.push(`OS: ${osLine}`);\n\n // Shell\n lines.push(`Shell: ${cache.shell}`);\n\n // CWD\n lines.push(`CWD: ${process.cwd()}`);\n\n // Git\n if (git) {\n const suffix =\n git.modifiedCount > 0 ? ` (${git.modifiedCount} files modified)` : \"\";\n lines.push(`Git: ${git.branch}${suffix}`);\n } else {\n lines.push(\"Git: (not a git repository)\");\n }\n\n // Node\n if (cache.node_version) {\n lines.push(`Node: v${cache.node_version}`);\n }\n\n // Package Managers\n if (cache.package_managers.length > 0) {\n lines.push(`Package Manager: ${formatToolList(cache.package_managers)}`);\n }\n\n // CLI Tools\n if (cache.cli_tools.length > 0) {\n lines.push(`CLI: ${formatToolList(cache.cli_tools)}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n// ----- Public API -----\n\nexport async function detectEnvironment(): Promise<string> {\n const [cache, git] = await Promise.all([\n detectStaticEnvironment(),\n detectGit(),\n ]);\n\n return formatEnvironment(cache, git);\n}\n","import { detectTool } from \"../ai/environment.js\";\n\n// ----- Types -----\n\nexport interface RecommendedTool {\n name: string;\n description: string;\n install: { brew: string; apt: string };\n}\n\nexport interface RecommendedCategory {\n label: string;\n tools: RecommendedTool[];\n}\n\nexport interface ToolCheckResult {\n name: string;\n description: string;\n installed: boolean;\n version: string | null;\n install: { brew: string; apt: string };\n}\n\nexport interface DoctorResult {\n categories: Array<{\n label: string;\n tools: ToolCheckResult[];\n }>;\n installedCount: number;\n missingCount: number;\n}\n\n// ----- Catalog -----\n\nexport const RECOMMENDED_TOOLS: RecommendedCategory[] = [\n {\n label: \"データ処理\",\n tools: [\n { name: \"jq\", description: \"JSON 加工・抽出\", install: { brew: \"brew install jq\", apt: \"sudo apt install -y jq\" } },\n ],\n },\n {\n label: \"高速検索\",\n tools: [\n { name: \"rg\", description: \"grep の高速版 (ripgrep)\", install: { brew: \"brew install ripgrep\", apt: \"sudo apt install -y ripgrep\" } },\n ],\n },\n {\n label: \"JS/TS 実行\",\n tools: [\n { name: \"bun\", description: \"高速 JS/TS ランタイム\", install: { brew: \"brew install bun\", apt: \"curl -fsSL https://bun.sh/install | bash\" } },\n ],\n },\n {\n label: \"Python 実行\",\n tools: [\n { name: \"uv\", description: \"高速 Python パッケージ実行\", install: { brew: \"brew install uv\", apt: \"curl -LsSf https://astral.sh/uv/install.sh | sh\" } },\n ],\n },\n {\n label: \"Git / GitHub\",\n tools: [\n { name: \"gh\", description: \"GitHub CLI(PR 作成等)\", install: { brew: \"brew install gh\", apt: \"sudo apt install -y gh\" } },\n ],\n },\n {\n label: \"Google Apps Script\",\n tools: [\n { name: \"clasp\", description: \"Apps Script CLI(作成・デプロイ)\", install: { brew: \"npm install -g @google/clasp\", apt: \"npm install -g @google/clasp\" } },\n ],\n },\n];\n\n// ----- Markdown -----\n\nexport function toMarkdown(): string {\n const lines = [\n \"\",\n \"---\",\n \"\",\n \"以下はエージェントの基本動作に役立つ CLI ツールです。`wellgrow doctor` でインストール状況を確認できます。\",\n \"\",\n ];\n\n for (const cat of RECOMMENDED_TOOLS) {\n for (const t of cat.tools) {\n lines.push(`## ${t.name} — ${t.description}`, \"\");\n lines.push(`\\`${t.install.brew}\\` / \\`${t.install.apt}\\``);\n lines.push(\"\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// ----- Check -----\n\nexport async function checkRecommendedTools(): Promise<DoctorResult> {\n const allTools = RECOMMENDED_TOOLS.flatMap((c) => c.tools);\n const results = await Promise.all(\n allTools.map(async (t) => {\n const info = await detectTool(t.name);\n return {\n name: t.name,\n description: t.description,\n installed: info !== null,\n version: info?.version ?? null,\n install: t.install,\n };\n }),\n );\n\n let idx = 0;\n const categories = RECOMMENDED_TOOLS.map((cat) => {\n const catTools = cat.tools.map(() => results[idx++]!);\n return { label: cat.label, tools: catTools };\n });\n\n const installedCount = results.filter((r) => r.installed).length;\n const missingCount = results.filter((r) => !r.installed).length;\n\n return { categories, installedCount, missingCount };\n}\n"],"mappings":"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","names":["mkdir","join","homedir","WELLGROW_HOME","join","homedir","mkdir"]}