@ekkos/cli 1.3.1 → 1.3.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 (131) 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 +742 -118
  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.d.ts +1 -0
  13. package/dist/commands/init.js +56 -41
  14. package/dist/commands/run.d.ts +0 -1
  15. package/dist/commands/run.js +288 -263
  16. package/dist/commands/scan.d.ts +21 -0
  17. package/dist/commands/scan.js +386 -0
  18. package/dist/commands/status.d.ts +4 -1
  19. package/dist/commands/status.js +165 -27
  20. package/dist/commands/swarm-dashboard.js +156 -28
  21. package/dist/commands/swarm.d.ts +1 -1
  22. package/dist/commands/swarm.js +1 -1
  23. package/dist/commands/test-claude.d.ts +2 -2
  24. package/dist/commands/test-claude.js +3 -3
  25. package/dist/deploy/index.d.ts +0 -2
  26. package/dist/deploy/index.js +0 -2
  27. package/dist/deploy/settings.d.ts +6 -5
  28. package/dist/deploy/settings.js +64 -16
  29. package/dist/deploy/skills.js +1 -2
  30. package/dist/index.js +86 -96
  31. package/dist/lib/usage-parser.d.ts +1 -1
  32. package/dist/lib/usage-parser.js +9 -6
  33. package/dist/local/index.d.ts +14 -0
  34. package/dist/local/index.js +28 -0
  35. package/dist/local/local-embeddings.d.ts +49 -0
  36. package/dist/local/local-embeddings.js +232 -0
  37. package/dist/local/offline-fallback.d.ts +44 -0
  38. package/dist/local/offline-fallback.js +159 -0
  39. package/dist/local/sqlite-store.d.ts +126 -0
  40. package/dist/local/sqlite-store.js +393 -0
  41. package/dist/local/sync-engine.d.ts +42 -0
  42. package/dist/local/sync-engine.js +223 -0
  43. package/dist/utils/platform.d.ts +5 -1
  44. package/dist/utils/platform.js +24 -4
  45. package/dist/utils/proxy-url.d.ts +21 -0
  46. package/dist/utils/proxy-url.js +34 -0
  47. package/dist/utils/state.d.ts +1 -1
  48. package/dist/utils/state.js +11 -3
  49. package/dist/utils/templates.js +1 -1
  50. package/package.json +11 -4
  51. package/templates/CLAUDE.md +49 -107
  52. package/dist/agent/daemon.d.ts +0 -130
  53. package/dist/agent/daemon.js +0 -606
  54. package/dist/agent/health-check.d.ts +0 -35
  55. package/dist/agent/health-check.js +0 -243
  56. package/dist/agent/pty-runner.d.ts +0 -53
  57. package/dist/agent/pty-runner.js +0 -190
  58. package/dist/commands/agent.d.ts +0 -50
  59. package/dist/commands/agent.js +0 -544
  60. package/dist/commands/setup-remote.d.ts +0 -20
  61. package/dist/commands/setup-remote.js +0 -582
  62. package/dist/utils/verify-remote-terminal.d.ts +0 -10
  63. package/dist/utils/verify-remote-terminal.js +0 -415
  64. package/templates/README.md +0 -378
  65. package/templates/claude-plugins/PHASE2_COMPLETION.md +0 -346
  66. package/templates/claude-plugins/PLUGIN_PROPOSALS.md +0 -1776
  67. package/templates/claude-plugins/README.md +0 -587
  68. package/templates/claude-plugins/agents/code-reviewer.json +0 -14
  69. package/templates/claude-plugins/agents/debug-detective.json +0 -15
  70. package/templates/claude-plugins/agents/git-companion.json +0 -14
  71. package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +0 -8
  72. package/templates/claude-plugins/blog-manager/commands/blog.md +0 -691
  73. package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +0 -8
  74. package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +0 -434
  75. package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +0 -8
  76. package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +0 -282
  77. package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +0 -8
  78. package/templates/claude-plugins/memory-lens/commands/memory-search.md +0 -181
  79. package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +0 -8
  80. package/templates/claude-plugins/pattern-coach/commands/forge.md +0 -365
  81. package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +0 -8
  82. package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +0 -582
  83. package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +0 -819
  84. package/templates/claude-plugins-admin/README.md +0 -446
  85. package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +0 -8
  86. package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +0 -595
  87. package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +0 -8
  88. package/templates/claude-plugins-admin/backend-agent/commands/backend.md +0 -798
  89. package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +0 -8
  90. package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +0 -554
  91. package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +0 -8
  92. package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +0 -881
  93. package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +0 -8
  94. package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +0 -85
  95. package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +0 -8
  96. package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +0 -569
  97. package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +0 -8
  98. package/templates/claude-plugins-admin/qa-agent/commands/qa.md +0 -863
  99. package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +0 -8
  100. package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +0 -732
  101. package/templates/commands/continue.md +0 -47
  102. package/templates/cursor-rules/ekkos-memory.md +0 -127
  103. package/templates/ekkos-manifest.json +0 -223
  104. package/templates/helpers/json-parse.cjs +0 -101
  105. package/templates/hooks-node/lib/state.js +0 -187
  106. package/templates/hooks-node/stop.js +0 -416
  107. package/templates/hooks-node/user-prompt-submit.js +0 -337
  108. package/templates/plan-template.md +0 -306
  109. package/templates/rules/00-hooks-contract.mdc +0 -89
  110. package/templates/rules/30-ekkos-core.mdc +0 -188
  111. package/templates/rules/31-ekkos-messages.mdc +0 -78
  112. package/templates/shared/hooks-enabled.json +0 -22
  113. package/templates/shared/session-words.json +0 -45
  114. package/templates/skills/ekkOS_Deep_Recall/Skill.md +0 -282
  115. package/templates/skills/ekkOS_Learn/Skill.md +0 -265
  116. package/templates/skills/ekkOS_Memory_First/Skill.md +0 -206
  117. package/templates/skills/ekkOS_Plan_Assist/Skill.md +0 -302
  118. package/templates/skills/ekkOS_Preferences/Skill.md +0 -247
  119. package/templates/skills/ekkOS_Reflect/Skill.md +0 -257
  120. package/templates/skills/ekkOS_Safety/Skill.md +0 -265
  121. package/templates/skills/ekkOS_Schema/Skill.md +0 -251
  122. package/templates/skills/ekkOS_Summary/Skill.md +0 -257
  123. package/templates/spec-template.md +0 -159
  124. package/templates/windsurf-rules/ekkos-memory.md +0 -127
  125. package/templates/windsurf-skills/README.md +0 -58
  126. package/templates/windsurf-skills/ekkos-continue/SKILL.md +0 -81
  127. package/templates/windsurf-skills/ekkos-golden-loop/SKILL.md +0 -225
  128. package/templates/windsurf-skills/ekkos-insights/SKILL.md +0 -138
  129. package/templates/windsurf-skills/ekkos-recall/SKILL.md +0 -96
  130. package/templates/windsurf-skills/ekkos-safety/SKILL.md +0 -89
  131. 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
+ }