@ekkos/cli 1.3.2 → 1.3.6

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 (123) hide show
  1. package/dist/capture/jsonl-rewriter.d.ts +1 -1
  2. package/dist/capture/jsonl-rewriter.js +3 -3
  3. package/dist/capture/transcript-repair.d.ts +2 -2
  4. package/dist/capture/transcript-repair.js +2 -2
  5. package/dist/commands/claw.d.ts +13 -0
  6. package/dist/commands/claw.js +253 -0
  7. package/dist/commands/dashboard.js +617 -83
  8. package/dist/commands/doctor.d.ts +3 -3
  9. package/dist/commands/doctor.js +6 -79
  10. package/dist/commands/gemini.d.ts +19 -0
  11. package/dist/commands/gemini.js +193 -0
  12. package/dist/commands/init.js +2 -25
  13. package/dist/commands/run.d.ts +0 -1
  14. package/dist/commands/run.js +147 -241
  15. package/dist/commands/scan.d.ts +21 -0
  16. package/dist/commands/scan.js +386 -0
  17. package/dist/commands/swarm-dashboard.js +156 -28
  18. package/dist/commands/swarm.d.ts +1 -1
  19. package/dist/commands/swarm.js +1 -1
  20. package/dist/commands/test-claude.d.ts +2 -2
  21. package/dist/commands/test-claude.js +3 -3
  22. package/dist/deploy/index.d.ts +0 -2
  23. package/dist/deploy/index.js +0 -2
  24. package/dist/deploy/settings.d.ts +2 -2
  25. package/dist/deploy/settings.js +42 -4
  26. package/dist/deploy/skills.js +1 -2
  27. package/dist/index.js +79 -19
  28. package/dist/lib/usage-parser.js +5 -4
  29. package/dist/utils/proxy-url.d.ts +12 -1
  30. package/dist/utils/proxy-url.js +16 -1
  31. package/dist/utils/templates.js +1 -1
  32. package/package.json +4 -6
  33. package/templates/CLAUDE.md +49 -107
  34. package/dist/agent/daemon.d.ts +0 -130
  35. package/dist/agent/daemon.js +0 -606
  36. package/dist/agent/health-check.d.ts +0 -35
  37. package/dist/agent/health-check.js +0 -243
  38. package/dist/agent/pty-runner.d.ts +0 -53
  39. package/dist/agent/pty-runner.js +0 -190
  40. package/dist/commands/agent.d.ts +0 -50
  41. package/dist/commands/agent.js +0 -544
  42. package/dist/commands/setup-remote.d.ts +0 -20
  43. package/dist/commands/setup-remote.js +0 -582
  44. package/dist/commands/synk.d.ts +0 -7
  45. package/dist/commands/synk.js +0 -339
  46. package/dist/cron/index.d.ts +0 -7
  47. package/dist/cron/index.js +0 -13
  48. package/dist/cron/promoter.d.ts +0 -70
  49. package/dist/cron/promoter.js +0 -403
  50. package/dist/synk/api.d.ts +0 -22
  51. package/dist/synk/api.js +0 -133
  52. package/dist/synk/auth.d.ts +0 -7
  53. package/dist/synk/auth.js +0 -30
  54. package/dist/synk/config.d.ts +0 -18
  55. package/dist/synk/config.js +0 -37
  56. package/dist/synk/daemon/control-client.d.ts +0 -11
  57. package/dist/synk/daemon/control-client.js +0 -101
  58. package/dist/synk/daemon/control-server.d.ts +0 -24
  59. package/dist/synk/daemon/control-server.js +0 -91
  60. package/dist/synk/daemon/run.d.ts +0 -14
  61. package/dist/synk/daemon/run.js +0 -338
  62. package/dist/synk/encryption.d.ts +0 -17
  63. package/dist/synk/encryption.js +0 -133
  64. package/dist/synk/index.d.ts +0 -13
  65. package/dist/synk/index.js +0 -36
  66. package/dist/synk/machine-client.d.ts +0 -42
  67. package/dist/synk/machine-client.js +0 -218
  68. package/dist/synk/persistence.d.ts +0 -51
  69. package/dist/synk/persistence.js +0 -211
  70. package/dist/synk/qr.d.ts +0 -5
  71. package/dist/synk/qr.js +0 -33
  72. package/dist/synk/session-bridge.d.ts +0 -58
  73. package/dist/synk/session-bridge.js +0 -171
  74. package/dist/synk/session-client.d.ts +0 -46
  75. package/dist/synk/session-client.js +0 -240
  76. package/dist/synk/types.d.ts +0 -574
  77. package/dist/synk/types.js +0 -74
  78. package/dist/utils/verify-remote-terminal.d.ts +0 -10
  79. package/dist/utils/verify-remote-terminal.js +0 -415
  80. package/templates/README.md +0 -378
  81. package/templates/claude-plugins/PHASE2_COMPLETION.md +0 -346
  82. package/templates/claude-plugins/PLUGIN_PROPOSALS.md +0 -1776
  83. package/templates/claude-plugins/README.md +0 -587
  84. package/templates/claude-plugins/agents/code-reviewer.json +0 -14
  85. package/templates/claude-plugins/agents/debug-detective.json +0 -15
  86. package/templates/claude-plugins/agents/git-companion.json +0 -14
  87. package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +0 -8
  88. package/templates/claude-plugins/blog-manager/commands/blog.md +0 -691
  89. package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +0 -8
  90. package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +0 -434
  91. package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +0 -8
  92. package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +0 -282
  93. package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +0 -8
  94. package/templates/claude-plugins/memory-lens/commands/memory-search.md +0 -181
  95. package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +0 -8
  96. package/templates/claude-plugins/pattern-coach/commands/forge.md +0 -365
  97. package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +0 -8
  98. package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +0 -582
  99. package/templates/commands/continue.md +0 -47
  100. package/templates/cursor-rules/ekkos-memory.md +0 -127
  101. package/templates/ekkos-manifest.json +0 -223
  102. package/templates/helpers/json-parse.cjs +0 -101
  103. package/templates/plan-template.md +0 -306
  104. package/templates/shared/hooks-enabled.json +0 -22
  105. package/templates/shared/session-words.json +0 -45
  106. package/templates/skills/ekkOS_Deep_Recall/Skill.md +0 -282
  107. package/templates/skills/ekkOS_Learn/Skill.md +0 -265
  108. package/templates/skills/ekkOS_Memory_First/Skill.md +0 -206
  109. package/templates/skills/ekkOS_Plan_Assist/Skill.md +0 -302
  110. package/templates/skills/ekkOS_Preferences/Skill.md +0 -247
  111. package/templates/skills/ekkOS_Reflect/Skill.md +0 -257
  112. package/templates/skills/ekkOS_Safety/Skill.md +0 -265
  113. package/templates/skills/ekkOS_Schema/Skill.md +0 -251
  114. package/templates/skills/ekkOS_Summary/Skill.md +0 -257
  115. package/templates/spec-template.md +0 -159
  116. package/templates/windsurf-rules/ekkos-memory.md +0 -127
  117. package/templates/windsurf-skills/README.md +0 -58
  118. package/templates/windsurf-skills/ekkos-continue/SKILL.md +0 -81
  119. package/templates/windsurf-skills/ekkos-golden-loop/SKILL.md +0 -225
  120. package/templates/windsurf-skills/ekkos-insights/SKILL.md +0 -138
  121. package/templates/windsurf-skills/ekkos-recall/SKILL.md +0 -96
  122. package/templates/windsurf-skills/ekkos-safety/SKILL.md +0 -89
  123. package/templates/windsurf-skills/ekkos-vault/SKILL.md +0 -86
