ccjk 9.5.6 → 9.7.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.
Files changed (103) hide show
  1. package/dist/chunks/agent.mjs +1 -1
  2. package/dist/chunks/api-providers.mjs +1 -1
  3. package/dist/chunks/api.mjs +3 -3
  4. package/dist/chunks/auto-bootstrap.mjs +1 -1
  5. package/dist/chunks/auto-updater.mjs +1 -1
  6. package/dist/chunks/boost.mjs +160 -0
  7. package/dist/chunks/ccjk-agents.mjs +1 -1
  8. package/dist/chunks/ccjk-all.mjs +1 -1
  9. package/dist/chunks/ccjk-config.mjs +1 -1
  10. package/dist/chunks/ccjk-hooks.mjs +1 -1
  11. package/dist/chunks/ccjk-mcp.mjs +2 -2
  12. package/dist/chunks/ccjk-setup.mjs +1 -1
  13. package/dist/chunks/ccjk-skills.mjs +1 -1
  14. package/dist/chunks/ccr.mjs +25 -30
  15. package/dist/chunks/ccu.mjs +1 -1
  16. package/dist/chunks/check-updates.mjs +3 -4
  17. package/dist/chunks/claude-code-config-manager.mjs +7 -7
  18. package/dist/chunks/claude-code-incremental-manager.mjs +2 -2
  19. package/dist/chunks/claude-config.mjs +4 -4
  20. package/dist/chunks/claude-wrapper.mjs +2 -2
  21. package/dist/chunks/codex-config-switch.mjs +4 -5
  22. package/dist/chunks/codex-provider-manager.mjs +2 -3
  23. package/dist/chunks/codex-uninstaller.mjs +2 -2
  24. package/dist/chunks/codex.mjs +207 -6
  25. package/dist/chunks/commands.mjs +391 -88
  26. package/dist/chunks/commands2.mjs +88 -391
  27. package/dist/chunks/completion.mjs +1 -1
  28. package/dist/chunks/config-consolidator.mjs +2 -2
  29. package/dist/chunks/config-switch.mjs +3 -4
  30. package/dist/chunks/config.mjs +78 -7
  31. package/dist/chunks/config2.mjs +400 -410
  32. package/dist/chunks/config3.mjs +410 -400
  33. package/dist/chunks/constants.mjs +1 -1
  34. package/dist/chunks/doctor.mjs +4 -4
  35. package/dist/chunks/features.mjs +24 -17
  36. package/dist/chunks/index.mjs +178 -7
  37. package/dist/chunks/index2.mjs +1162 -169
  38. package/dist/chunks/index3.mjs +910 -1076
  39. package/dist/chunks/index4.mjs +137 -947
  40. package/dist/chunks/index5.mjs +635 -167
  41. package/dist/chunks/init.mjs +141 -99
  42. package/dist/chunks/installer.mjs +147 -649
  43. package/dist/chunks/installer2.mjs +649 -147
  44. package/dist/chunks/interview.mjs +2 -2
  45. package/dist/chunks/marketplace.mjs +1 -1
  46. package/dist/chunks/mcp.mjs +1058 -17
  47. package/dist/chunks/menu.mjs +147 -56
  48. package/dist/chunks/monitor.mjs +2 -2
  49. package/dist/chunks/notification.mjs +1 -1
  50. package/dist/chunks/onboarding.mjs +2 -2
  51. package/dist/chunks/package.mjs +2 -210
  52. package/dist/chunks/permission-manager.mjs +2 -2
  53. package/dist/chunks/permissions.mjs +1 -1
  54. package/dist/chunks/platform.mjs +1 -1
  55. package/dist/chunks/plugin.mjs +1 -1
  56. package/dist/chunks/prompts.mjs +1 -1
  57. package/dist/chunks/providers.mjs +1 -1
  58. package/dist/chunks/quick-setup.mjs +16 -20
  59. package/dist/chunks/silent-updater.mjs +1 -1
  60. package/dist/chunks/simple-config.mjs +2 -2
  61. package/dist/chunks/skill.mjs +1 -1
  62. package/dist/chunks/skills-sync.mjs +1 -1
  63. package/dist/chunks/skills.mjs +1 -1
  64. package/dist/chunks/startup.mjs +1 -1
  65. package/dist/chunks/stats.mjs +1 -1
  66. package/dist/chunks/status.mjs +159 -0
  67. package/dist/chunks/team.mjs +1 -1
  68. package/dist/chunks/thinking.mjs +2 -2
  69. package/dist/chunks/uninstall.mjs +6 -6
  70. package/dist/chunks/update.mjs +6 -9
  71. package/dist/chunks/upgrade-manager.mjs +2 -2
  72. package/dist/chunks/version-checker.mjs +3 -3
  73. package/dist/chunks/vim.mjs +1 -1
  74. package/dist/chunks/workflows.mjs +616 -215
  75. package/dist/cli.mjs +70 -121
  76. package/dist/index.d.mts +17 -1482
  77. package/dist/index.d.ts +17 -1482
  78. package/dist/index.mjs +950 -4740
  79. package/dist/shared/{ccjk.zCqdxT2Y.mjs → ccjk.Br91zBIG.mjs} +2 -2
  80. package/dist/shared/ccjk.CSkyCZIM.mjs +638 -0
  81. package/dist/shared/{ccjk.BKoi8-Hy.mjs → ccjk.DE91nClQ.mjs} +1 -1
  82. package/dist/shared/{ccjk.f40us0yY.mjs → ccjk.DvIrK0wz.mjs} +2 -2
  83. package/dist/shared/ccjk.LsPZ2PYo.mjs +1048 -0
  84. package/dist/shared/{ccjk.DRweXU5F.mjs → ccjk.q1koQxEE.mjs} +2 -2
  85. package/package.json +1 -1
  86. package/templates/claude-code/common/settings.json +15 -111
  87. package/dist/chunks/api-adapter.mjs +0 -180
  88. package/dist/chunks/cli.mjs +0 -2227
  89. package/dist/chunks/context-menu.mjs +0 -913
  90. package/dist/chunks/hooks-sync.mjs +0 -1627
  91. package/dist/chunks/index6.mjs +0 -663
  92. package/dist/chunks/mcp-market.mjs +0 -1077
  93. package/dist/chunks/mcp-server.mjs +0 -776
  94. package/dist/chunks/project-detector.mjs +0 -131
  95. package/dist/chunks/provider-registry.mjs +0 -92
  96. package/dist/chunks/setup-wizard.mjs +0 -362
  97. package/dist/chunks/tools.mjs +0 -143
  98. package/dist/chunks/workflows2.mjs +0 -633
  99. package/dist/shared/ccjk.BM_HZogn.mjs +0 -347
  100. package/dist/shared/ccjk.BaEp4UHQ.mjs +0 -75
  101. package/dist/shared/ccjk.CS0ybJCf.mjs +0 -490
  102. package/dist/shared/ccjk.CZgIwikC.mjs +0 -209
  103. package/dist/shared/ccjk.tO8zeFh1.mjs +0 -397
