@mainwp/control 1.0.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 (204) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +583 -0
  3. package/bin/_exit.js +12 -0
  4. package/bin/dev.js +7 -0
  5. package/bin/run.js +7 -0
  6. package/dist/chat/chat-engine.d.ts +213 -0
  7. package/dist/chat/chat-engine.d.ts.map +1 -0
  8. package/dist/chat/chat-engine.js +636 -0
  9. package/dist/chat/chat-engine.js.map +1 -0
  10. package/dist/chat/index.d.ts +10 -0
  11. package/dist/chat/index.d.ts.map +1 -0
  12. package/dist/chat/index.js +14 -0
  13. package/dist/chat/index.js.map +1 -0
  14. package/dist/chat/providers/anthropic.d.ts +52 -0
  15. package/dist/chat/providers/anthropic.d.ts.map +1 -0
  16. package/dist/chat/providers/anthropic.js +292 -0
  17. package/dist/chat/providers/anthropic.js.map +1 -0
  18. package/dist/chat/providers/gemini.d.ts +52 -0
  19. package/dist/chat/providers/gemini.d.ts.map +1 -0
  20. package/dist/chat/providers/gemini.js +284 -0
  21. package/dist/chat/providers/gemini.js.map +1 -0
  22. package/dist/chat/providers/index.d.ts +19 -0
  23. package/dist/chat/providers/index.d.ts.map +1 -0
  24. package/dist/chat/providers/index.js +23 -0
  25. package/dist/chat/providers/index.js.map +1 -0
  26. package/dist/chat/providers/local.d.ts +37 -0
  27. package/dist/chat/providers/local.d.ts.map +1 -0
  28. package/dist/chat/providers/local.js +130 -0
  29. package/dist/chat/providers/local.js.map +1 -0
  30. package/dist/chat/providers/openai-compatible.d.ts +155 -0
  31. package/dist/chat/providers/openai-compatible.d.ts.map +1 -0
  32. package/dist/chat/providers/openai-compatible.js +264 -0
  33. package/dist/chat/providers/openai-compatible.js.map +1 -0
  34. package/dist/chat/providers/openai.d.ts +24 -0
  35. package/dist/chat/providers/openai.d.ts.map +1 -0
  36. package/dist/chat/providers/openai.js +62 -0
  37. package/dist/chat/providers/openai.js.map +1 -0
  38. package/dist/chat/providers/openrouter.d.ts +26 -0
  39. package/dist/chat/providers/openrouter.d.ts.map +1 -0
  40. package/dist/chat/providers/openrouter.js +65 -0
  41. package/dist/chat/providers/openrouter.js.map +1 -0
  42. package/dist/chat/providers/provider-fetch.d.ts +15 -0
  43. package/dist/chat/providers/provider-fetch.d.ts.map +1 -0
  44. package/dist/chat/providers/provider-fetch.js +35 -0
  45. package/dist/chat/providers/provider-fetch.js.map +1 -0
  46. package/dist/chat/providers/provider.d.ts +214 -0
  47. package/dist/chat/providers/provider.d.ts.map +1 -0
  48. package/dist/chat/providers/provider.js +166 -0
  49. package/dist/chat/providers/provider.js.map +1 -0
  50. package/dist/chat/providers/sse-reader.d.ts +21 -0
  51. package/dist/chat/providers/sse-reader.d.ts.map +1 -0
  52. package/dist/chat/providers/sse-reader.js +48 -0
  53. package/dist/chat/providers/sse-reader.js.map +1 -0
  54. package/dist/chat/system-prompt.d.ts +33 -0
  55. package/dist/chat/system-prompt.d.ts.map +1 -0
  56. package/dist/chat/system-prompt.js +166 -0
  57. package/dist/chat/system-prompt.js.map +1 -0
  58. package/dist/chat/tool-envelope.d.ts +72 -0
  59. package/dist/chat/tool-envelope.d.ts.map +1 -0
  60. package/dist/chat/tool-envelope.js +263 -0
  61. package/dist/chat/tool-envelope.js.map +1 -0
  62. package/dist/commands/abilities/info.d.ts +21 -0
  63. package/dist/commands/abilities/info.d.ts.map +1 -0
  64. package/dist/commands/abilities/info.js +80 -0
  65. package/dist/commands/abilities/info.js.map +1 -0
  66. package/dist/commands/abilities/list.d.ts +19 -0
  67. package/dist/commands/abilities/list.d.ts.map +1 -0
  68. package/dist/commands/abilities/list.js +98 -0
  69. package/dist/commands/abilities/list.js.map +1 -0
  70. package/dist/commands/abilities/run.d.ts +75 -0
  71. package/dist/commands/abilities/run.d.ts.map +1 -0
  72. package/dist/commands/abilities/run.js +468 -0
  73. package/dist/commands/abilities/run.js.map +1 -0
  74. package/dist/commands/chat.d.ts +54 -0
  75. package/dist/commands/chat.d.ts.map +1 -0
  76. package/dist/commands/chat.js +384 -0
  77. package/dist/commands/chat.js.map +1 -0
  78. package/dist/commands/config/show.d.ts +54 -0
  79. package/dist/commands/config/show.d.ts.map +1 -0
  80. package/dist/commands/config/show.js +324 -0
  81. package/dist/commands/config/show.js.map +1 -0
  82. package/dist/commands/doctor.d.ts +77 -0
  83. package/dist/commands/doctor.d.ts.map +1 -0
  84. package/dist/commands/doctor.js +412 -0
  85. package/dist/commands/doctor.js.map +1 -0
  86. package/dist/commands/jobs/watch.d.ts +50 -0
  87. package/dist/commands/jobs/watch.d.ts.map +1 -0
  88. package/dist/commands/jobs/watch.js +269 -0
  89. package/dist/commands/jobs/watch.js.map +1 -0
  90. package/dist/commands/login.d.ts +25 -0
  91. package/dist/commands/login.d.ts.map +1 -0
  92. package/dist/commands/login.js +165 -0
  93. package/dist/commands/login.js.map +1 -0
  94. package/dist/commands/profile/delete.d.ts +22 -0
  95. package/dist/commands/profile/delete.d.ts.map +1 -0
  96. package/dist/commands/profile/delete.js +57 -0
  97. package/dist/commands/profile/delete.js.map +1 -0
  98. package/dist/commands/profile/list.d.ts +19 -0
  99. package/dist/commands/profile/list.d.ts.map +1 -0
  100. package/dist/commands/profile/list.js +53 -0
  101. package/dist/commands/profile/list.js.map +1 -0
  102. package/dist/commands/profile/use.d.ts +22 -0
  103. package/dist/commands/profile/use.d.ts.map +1 -0
  104. package/dist/commands/profile/use.js +46 -0
  105. package/dist/commands/profile/use.js.map +1 -0
  106. package/dist/config/fs-utils.d.ts +14 -0
  107. package/dist/config/fs-utils.d.ts.map +1 -0
  108. package/dist/config/fs-utils.js +31 -0
  109. package/dist/config/fs-utils.js.map +1 -0
  110. package/dist/config/keychain.d.ts +53 -0
  111. package/dist/config/keychain.d.ts.map +1 -0
  112. package/dist/config/keychain.js +175 -0
  113. package/dist/config/keychain.js.map +1 -0
  114. package/dist/config/profile-store.d.ts +85 -0
  115. package/dist/config/profile-store.d.ts.map +1 -0
  116. package/dist/config/profile-store.js +228 -0
  117. package/dist/config/profile-store.js.map +1 -0
  118. package/dist/config/settings.d.ts +71 -0
  119. package/dist/config/settings.d.ts.map +1 -0
  120. package/dist/config/settings.js +151 -0
  121. package/dist/config/settings.js.map +1 -0
  122. package/dist/core/abilities-executor.d.ts +126 -0
  123. package/dist/core/abilities-executor.d.ts.map +1 -0
  124. package/dist/core/abilities-executor.js +264 -0
  125. package/dist/core/abilities-executor.js.map +1 -0
  126. package/dist/core/batch-manager.d.ts +113 -0
  127. package/dist/core/batch-manager.d.ts.map +1 -0
  128. package/dist/core/batch-manager.js +244 -0
  129. package/dist/core/batch-manager.js.map +1 -0
  130. package/dist/core/http-client.d.ts +111 -0
  131. package/dist/core/http-client.d.ts.map +1 -0
  132. package/dist/core/http-client.js +329 -0
  133. package/dist/core/http-client.js.map +1 -0
  134. package/dist/core/safety-controller.d.ts +114 -0
  135. package/dist/core/safety-controller.d.ts.map +1 -0
  136. package/dist/core/safety-controller.js +229 -0
  137. package/dist/core/safety-controller.js.map +1 -0
  138. package/dist/hooks/command-not-found.d.ts +12 -0
  139. package/dist/hooks/command-not-found.d.ts.map +1 -0
  140. package/dist/hooks/command-not-found.js +58 -0
  141. package/dist/hooks/command-not-found.js.map +1 -0
  142. package/dist/index.d.ts +7 -0
  143. package/dist/index.d.ts.map +1 -0
  144. package/dist/index.js +7 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/lib/base-command.d.ts +123 -0
  147. package/dist/lib/base-command.d.ts.map +1 -0
  148. package/dist/lib/base-command.js +285 -0
  149. package/dist/lib/base-command.js.map +1 -0
  150. package/dist/output/formatter.d.ts +48 -0
  151. package/dist/output/formatter.d.ts.map +1 -0
  152. package/dist/output/formatter.js +138 -0
  153. package/dist/output/formatter.js.map +1 -0
  154. package/dist/output/json-envelope.d.ts +43 -0
  155. package/dist/output/json-envelope.d.ts.map +1 -0
  156. package/dist/output/json-envelope.js +73 -0
  157. package/dist/output/json-envelope.js.map +1 -0
  158. package/dist/utils/audit-logger.d.ts +97 -0
  159. package/dist/utils/audit-logger.d.ts.map +1 -0
  160. package/dist/utils/audit-logger.js +169 -0
  161. package/dist/utils/audit-logger.js.map +1 -0
  162. package/dist/utils/colors.d.ts +29 -0
  163. package/dist/utils/colors.d.ts.map +1 -0
  164. package/dist/utils/colors.js +36 -0
  165. package/dist/utils/colors.js.map +1 -0
  166. package/dist/utils/errors.d.ts +107 -0
  167. package/dist/utils/errors.d.ts.map +1 -0
  168. package/dist/utils/errors.js +149 -0
  169. package/dist/utils/errors.js.map +1 -0
  170. package/dist/utils/exit-codes.d.ts +21 -0
  171. package/dist/utils/exit-codes.d.ts.map +1 -0
  172. package/dist/utils/exit-codes.js +20 -0
  173. package/dist/utils/exit-codes.js.map +1 -0
  174. package/dist/utils/format.d.ts +64 -0
  175. package/dist/utils/format.d.ts.map +1 -0
  176. package/dist/utils/format.js +69 -0
  177. package/dist/utils/format.js.map +1 -0
  178. package/dist/utils/prompt.d.ts +34 -0
  179. package/dist/utils/prompt.d.ts.map +1 -0
  180. package/dist/utils/prompt.js +132 -0
  181. package/dist/utils/prompt.js.map +1 -0
  182. package/dist/utils/retry.d.ts +59 -0
  183. package/dist/utils/retry.d.ts.map +1 -0
  184. package/dist/utils/retry.js +96 -0
  185. package/dist/utils/retry.js.map +1 -0
  186. package/dist/utils/terminal-sanitizer.d.ts +60 -0
  187. package/dist/utils/terminal-sanitizer.d.ts.map +1 -0
  188. package/dist/utils/terminal-sanitizer.js +166 -0
  189. package/dist/utils/terminal-sanitizer.js.map +1 -0
  190. package/dist/validation/input-sanitizer.d.ts +76 -0
  191. package/dist/validation/input-sanitizer.d.ts.map +1 -0
  192. package/dist/validation/input-sanitizer.js +199 -0
  193. package/dist/validation/input-sanitizer.js.map +1 -0
  194. package/dist/validation/schema-validator.d.ts +75 -0
  195. package/dist/validation/schema-validator.d.ts.map +1 -0
  196. package/dist/validation/schema-validator.js +147 -0
  197. package/dist/validation/schema-validator.js.map +1 -0
  198. package/oclif.manifest.json +857 -0
  199. package/package.json +101 -0
  200. package/scripts/completions/README.md +221 -0
  201. package/scripts/completions/mainwpcontrol.bash +193 -0
  202. package/scripts/completions/mainwpcontrol.zsh +267 -0
  203. package/scripts/completions/profile-completer.sh +35 -0
  204. package/scripts/completions/regenerate.sh +78 -0
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Base command for mainwpcontrol
3
+ *
4
+ * Provides common functionality for all CLI commands:
5
+ * - Profile and authentication management
6
+ * - JSON/human output handling
7
+ * - AbilitiesExecutor initialization
8
+ */
9
+ import { Command, Flags } from '@oclif/core';
10
+ import { getProfileStore } from '../config/profile-store.js';
11
+ import { getKeychain } from '../config/keychain.js';
12
+ import { loadSettings, resolveSettings, } from '../config/settings.js';
13
+ import { createAbilitiesExecutor } from '../core/abilities-executor.js';
14
+ import { createBatchManager } from '../core/batch-manager.js';
15
+ import { isMainWPCTLError, ConfigError } from '../utils/errors.js';
16
+ import { successOutput, errorOutput } from '../output/json-envelope.js';
17
+ import { ExitCode } from '../utils/exit-codes.js';
18
+ import { formatError, formatWarning } from '../output/formatter.js';
19
+ /**
20
+ * Common flags available to all commands
21
+ */
22
+ export const commonFlags = {
23
+ json: Flags.boolean({
24
+ description: 'Output JSON (for scripting/CI)',
25
+ // No default - allows distinguishing "not provided" from "explicitly false"
26
+ // Precedence: --json flag > settings.defaultJsonOutput > false
27
+ }),
28
+ quiet: Flags.boolean({
29
+ char: 'q',
30
+ description: 'Suppress output (exit code only)',
31
+ default: false,
32
+ }),
33
+ profile: Flags.string({
34
+ char: 'p',
35
+ description: 'Use a specific profile',
36
+ }),
37
+ debug: Flags.boolean({
38
+ description: 'Show debug output',
39
+ }),
40
+ };
41
+ /**
42
+ * Base command class
43
+ *
44
+ * All mainwpcontrol commands should extend this class.
45
+ */
46
+ export class BaseCommand extends Command {
47
+ /**
48
+ * Current active profile
49
+ */
50
+ currentProfile;
51
+ /**
52
+ * Whether to output JSON
53
+ */
54
+ jsonOutput = false;
55
+ /**
56
+ * Debug mode flag
57
+ */
58
+ debugMode = false;
59
+ /**
60
+ * Whether debug was explicitly requested on the CLI.
61
+ */
62
+ explicitDebugMode = false;
63
+ /**
64
+ * Quiet mode flag — suppress stdout output (exit code only)
65
+ */
66
+ quietMode = false;
67
+ /**
68
+ * Raw settings from settings.json
69
+ */
70
+ rawSettings = {};
71
+ /**
72
+ * Validated and normalized settings
73
+ */
74
+ settings = {
75
+ defaultJsonOutput: false,
76
+ timeout: 30000,
77
+ skipSSLVerification: false,
78
+ debug: false,
79
+ chatContextMessages: 20,
80
+ allowInsecureHttp: false,
81
+ };
82
+ /**
83
+ * Cached executor instance
84
+ */
85
+ executor;
86
+ /**
87
+ * Cached batch manager instance
88
+ */
89
+ batchManagerInstance;
90
+ /**
91
+ * Whether this command needs a profile to be loaded.
92
+ * Override to return false for commands like `login` that don't need a profile.
93
+ */
94
+ needsProfile() {
95
+ return true;
96
+ }
97
+ /**
98
+ * Initialize common functionality.
99
+ * Call this at the start of each command's run() method.
100
+ */
101
+ async initCommon(flags) {
102
+ // Load and validate settings
103
+ this.rawSettings = await loadSettings();
104
+ const resolved = resolveSettings(this.rawSettings);
105
+ this.settings = resolved.settings;
106
+ // Apply precedence: explicit flag > settings file > default (false)
107
+ // flags.json is undefined if not provided, boolean if provided
108
+ this.jsonOutput = flags.json ?? this.settings.defaultJsonOutput;
109
+ this.explicitDebugMode = flags.debug === true;
110
+ this.debugMode = flags.debug ?? this.settings.debug;
111
+ // Quiet mode: suppress stdout. --json and explicit --debug override --quiet.
112
+ this.quietMode = (flags.quiet ?? false) && !this.jsonOutput && !this.explicitDebugMode;
113
+ for (const warning of resolved.warnings) {
114
+ this.logToStderr(formatWarning(warning));
115
+ }
116
+ if (this.needsProfile()) {
117
+ await this.loadProfile(flags.profile);
118
+ }
119
+ }
120
+ /**
121
+ * Load the specified or active profile
122
+ */
123
+ async loadProfile(profileName) {
124
+ const profileStore = getProfileStore();
125
+ if (profileName) {
126
+ const profile = await profileStore.get(profileName);
127
+ if (!profile) {
128
+ throw new ConfigError(`Profile not found: ${profileName}`, undefined, 'List available profiles with `mainwpcontrol profile list` or create one with `mainwpcontrol login`');
129
+ }
130
+ this.currentProfile = profile;
131
+ }
132
+ else {
133
+ this.currentProfile = await profileStore.getActive();
134
+ if (!this.currentProfile) {
135
+ throw new ConfigError('No profile configured.', undefined, 'Create your first profile with `mainwpcontrol login`');
136
+ }
137
+ }
138
+ if (this.currentProfile) {
139
+ this.debugLog('Loaded profile', {
140
+ profile: this.currentProfile.name,
141
+ dashboardUrl: this.currentProfile.dashboardUrl,
142
+ skipSSLVerification: this.getTransportConfig().skipSSLVerification,
143
+ });
144
+ }
145
+ }
146
+ /**
147
+ * Get the AbilitiesExecutor instance
148
+ */
149
+ async getExecutor() {
150
+ if (this.executor) {
151
+ return this.executor;
152
+ }
153
+ if (!this.currentProfile) {
154
+ throw new ConfigError('No profile loaded', undefined, 'This is an internal error. Please report this issue.');
155
+ }
156
+ const keychain = getKeychain();
157
+ const password = await keychain.getOrThrow(this.currentProfile.name);
158
+ this.executor = createAbilitiesExecutor({
159
+ baseUrl: this.currentProfile.dashboardUrl,
160
+ username: this.currentProfile.username,
161
+ appPassword: password,
162
+ ...this.getTransportConfig(),
163
+ });
164
+ this.debugLog('Initialized abilities executor', {
165
+ profile: this.currentProfile.name,
166
+ timeoutMs: this.settings.timeout,
167
+ allowInsecureHttp: this.settings.allowInsecureHttp,
168
+ skipSSLVerification: this.getTransportConfig().skipSSLVerification,
169
+ });
170
+ return this.executor;
171
+ }
172
+ /**
173
+ * Get the BatchManager instance (lazy, cached)
174
+ */
175
+ async getBatchManager() {
176
+ if (this.batchManagerInstance) {
177
+ return this.batchManagerInstance;
178
+ }
179
+ if (!this.currentProfile) {
180
+ throw new ConfigError('No profile loaded', undefined, 'This is an internal error. Please report this issue.');
181
+ }
182
+ const keychain = getKeychain();
183
+ const appPassword = await keychain.getOrThrow(this.currentProfile.name);
184
+ this.batchManagerInstance = createBatchManager({
185
+ baseUrl: this.currentProfile.dashboardUrl,
186
+ username: this.currentProfile.username,
187
+ appPassword,
188
+ ...this.getTransportConfig(),
189
+ });
190
+ this.debugLog('Initialized batch manager', {
191
+ profile: this.currentProfile.name,
192
+ timeoutMs: this.settings.timeout,
193
+ allowInsecureHttp: this.settings.allowInsecureHttp,
194
+ skipSSLVerification: this.getTransportConfig().skipSSLVerification,
195
+ });
196
+ return this.batchManagerInstance;
197
+ }
198
+ /**
199
+ * Build common transport configuration using profile-scoped settings first.
200
+ */
201
+ getTransportConfig() {
202
+ return {
203
+ skipSSLVerification: this.currentProfile?.skipSSLVerification ?? this.settings.skipSSLVerification,
204
+ allowInsecureHttp: this.settings.allowInsecureHttp,
205
+ timeout: this.settings.timeout,
206
+ };
207
+ }
208
+ /**
209
+ * Emit redacted debug output to stderr.
210
+ */
211
+ debugLog(message, context) {
212
+ if (!this.shouldEmitDebug()) {
213
+ return;
214
+ }
215
+ const suffix = context && Object.keys(context).length > 0
216
+ ? ` ${JSON.stringify(this.redactDebugContext(context))}`
217
+ : '';
218
+ this.logToStderr(`[debug] ${message}${suffix}`);
219
+ }
220
+ shouldEmitDebug() {
221
+ if (!this.debugMode) {
222
+ return false;
223
+ }
224
+ return this.explicitDebugMode || !this.quietMode;
225
+ }
226
+ redactDebugContext(context) {
227
+ const sensitiveKeys = ['password', 'secret', 'token', 'authorization', 'cookie', 'apikey'];
228
+ const redacted = {};
229
+ for (const [key, value] of Object.entries(context)) {
230
+ if (sensitiveKeys.includes(key.toLowerCase())) {
231
+ redacted[key] = '[REDACTED]';
232
+ continue;
233
+ }
234
+ if (typeof value === 'string' && value.length > 300) {
235
+ redacted[key] = `${value.slice(0, 297)}...`;
236
+ continue;
237
+ }
238
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
239
+ redacted[key] = this.redactDebugContext(value);
240
+ continue;
241
+ }
242
+ redacted[key] = value;
243
+ }
244
+ return redacted;
245
+ }
246
+ /**
247
+ * Output data in JSON or human-readable format.
248
+ *
249
+ * @param data - The data to output (used for JSON mode)
250
+ * @param humanFormatter - Optional function that returns human-readable string
251
+ */
252
+ output(data, humanFormatter) {
253
+ if (this.quietMode) {
254
+ return;
255
+ }
256
+ if (this.jsonOutput) {
257
+ const envelope = successOutput(data);
258
+ this.log(JSON.stringify(envelope, null, 2));
259
+ }
260
+ else if (humanFormatter) {
261
+ this.log(humanFormatter());
262
+ }
263
+ }
264
+ /**
265
+ * Handle errors with appropriate exit codes
266
+ */
267
+ async catch(err) {
268
+ // Re-throw oclif exit errors to preserve their exit code
269
+ if (err.oclif && typeof err.oclif.exit === 'number') {
270
+ throw err;
271
+ }
272
+ if (this.jsonOutput) {
273
+ const envelope = errorOutput(err);
274
+ this.log(JSON.stringify(envelope, null, 2));
275
+ }
276
+ else {
277
+ // Human-readable error output with hints
278
+ this.logToStderr(formatError(err));
279
+ }
280
+ // Determine exit code from error class (MainWPCTLError subclasses carry exitCode)
281
+ const exitCode = isMainWPCTLError(err) ? err.exitCode : (err.exitCode ?? ExitCode.INTERNAL_ERROR);
282
+ this.exit(exitCode);
283
+ }
284
+ }
285
+ //# sourceMappingURL=base-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-command.js","sourceRoot":"","sources":["../../src/lib/base-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Human-readable output formatter for mainwpcontrol
3
+ */
4
+ /**
5
+ * Format a success message
6
+ */
7
+ export declare function formatSuccess(message: string): string;
8
+ /**
9
+ * Format an error message
10
+ */
11
+ export declare function formatError(error: Error | string): string;
12
+ /**
13
+ * Format a warning message
14
+ */
15
+ export declare function formatWarning(message: string): string;
16
+ /**
17
+ * Format an info message
18
+ */
19
+ export declare function formatInfo(message: string): string;
20
+ /**
21
+ * Format a heading
22
+ */
23
+ export declare function formatHeading(text: string): string;
24
+ /**
25
+ * Format a key-value pair
26
+ */
27
+ export declare function formatKeyValue(key: string, value: unknown): string;
28
+ /**
29
+ * Format a table of data
30
+ */
31
+ export declare function formatTable(headers: string[], rows: string[][]): string;
32
+ /**
33
+ * Format a list of items
34
+ */
35
+ export declare function formatList(items: string[], bullet?: string): string;
36
+ /**
37
+ * Format a preview/dry-run result
38
+ */
39
+ export declare function formatPreview(action: string, affectedItems: unknown): string;
40
+ /**
41
+ * Format a progress bar
42
+ */
43
+ export declare function formatProgressBar(percent: number, width?: number): string;
44
+ /**
45
+ * Format elapsed time
46
+ */
47
+ export declare function formatElapsed(ms: number): string;
48
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAgBzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAKlE;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,MAAM,EAAE,EAAE,GACf,MAAM,CAgCR;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,SAAM,GAAG,MAAM,CAGhE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,OAAO,GACrB,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CASrE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAgBhD"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Human-readable output formatter for mainwpcontrol
3
+ */
4
+ import { isMainWPCTLError } from '../utils/errors.js';
5
+ import { stripControlChars, sanitizeForTerminal, safeString } from '../utils/terminal-sanitizer.js';
6
+ import { colors, color } from '../utils/colors.js';
7
+ /**
8
+ * Format a success message
9
+ */
10
+ export function formatSuccess(message) {
11
+ return color('✓ ', colors.green) + message;
12
+ }
13
+ /**
14
+ * Format an error message
15
+ */
16
+ export function formatError(error) {
17
+ const message = error instanceof Error ? stripControlChars(error.message) : stripControlChars(error);
18
+ let output = color('✗ Error: ', colors.red, colors.bold) + message;
19
+ if (isMainWPCTLError(error)) {
20
+ if (error.details) {
21
+ // Sanitize error details before display (untrusted API data)
22
+ const sanitizedDetails = sanitizeForTerminal(error.details);
23
+ output += '\n' + color(' Details: ', colors.dim) + JSON.stringify(sanitizedDetails);
24
+ }
25
+ if (error.hint) {
26
+ output += '\n' + color('💡 ' + stripControlChars(error.hint), colors.dim);
27
+ }
28
+ }
29
+ return output;
30
+ }
31
+ /**
32
+ * Format a warning message
33
+ */
34
+ export function formatWarning(message) {
35
+ return color('⚠ Warning: ', colors.yellow) + stripControlChars(message);
36
+ }
37
+ /**
38
+ * Format an info message
39
+ */
40
+ export function formatInfo(message) {
41
+ return color('ℹ ', colors.blue) + message;
42
+ }
43
+ /**
44
+ * Format a heading
45
+ */
46
+ export function formatHeading(text) {
47
+ return color(text, colors.bold, colors.cyan);
48
+ }
49
+ /**
50
+ * Format a key-value pair
51
+ */
52
+ export function formatKeyValue(key, value) {
53
+ // Sanitize both key and value (may contain untrusted API data)
54
+ const safeKey = stripControlChars(key);
55
+ const valueStr = safeString(value);
56
+ return color(safeKey + ': ', colors.dim) + valueStr;
57
+ }
58
+ /**
59
+ * Format a table of data
60
+ */
61
+ export function formatTable(headers, rows) {
62
+ if (rows.length === 0) {
63
+ return '(no data)';
64
+ }
65
+ // Sanitize all table data (may contain untrusted API data)
66
+ const safeHeaders = headers.map((h) => stripControlChars(h));
67
+ const safeRows = rows.map((row) => row.map((cell) => stripControlChars(cell ?? '')));
68
+ // Calculate column widths using sanitized data
69
+ const widths = safeHeaders.map((h, i) => {
70
+ const rowWidths = safeRows.map((r) => (r[i] ?? '').length);
71
+ return Math.max(h.length, ...rowWidths);
72
+ });
73
+ // Format header
74
+ const headerLine = safeHeaders
75
+ .map((h, i) => h.padEnd(widths[i] ?? 0))
76
+ .join(' ');
77
+ const separator = widths.map((w) => '-'.repeat(w)).join(' ');
78
+ // Format rows
79
+ const dataLines = safeRows.map((row) => row.map((cell, i) => (cell ?? '').padEnd(widths[i] ?? 0)).join(' '));
80
+ return [
81
+ color(headerLine, colors.bold),
82
+ separator,
83
+ ...dataLines,
84
+ ].join('\n');
85
+ }
86
+ /**
87
+ * Format a list of items
88
+ */
89
+ export function formatList(items, bullet = '•') {
90
+ // Sanitize list items (may contain untrusted API data)
91
+ return items.map((item) => ` ${bullet} ${stripControlChars(item)}`).join('\n');
92
+ }
93
+ /**
94
+ * Format a preview/dry-run result
95
+ */
96
+ export function formatPreview(action, affectedItems) {
97
+ // Sanitize preview data (may contain untrusted API data)
98
+ const sanitizedItems = sanitizeForTerminal(affectedItems);
99
+ const lines = [
100
+ color('Preview: ', colors.yellow, colors.bold) + stripControlChars(action),
101
+ '',
102
+ color('Affected items:', colors.dim),
103
+ JSON.stringify(sanitizedItems, null, 2),
104
+ '',
105
+ color('This is a preview. No changes have been made.', colors.yellow),
106
+ 'To execute, run the command with --confirm',
107
+ ];
108
+ return lines.join('\n');
109
+ }
110
+ /**
111
+ * Format a progress bar
112
+ */
113
+ export function formatProgressBar(percent, width = 20) {
114
+ const clampedPercent = Math.max(0, Math.min(100, percent));
115
+ const filled = Math.round((clampedPercent / 100) * width);
116
+ const empty = width - filled;
117
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
118
+ const percentStr = `${clampedPercent}%`.padStart(4);
119
+ return `[${bar}] ${percentStr}`;
120
+ }
121
+ /**
122
+ * Format elapsed time
123
+ */
124
+ export function formatElapsed(ms) {
125
+ const seconds = Math.floor(ms / 1000);
126
+ const minutes = Math.floor(seconds / 60);
127
+ const hours = Math.floor(minutes / 60);
128
+ if (hours > 0) {
129
+ const remainingMinutes = minutes % 60;
130
+ return `${hours}h ${remainingMinutes}m`;
131
+ }
132
+ if (minutes > 0) {
133
+ const remainingSeconds = seconds % 60;
134
+ return `${minutes}m ${remainingSeconds}s`;
135
+ }
136
+ return `${seconds}s`;
137
+ }
138
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * JSON output envelope for mainwpcontrol
3
+ *
4
+ * This structure is stable and should not be changed without a major version bump.
5
+ */
6
+ import { type MainWPCTLError } from '../utils/errors.js';
7
+ /**
8
+ * Stable CLI output envelope
9
+ */
10
+ export interface CLIOutput<T = unknown> {
11
+ success: boolean;
12
+ data?: T;
13
+ error?: {
14
+ code: string;
15
+ message: string;
16
+ details?: unknown;
17
+ hint?: string;
18
+ };
19
+ meta?: {
20
+ command: string;
21
+ timestamp: string;
22
+ version: string;
23
+ };
24
+ }
25
+ /**
26
+ * Create a success response
27
+ */
28
+ export declare function successOutput<T>(data: T, meta?: {
29
+ command: string;
30
+ version: string;
31
+ }): CLIOutput<T>;
32
+ /**
33
+ * Create an error response
34
+ */
35
+ export declare function errorOutput(error: MainWPCTLError | Error | string, meta?: {
36
+ command: string;
37
+ version: string;
38
+ }): CLIOutput<never>;
39
+ /**
40
+ * Format output as JSON string
41
+ */
42
+ export declare function formatJSON<T>(output: CLIOutput<T>): string;
43
+ //# sourceMappingURL=json-envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-envelope.d.ts","sourceRoot":"","sources":["../../src/output/json-envelope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG3E;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,IAAI,EAAE,CAAC,EACP,IAAI,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C,SAAS,CAAC,CAAC,CAAC,CAkBd;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,GAAG,KAAK,GAAG,MAAM,EACtC,IAAI,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C,SAAS,CAAC,KAAK,CAAC,CAsClB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * JSON output envelope for mainwpcontrol
3
+ *
4
+ * This structure is stable and should not be changed without a major version bump.
5
+ */
6
+ import { isMainWPCTLError } from '../utils/errors.js';
7
+ import { sanitizeForTerminal, stripControlChars } from '../utils/terminal-sanitizer.js';
8
+ /**
9
+ * Create a success response
10
+ */
11
+ export function successOutput(data, meta) {
12
+ // Sanitize data to prevent terminal escape injection in piped JSON
13
+ const sanitizedData = sanitizeForTerminal(data);
14
+ const output = {
15
+ success: true,
16
+ data: sanitizedData,
17
+ };
18
+ if (meta) {
19
+ output.meta = {
20
+ command: meta.command,
21
+ timestamp: new Date().toISOString(),
22
+ version: meta.version,
23
+ };
24
+ }
25
+ return output;
26
+ }
27
+ /**
28
+ * Create an error response
29
+ */
30
+ export function errorOutput(error, meta) {
31
+ let errorBody;
32
+ if (isMainWPCTLError(error)) {
33
+ errorBody = {
34
+ code: error.code,
35
+ message: stripControlChars(error.message),
36
+ details: error.details ? sanitizeForTerminal(error.details) : undefined,
37
+ };
38
+ if (error.hint) {
39
+ errorBody.hint = stripControlChars(error.hint);
40
+ }
41
+ }
42
+ else if (error instanceof Error) {
43
+ errorBody = {
44
+ code: 'INTERNAL_ERROR',
45
+ message: stripControlChars(error.message),
46
+ };
47
+ }
48
+ else {
49
+ errorBody = {
50
+ code: 'INTERNAL_ERROR',
51
+ message: stripControlChars(String(error)),
52
+ };
53
+ }
54
+ const output = {
55
+ success: false,
56
+ error: errorBody,
57
+ };
58
+ if (meta) {
59
+ output.meta = {
60
+ command: meta.command,
61
+ timestamp: new Date().toISOString(),
62
+ version: meta.version,
63
+ };
64
+ }
65
+ return output;
66
+ }
67
+ /**
68
+ * Format output as JSON string
69
+ */
70
+ export function formatJSON(output) {
71
+ return JSON.stringify(output, null, 2);
72
+ }
73
+ //# sourceMappingURL=json-envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-envelope.js","sourceRoot":"","sources":["../../src/output/json-envelope.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAuB,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAqBxF;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAO,EACP,IAA2C;IAE3C,mEAAmE;IACnE,MAAM,aAAa,GAAG,mBAAmB,CAAC,IAAI,CAAM,CAAC;IAErD,MAAM,MAAM,GAAiB;QAC3B,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,aAAa;KACpB,CAAC;IAEF,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,CAAC,IAAI,GAAG;YACZ,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,KAAsC,EACtC,IAA2C;IAE3C,IAAI,SAAoC,CAAC;IAEzC,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,SAAS,GAAG;YACV,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC;YACzC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;SACxE,CAAC;QACF,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,SAAS,CAAC,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;SAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAClC,SAAS,GAAG;YACV,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC;SAC1C,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,SAAS,GAAG;YACV,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SAC1C,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAqB;QAC/B,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,SAAS;KACjB,CAAC;IAEF,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,CAAC,IAAI,GAAG;YACZ,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAI,MAAoB;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC"}