@@ -87,7 +87,7 @@ export declare function getEvictionStats(): {
87
87
  lastEviction?: string;
88
88
  };
89
89
  /**
90
- * Get evicted content for retrieval (used by ccDNA)
90
+ * Get evicted content for retrieval
91
91
  */
92
92
  export declare function getEvictedContent(limit?: number): Array<{
93
93
  timestamp: string;
@@ -283,7 +283,7 @@ function truncateToolResult(line) {
283
283
  return line;
284
284
  }
285
285
  }
286
- // Evicted content store (for retrieval by ccDNA)
286
+ // Evicted content store
287
287
  const EVICTED_STORE = path.join(os.homedir(), '.ekkos', 'evicted-context.jsonl');
288
288
  const EKKOS_CAPTURE_ENDPOINT = 'https://mcp.ekkos.dev/api/v1/context/evict';
289
289
  const EKKOS_API_URL = process.env.EKKOS_API_URL || 'https://mcp.ekkos.dev';
@@ -716,7 +716,7 @@ function evictToTarget(filePath, currentPercent, sessionId, sessionName) {
716
716
  debugLog('EVICTION_NOOP', 'No lines to evict or truncate');
717
717
  return { success: true, evicted: 0, truncated: 0, newPercent: currentPercent };
718
718
  }