@@ -1,6 +1,6 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { i18n } from './index2.mjs';
3
+ import { i18n } from './index.mjs';
4
4
  import { existsSync, unlinkSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
5
5
  import 'node:os';
6
6
  import { join } from 'pathe';
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from
2
2
  import { mkdir } from 'node:fs/promises';
3
3
  import { homedir } from 'node:os';
4
4
  import { join, basename } from 'pathe';
5
- import { i18n } from './index2.mjs';
5
+ import { i18n } from './index.mjs';
6
6
  import 'node:process';
7
7
  import 'node:url';
8
8
  import 'i18next';
@@ -1,5 +1,5 @@
1
1
  import ansis from 'ansis';
2
- import { i18n } from './index2.mjs';
2
+ import { i18n } from './index.mjs';
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
4
4
  import { homedir } from 'node:os';
5
5
  import { join } from 'pathe';
@@ -0,0 +1,159 @@
1
+ import ansis from 'ansis';
2
+ import { r as runHealthCheck, a as analyzeProject, g as getRecommendations } from '../shared/ccjk.CSkyCZIM.mjs';
3
+ import 'node:fs';
4
+ import 'node:process';
5
+ import 'pathe';
6
+ import './constants.mjs';
7
+ import 'node:os';
8
+ import './index.mjs';
9
+ import 'node:url';
10
+ import 'i18next';
11
+ import 'i18next-fs-backend';
12
+
13
+ const GRADE_COLORS = {
14
+ S: (s) => ansis.magenta.bold(s),
15
+ A: (s) => ansis.green.bold(s),
16
+ B: (s) => ansis.cyan.bold(s),
17
+ C: (s) => ansis.yellow.bold(s),
18
+ D: (s) => ansis.red(s),
19
+ F: (s) => ansis.red.bold(s)
20
+ };
21
+ const STATUS_ICONS = {
22
+ pass: ansis.green("\u2713"),
23
+ warn: ansis.yellow("\u26A0"),
24
+ fail: ansis.red("\u2717")
25
+ };
26
+ function stripAnsi(s) {
27
+ return s.replace(/\x1B\[[0-9;]*m/g, "");
28
+ }
29
+ function renderBox(lines, width = 55) {
30
+ const top = ansis.gray(`\u256D${"\u2500".repeat(width - 2)}\u256E`);
31
+ const bot = ansis.gray(`\u2570${"\u2500".repeat(width - 2)}\u256F`);
32
+ const pad = (s) => {
33
+ const stripped = stripAnsi(s);
34
+ const remaining = width - 4 - stripped.length;
35
+ return `${ansis.gray("\u2502")} ${s}${" ".repeat(Math.max(0, remaining))} ${ansis.gray("\u2502")}`;
36
+ };
37
+ return [top, ...lines.map(pad), bot].join("\n");
38
+ }
39
+ function renderScoreBar(score) {
40
+ const filled = Math.round(score / 5);
41
+ const empty = 20 - filled;
42
+ let bar = "";
43
+ if (score >= 80)
44
+ bar = ansis.green("\u2588".repeat(filled));
45
+ else if (score >= 50)
46
+ bar = ansis.yellow("\u2588".repeat(filled));
47
+ else bar = ansis.red("\u2588".repeat(filled));
48
+ bar += ansis.gray("\u2591".repeat(empty));
49
+ return bar;
50
+ }
51
+ function renderHeader(report, profile) {
52
+ const gradeColor = GRADE_COLORS[report.grade] || ((s) => s);
53
+ const lines = [];
54
+ lines.push("");
55
+ lines.push(ansis.cyan.bold("\u{1F9E0} CCJK Brain Dashboard"));
56
+ lines.push("");
57
+ lines.push(`${renderScoreBar(report.totalScore)} ${gradeColor(report.grade)} ${ansis.bold(`${report.totalScore}/100`)}`);
58
+ lines.push("");
59
+ if (profile.projectName) {
60
+ const stackParts = [];
61
+ if (profile.language !== "unknown")
62
+ stackParts.push(profile.language);
63
+ stackParts.push(...profile.frameworks.slice(0, 3));
64
+ const stack = stackParts.length > 0 ? ansis.gray(` (${stackParts.join(", ")})`) : "";
65
+ lines.push(ansis.gray("Project: ") + ansis.white(profile.projectName) + stack);
66
+ }
67
+ return lines;
68
+ }
69
+ function renderSetupStatus(results) {
70
+ const lines = [];
71
+ lines.push("");
72
+ lines.push(ansis.yellow.bold("Setup Status"));
73
+ lines.push("");
74
+ for (const r of results) {
75
+ const icon = STATUS_ICONS[r.status] || "?";
76
+ const name = r.name.padEnd(16);
77
+ const msg = r.status === "pass" ? ansis.green(r.message) : r.status === "warn" ? ansis.yellow(r.message) : ansis.red(r.message);
78
+ lines.push(`${icon} ${ansis.bold(name)} ${msg}`);
79
+ }
80
+ return lines;
81
+ }
82
+ function renderRecommendations(recs, maxShow = 4) {
83
+ if (recs.length === 0)
84
+ return [];
85
+ const lines = [];
86
+ lines.push("");
87
+ lines.push(ansis.yellow.bold("Recommendations"));
88
+ lines.push("");
89
+ for (const rec of recs.slice(0, maxShow)) {
90
+ const icon = rec.priority === "high" ? ansis.red("\u2192") : ansis.yellow("\u2192");
91
+ lines.push(`${icon} ${rec.description}`);
92
+ if (rec.command) {
93
+ lines.push(` ${ansis.cyan(rec.command)}`);
94
+ }
95
+ }
96
+ if (recs.length > maxShow) {
97
+ lines.push(ansis.gray(` ... and ${recs.length - maxShow} more`));
98
+ }
99
+ return lines;
100
+ }
101
+ function renderProjectRecs(profile) {
102
+ const { skills, mcpServices } = getRecommendations(profile);
103
+ if (skills.length === 0 && mcpServices.length === 0)
104
+ return [];
105
+ const lines = [];
106
+ lines.push("");
107
+ lines.push(ansis.yellow.bold("For Your Project"));
108
+ lines.push("");
109
+ if (skills.length > 0) {
110
+ lines.push(`${ansis.cyan(String(skills.length))} skills match your stack:`);
111
+ for (const s of skills.slice(0, 3)) {
112
+ lines.push(` ${ansis.green("+")} ${s.name} ${ansis.gray(`- ${s.reason}`)}`);
113
+ }
114
+ lines.push(` ${ansis.cyan("ccjk ccjk:skills --dry-run")}`);
115
+ }
116
+ if (mcpServices.length > 0) {
117
+ lines.push(`${ansis.cyan(String(mcpServices.length))} MCP services recommended`);
118
+ lines.push(` ${ansis.cyan("ccjk ccjk:mcp --dry-run")}`);
119
+ }
120
+ return lines;
121
+ }
122
+ function renderQuickActions() {
123
+ return [
124
+ "",
125
+ ansis.yellow.bold("Quick Actions"),
126
+ "",
127
+ `${ansis.cyan("ccjk boost")} Auto-apply recommendations`,
128
+ `${ansis.cyan("ccjk ccjk:skills")} Install project-matched skills`,
129
+ `${ansis.cyan("ccjk ccjk:mcp")} Install recommended MCP services`,
130
+ `${ansis.cyan("ccjk doctor")} Full environment diagnostics`
131
+ ];
132
+ }
133
+ async function status(options = {}) {
134
+ const [report, profile] = await Promise.all([
135
+ runHealthCheck(),
136
+ Promise.resolve(analyzeProject())
137
+ ]);
138
+ if (options.json) {
139
+ console.log(JSON.stringify({
140
+ score: report.totalScore,
141
+ grade: report.grade,
142
+ results: report.results.map((r) => ({ name: r.name, status: r.status, score: r.score, message: r.message })),
143
+ recommendations: report.recommendations,
144
+ project: { name: profile.projectName, language: profile.language, frameworks: profile.frameworks, tags: profile.tags }
145
+ }, null, 2));
146
+ return;
147
+ }
148
+ const allLines = [
149
+ ...renderHeader(report, profile),
150
+ ...renderSetupStatus(report.results),
151
+ ...renderRecommendations(report.recommendations),
152
+ ...renderProjectRecs(profile),
153
+ ...renderQuickActions(),
154
+ ""
155
+ ];
156
+ console.log(renderBox(allLines));
157
+ }
158
+
159
+ export { status };
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
2
2
  import ansis from 'ansis';
3
3
  import inquirer from 'inquirer';
4
4
  import { join } from 'pathe';
5
- import { i18n } from './index2.mjs';
5
+ import { i18n } from './index.mjs';
6
6
  import { writeFileAtomic } from './fs-operations.mjs';
7
7
  import 'node:process';
8
8
  import 'node:url';
@@ -1,9 +1,9 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
3
  import { SETTINGS_FILE } from './constants.mjs';
4
- import { i18n } from './index2.mjs';
4
+ import { i18n } from './index.mjs';
5
5
  import { readJsonConfig, writeJsonConfig } from './json-config.mjs';
6
- import { a as handleExitPromptError, h as handleGeneralError } from '../shared/ccjk.f40us0yY.mjs';
6
+ import { h as handleExitPromptError, a as handleGeneralError } from '../shared/ccjk.DvIrK0wz.mjs';
7
7
  import 'node:os';
8
8
  import 'pathe';
9
9
  import 'node:fs';
@@ -1,10 +1,10 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
3
  import { ZCF_CONFIG_FILE, DEFAULT_CODE_TOOL_TYPE, isCodeToolType } from './constants.mjs';
4
- import { i18n, ensureI18nInitialized } from './index2.mjs';
4
+ import { i18n, ensureI18nInitialized } from './index.mjs';
5
5
  import { readZcfConfig } from './ccjk-config.mjs';
6
- import { r as resolveCodeType } from '../shared/ccjk.DRweXU5F.mjs';
7
- import { a as handleExitPromptError, h as handleGeneralError } from '../shared/ccjk.f40us0yY.mjs';
6
+ import { r as resolveCodeType } from '../shared/ccjk.q1koQxEE.mjs';
7
+ import { h as handleExitPromptError, a as handleGeneralError } from '../shared/ccjk.DvIrK0wz.mjs';
8
8
  import { a as addNumbersToChoices } from '../shared/ccjk.BFQ7yr5S.mjs';
9
9
  import { p as promptBoolean } from '../shared/ccjk.DHbrGcgg.mjs';
10
10
  import { promises } from 'node:fs';
@@ -21,10 +21,10 @@ import 'smol-toml';
21
21
  import './fs-operations.mjs';
22
22
  import 'node:crypto';
23
23
  import 'node:fs/promises';
24
- import 'dayjs';
25
24
  import 'node:child_process';
26
25
  import './platform.mjs';
27
26
  import 'inquirer-toggle';
27
+ import 'dayjs';
28
28
  import 'trash';
29
29
 
30
30
  async function pathExists(p) {
@@ -322,7 +322,7 @@ class ZcfUninstaller {
322
322
  result.removed.push(".claude.json (includes MCP configuration)");
323
323
  }
324
324
  try {
325
- const { uninstallCodeTool } = await import('./installer.mjs');
325
+ const { uninstallCodeTool } = await import('./installer2.mjs');
326
326
  const success = await uninstallCodeTool("claude-code");
327
327
  if (success) {
328
328
  result.removed.push("@anthropic-ai/claude-code");
@@ -558,7 +558,7 @@ async function uninstall(options = {}) {
558
558
  }
559
559
  const uninstaller = new ZcfUninstaller(options.lang || "en");
560
560
  if (codeType === "codex") {
561
- const { runCodexUninstall } = await import('./codex.mjs').then(function (n) { return n.i; });
561
+ const { runCodexUninstall } = await import('./codex.mjs').then(function (n) { return n.m; });
562
562
  await runCodexUninstall();
563
563
  return;
564
564
  }
@@ -2,14 +2,13 @@ import { existsSync } from 'node:fs';
2
2
  import ansis from 'ansis';
3
3
  import { version } from './package.mjs';
4
4
  import { SETTINGS_FILE, DEFAULT_CODE_TOOL_TYPE, resolveCodeToolType as resolveCodeToolType$1, isCodeToolType } from './constants.mjs';
5
- import { i18n } from './index2.mjs';
6
- import { d as displayBanner } from '../shared/ccjk.zCqdxT2Y.mjs';
5
+ import { i18n } from './index.mjs';
6
+ import { a as displayBanner } from '../shared/ccjk.Br91zBIG.mjs';
7
7
  import { readZcfConfig, updateZcfConfig } from './ccjk-config.mjs';
8
- import { c as runCodexUpdate } from './codex.mjs';
9
- import { h as copyConfigFiles } from './config.mjs';
10
- import { n as needsMigration, m as migrateSettingsForTokenRetrieval, d as displayMigrationResult, p as promptMigration, s as selectAndInstallWorkflows } from '../shared/ccjk.BM_HZogn.mjs';
11
- import { u as updatePromptOnly } from '../shared/ccjk.CS0ybJCf.mjs';
12
- import { a as handleExitPromptError, h as handleGeneralError } from '../shared/ccjk.f40us0yY.mjs';
8
+ import { d as runCodexUpdate } from './codex.mjs';
9
+ import { a as copyConfigFiles } from './config.mjs';
10
+ import { n as needsMigration, a as migrateSettingsForTokenRetrieval, d as displayMigrationResult, p as promptMigration, u as updatePromptOnly, s as selectAndInstallWorkflows } from '../shared/ccjk.LsPZ2PYo.mjs';
11
+ import { h as handleExitPromptError, a as handleGeneralError } from '../shared/ccjk.DvIrK0wz.mjs';
13
12
  import { resolveAiOutputLanguage } from './prompts.mjs';
14
13
  import { checkClaudeCodeVersionAndPrompt } from './version-checker.mjs';
15
14
  import 'node:os';
@@ -32,10 +31,8 @@ import './platform.mjs';
32
31
  import '../shared/ccjk.BFQ7yr5S.mjs';
33
32
  import '../shared/ccjk.DHbrGcgg.mjs';
34
33
  import 'inquirer-toggle';
35
- import '../shared/ccjk.CZgIwikC.mjs';
36
34
  import 'node:child_process';
37
35
  import './claude-config.mjs';
38
- import './workflows.mjs';
39
36
  import 'node:path';
40
37
  import 'node:util';
41
38
 
@@ -4,8 +4,8 @@ import ora from 'ora';
4
4
  import * as semver from 'semver';
5
5
  import { exec } from 'tinyexec';
6
6
  import { version } from './package.mjs';
7
- import { S as STATUS } from '../shared/ccjk.zCqdxT2Y.mjs';
8
- import './index2.mjs';
7
+ import { S as STATUS } from '../shared/ccjk.Br91zBIG.mjs';
8
+ import './index.mjs';
9
9
  import 'node:fs';
10
10
  import 'node:url';
11
11
  import 'i18next';
@@ -4,7 +4,7 @@ import * as path from 'node:path';
4
4
  import process__default from 'node:process';
5
5
  import { promisify } from 'node:util';
6
6
  import * as semver from 'semver';
7
- import { g as getPlatform, f as findCommandPath, a as getHomebrewCommandPaths } from './platform.mjs';
7
+ import { b as getPlatform, f as findCommandPath, e as getHomebrewCommandPaths } from './platform.mjs';
8
8
  import 'node:os';
9
9
  import 'pathe';
10
10
  import 'tinyexec';
@@ -625,7 +625,7 @@ async function performNpmRemovalAndActivateHomebrew(_npmInstallation, homebrewIn
625
625
  if (homebrewInstallation && !homebrewInstallation.isActive) {
626
626
  console.log("");
627
627
  console.log(ansis.green(`\u{1F517} ${i18n.t("installation:activatingHomebrew")}`));
628
- const { createHomebrewSymlink } = await import('./installer.mjs');
628
+ const { createHomebrewSymlink } = await import('./installer2.mjs');
629
629
  const symlinkResult = await createHomebrewSymlink("claude", homebrewInstallation.path);
630
630
  if (symlinkResult.success) {
631
631
  console.log(ansis.green(`\u2714 ${i18n.t("installation:symlinkCreated", { path: symlinkResult.symlinkPath || "/usr/local/bin/claude" })}`));
@@ -649,7 +649,7 @@ async function performNpmRemovalAndActivateHomebrew(_npmInstallation, homebrewIn
649
649
  }
650
650
  }
651
651
  async function handleDuplicateInstallations(skipPrompt = false) {
652
- const { ensureI18nInitialized, format, i18n } = await import('./index2.mjs');
652
+ const { ensureI18nInitialized, format, i18n } = await import('./index.mjs');
653
653
  const ansis = (await import('ansis')).default;
654
654
  ensureI18nInitialized();
655
655
  const duplicateInfo = await checkDuplicateInstallations();
@@ -1,6 +1,6 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { ensureI18nInitialized, i18n } from './index2.mjs';
3
+ import { ensureI18nInitialized, i18n } from './index.mjs';
4
4
  import { existsSync, readFileSync } from 'node:fs';
5
5
  import { readFile, writeFile, mkdir } from 'node:fs/promises';
6
6
  import { homedir } from 'node:os';