719
- // Save evicted content for ccDNA retrieval
719
+ // Save evicted content
720
720
  const evictedLines = lines.filter(l => toRemove.has(l.index)).map(l => l.raw);
721
721
  const evictedIndices = lines.filter(l => toRemove.has(l.index)).map(l => l.index);
722
722
  // ═══════════════════════════════════════════════════════════════════════════
@@ -1346,7 +1346,7 @@ function getEvictionStats() {
1346
1346
  }
1347
1347
  }
1348
1348
  /**
1349
- * Get evicted content for retrieval (used by ccDNA)
1349
+ * Get evicted content for retrieval
1350
1350
  */
1351
1351
  function getEvictedContent(limit = 10) {
1352
1352
  try {
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Transcript Repair - Handles orphan tool_result recovery
3
3
  *
4
- * When ccDNA's validate mode detects orphan tool_results (tool_result without
4
+ * When orphan tool_results are detected (tool_result without
5
5
  * matching tool_use), this module repairs the transcript:
6
6
  *
7
7
  * 1. ROLLBACK (preferred): Restore from backup if valid
8
8
  * 2. SURGICAL REPAIR (fallback): Remove orphan tool_result lines
9
9
  *
10
- * This closes the loop: ccDNA detects → ekkos-cli repairs → /clear + /continue
10
+ * This closes the loop: orphan detected → ekkos-cli repairs → transcript clean
11
11
  */
12
12
  type RepairAction = 'none' | 'rollback' | 'surgical_repair' | 'failed';
13
13
  export interface RepairResult {
@@ -2,13 +2,13 @@
2
2
  /**
3
3
  * Transcript Repair - Handles orphan tool_result recovery
4
4
  *
5
- * When ccDNA's validate mode detects orphan tool_results (tool_result without
5
+ * When orphan tool_results are detected (tool_result without
6
6
  * matching tool_use), this module repairs the transcript:
7
7
  *
8
8
  * 1. ROLLBACK (preferred): Restore from backup if valid
9
9
  * 2. SURGICAL REPAIR (fallback): Remove orphan tool_result lines
10
10
  *
11
- * This closes the loop: ccDNA detects → ekkos-cli repairs → /clear + /continue
11
+ * This closes the loop: orphan detected → ekkos-cli repairs → transcript clean
12
12
  */
13
13
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
14
  if (k2 === undefined) k2 = k;
@@ -0,0 +1,13 @@
1
+ interface ClawStatusOptions {
2
+ json?: boolean;
3
+ proxyUrl?: string;
4
+ model?: string;
5
+ workspace?: string;
6
+ }
7
+ interface ClawUpgradeOptions extends ClawStatusOptions {
8
+ apply?: boolean;
9
+ force?: boolean;
10
+ }
11
+ export declare function clawStatus(options?: ClawStatusOptions): Promise<void>;
12
+ export declare function clawUpgrade(options?: ClawUpgradeOptions): Promise<void>;
13
+ export {};
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.clawStatus = clawStatus;
7
+ exports.clawUpgrade = clawUpgrade;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const fs_1 = require("fs");
10
+ const os_1 = require("os");
11
+ const path_1 = require("path");
12
+ const net_1 = __importDefault(require("net"));
13
+ const OPENCLAW_CONFIG_PATH = (0, path_1.join)((0, os_1.homedir)(), '.openclaw', 'openclaw.json');
14
+ const DEFAULT_PROXY_URL = process.env.EKKOS_CLAW_PROXY_URL || 'https://proxy.ekkos.dev';
15
+ const DEFAULT_MODEL = process.env.EKKOS_CLAW_MODEL || 'ekkos-proxy/claude-sonnet-4-6';
16
+ const DEFAULT_WORKSPACE_PATH = process.env.EKKOS_CLAW_WORKSPACE || '/Volumes/Dev_Disk/openclaw/workspace';
17
+ function isRecord(value) {
18
+ return !!value && typeof value === 'object' && !Array.isArray(value);
19
+ }
20
+ function readConfig() {
21
+ if (!(0, fs_1.existsSync)(OPENCLAW_CONFIG_PATH))
22
+ return null;
23
+ try {
24
+ const raw = (0, fs_1.readFileSync)(OPENCLAW_CONFIG_PATH, 'utf-8');
25
+ const parsed = JSON.parse(raw);
26
+ return isRecord(parsed) ? parsed : null;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ function ensureObject(parent, key) {
33
+ const current = parent[key];
34
+ if (isRecord(current))
35
+ return current;
36
+ const next = {};
37
+ parent[key] = next;
38
+ return next;
39
+ }
40
+ function timestampForBackup() {
41
+ return new Date().toISOString().replace(/[:.]/g, '-');
42
+ }
43
+ async function isPortListening(port, host = '127.0.0.1', timeoutMs = 1000) {
44
+ return new Promise((resolve) => {
45
+ const socket = new net_1.default.Socket();
46
+ let done = false;
47
+ const finish = (value) => {
48
+ if (done)
49
+ return;
50
+ done = true;
51
+ socket.destroy();
52
+ resolve(value);
53
+ };
54
+ socket.setTimeout(timeoutMs);
55
+ socket.once('connect', () => finish(true));
56
+ socket.once('timeout', () => finish(false));
57
+ socket.once('error', () => finish(false));
58
+ socket.connect(port, host);
59
+ });
60
+ }
61
+ async function isHttpReachable(url, timeoutMs = 1400) {
62
+ const controller = new AbortController();
63
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
64
+ try {
65
+ const response = await fetch(url, {
66
+ method: 'GET',
67
+ signal: controller.signal,
68
+ });
69
+ return response.ok || response.status < 500;
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ finally {
75
+ clearTimeout(timeout);
76
+ }
77
+ }
78
+ async function collectStatus(options = {}) {
79
+ const expectedProxy = options.proxyUrl || DEFAULT_PROXY_URL;
80
+ const expectedModel = options.model || DEFAULT_MODEL;
81
+ const workspacePath = options.workspace || DEFAULT_WORKSPACE_PATH;
82
+ const config = readConfig();
83
+ const configFound = config !== null;
84
+ const configValid = configFound && isRecord(config);
85
+ const gatewayPort = Number(config?.gateway?.port || 18789);
86
+ const listenerActive = await isPortListening(gatewayPort);
87
+ const uiReachable = await isHttpReachable(`http://127.0.0.1:${gatewayPort}/`);
88
+ const workspaceExists = (0, fs_1.existsSync)(workspacePath);
89
+ let primaryModel = null;
90
+ let ekkosProxyBaseUrl = null;
91
+ let ekkosProxyApi = null;
92
+ if (configValid && config) {
93
+ const agents = config.agents;
94
+ const defaults = isRecord(agents?.defaults) ? agents?.defaults : undefined;
95
+ const model = isRecord(defaults?.model) ? defaults?.model : undefined;
96
+ if (typeof model?.primary === 'string')
97
+ primaryModel = model.primary;
98
+ const models = isRecord(config.models) ? config.models : undefined;
99
+ const providers = isRecord(models?.providers) ? models?.providers : undefined;
100
+ const ekkosProxy = isRecord(providers?.['ekkos-proxy']) ? providers?.['ekkos-proxy'] : undefined;
101
+ if (typeof ekkosProxy?.baseUrl === 'string')
102
+ ekkosProxyBaseUrl = ekkosProxy.baseUrl;
103
+ if (typeof ekkosProxy?.api === 'string')
104
+ ekkosProxyApi = ekkosProxy.api;
105
+ }
106
+ const warnings = [];
107
+ if (!configFound)
108
+ warnings.push(`Missing OpenClaw config: ${OPENCLAW_CONFIG_PATH}`);
109
+ if (configFound && !configValid)
110
+ warnings.push(`Invalid JSON in: ${OPENCLAW_CONFIG_PATH}`);
111
+ if (!listenerActive)
112
+ warnings.push(`No listener on 127.0.0.1:${gatewayPort}`);
113
+ if (!uiReachable)
114
+ warnings.push(`OpenClaw UI check failed: http://127.0.0.1:${gatewayPort}/`);
115
+ if (!workspaceExists)
116
+ warnings.push(`Workspace not found: ${workspacePath}`);
117
+ if (primaryModel !== expectedModel)
118
+ warnings.push(`Primary model is '${primaryModel ?? 'unset'}' (expected '${expectedModel}')`);
119
+ if (ekkosProxyBaseUrl !== expectedProxy)
120
+ warnings.push(`ekkos-proxy baseUrl is '${ekkosProxyBaseUrl ?? 'unset'}' (expected '${expectedProxy}')`);
121
+ if (ekkosProxyApi !== 'anthropic-messages')
122
+ warnings.push(`ekkos-proxy api is '${ekkosProxyApi ?? 'unset'}' (expected 'anthropic-messages')`);
123
+ return {
124
+ timestamp: new Date().toISOString(),
125
+ configPath: OPENCLAW_CONFIG_PATH,
126
+ configFound,
127
+ configValid,
128
+ gatewayPort,
129
+ listenerActive,
130
+ uiReachable,
131
+ primaryModel,
132
+ ekkosProxyBaseUrl,
133
+ ekkosProxyApi,
134
+ workspacePath,
135
+ workspaceExists,
136
+ warnings,
137
+ };
138
+ }
139
+ function printStatus(report) {
140
+ const ok = (value) => (value ? chalk_1.default.green('yes') : chalk_1.default.red('no'));
141
+ console.log('');
142
+ console.log(chalk_1.default.cyan.bold('ekkOS_Claw Status'));
143
+ console.log(chalk_1.default.gray(` checked: ${report.timestamp}`));
144
+ console.log('');
145
+ console.log(` OpenClaw config: ${ok(report.configFound && report.configValid)} ${chalk_1.default.gray(report.configPath)}`);
146
+ console.log(` Listener active: ${ok(report.listenerActive)} ${chalk_1.default.gray(`127.0.0.1:${report.gatewayPort}`)}`);
147
+ console.log(` UI reachable: ${ok(report.uiReachable)} ${chalk_1.default.gray(`http://127.0.0.1:${report.gatewayPort}/`)}`);
148
+ console.log(` Workspace exists: ${ok(report.workspaceExists)} ${chalk_1.default.gray(report.workspacePath)}`);
149
+ console.log(` Primary model: ${chalk_1.default.white(report.primaryModel || 'unset')}`);
150
+ console.log(` ekkos-proxy URL: ${chalk_1.default.white(report.ekkosProxyBaseUrl || 'unset')}`);
151
+ console.log(` ekkos-proxy API: ${chalk_1.default.white(report.ekkosProxyApi || 'unset')}`);
152
+ console.log('');
153
+ if (report.warnings.length > 0) {
154
+ console.log(chalk_1.default.yellow('Warnings:'));
155
+ for (const warning of report.warnings) {
156
+ console.log(chalk_1.default.yellow(` - ${warning}`));
157
+ }
158
+ console.log('');
159
+ }
160
+ else {
161
+ console.log(chalk_1.default.green('Integration looks healthy.'));
162
+ console.log('');
163
+ }
164
+ }
165
+ function planUpgrade(config, options) {
166
+ const nextConfig = JSON.parse(JSON.stringify(config));
167
+ const changes = [];
168
+ const proxyUrl = options.proxyUrl || DEFAULT_PROXY_URL;
169
+ const modelName = options.model || DEFAULT_MODEL;
170
+ const models = ensureObject(nextConfig, 'models');
171
+ const providers = ensureObject(models, 'providers');
172
+ const existingProvider = isRecord(providers['ekkos-proxy']) ? providers['ekkos-proxy'] : {};
173
+ const nextProvider = { ...existingProvider };
174
+ if (nextProvider.baseUrl !== proxyUrl) {
175
+ changes.push(`models.providers.ekkos-proxy.baseUrl -> ${proxyUrl}`);
176
+ nextProvider.baseUrl = proxyUrl;
177
+ }
178
+ if (nextProvider.api !== 'anthropic-messages') {
179
+ changes.push(`models.providers.ekkos-proxy.api -> anthropic-messages`);
180
+ nextProvider.api = 'anthropic-messages';
181
+ }
182
+ const desiredProviderModels = ['claude-sonnet-4-6', 'claude-opus-4-6'];
183
+ const providerModels = Array.isArray(nextProvider.models)
184
+ ? nextProvider.models.filter((v) => typeof v === 'string')
185
+ : [];
186
+ const mergedProviderModels = Array.from(new Set([...providerModels, ...desiredProviderModels]));
187
+ if (mergedProviderModels.length !== providerModels.length) {
188
+ changes.push(`models.providers.ekkos-proxy.models += ${desiredProviderModels.join(', ')}`);
189
+ }
190
+ nextProvider.models = mergedProviderModels;
191
+ providers['ekkos-proxy'] = nextProvider;
192
+ const agents = ensureObject(nextConfig, 'agents');
193
+ const defaults = ensureObject(agents, 'defaults');
194
+ const model = ensureObject(defaults, 'model');
195
+ if (model.primary !== modelName) {
196
+ changes.push(`agents.defaults.model.primary -> ${modelName}`);
197
+ model.primary = modelName;
198
+ }
199
+ return { nextConfig, changes };
200
+ }
201
+ async function clawStatus(options = {}) {
202
+ const report = await collectStatus(options);
203
+ if (options.json) {
204
+ console.log(JSON.stringify(report, null, 2));
205
+ return;
206
+ }
207
+ printStatus(report);
208
+ }
209
+ async function clawUpgrade(options = {}) {
210
+ const config = readConfig();
211
+ if (!config) {
212
+ console.error(chalk_1.default.red(`OpenClaw config missing or invalid: ${OPENCLAW_CONFIG_PATH}`));
213
+ process.exit(1);
214
+ }
215
+ const { nextConfig, changes } = planUpgrade(config, options);
216
+ const reportBefore = await collectStatus(options);
217
+ if (options.json) {
218
+ console.log(JSON.stringify({
219
+ apply: !!options.apply,
220
+ force: !!options.force,
221
+ changes,
222
+ before: reportBefore,
223
+ }, null, 2));
224
+ return;
225
+ }
226
+ console.log('');
227
+ console.log(chalk_1.default.cyan.bold('ekkOS_Claw Upgrade (foundation)'));
228
+ console.log('');
229
+ if (changes.length === 0) {
230
+ console.log(chalk_1.default.green('No config changes needed. OpenClaw already points to ekkOS proxy.'));
231
+ console.log('');
232
+ printStatus(reportBefore);
233
+ return;
234
+ }
235
+ console.log(chalk_1.default.cyan('Planned changes:'));
236
+ for (const change of changes) {
237
+ console.log(` - ${change}`);
238
+ }
239
+ console.log('');
240
+ if (!options.apply) {
241
+ console.log(chalk_1.default.yellow('Dry run only. Re-run with --apply to write config changes.'));
242
+ console.log('');
243
+ return;
244
+ }
245
+ const backupPath = `${OPENCLAW_CONFIG_PATH}.bak.${timestampForBackup()}`;
246
+ (0, fs_1.copyFileSync)(OPENCLAW_CONFIG_PATH, backupPath);
247
+ (0, fs_1.writeFileSync)(OPENCLAW_CONFIG_PATH, `${JSON.stringify(nextConfig, null, 2)}\n`, 'utf-8');
248
+ console.log(chalk_1.default.green(`Updated ${OPENCLAW_CONFIG_PATH}`));
249
+ console.log(chalk_1.default.gray(`Backup written: ${backupPath}`));
250
+ console.log('');
251
+ const reportAfter = await collectStatus(options);
252
+ printStatus(reportAfter);
253
+ }