pm-orchestrator-runner 1.0.4 → 1.0.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.
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /**
3
+ * Recovery Executor for E2E Recovery Testing
4
+ *
5
+ * Purpose: Simulate TIMEOUT, BLOCKED, and FAIL_CLOSED scenarios
6
+ * to verify wrapper recovery behavior.
7
+ *
8
+ * ========================================
9
+ * SAFETY: TEST-ONLY COMPONENT
10
+ * ========================================
11
+ * This executor is designed ONLY for E2E testing.
12
+ * Production safety mechanisms:
13
+ * 1. Requires explicit PM_EXECUTOR_MODE=recovery-stub
14
+ * 2. Rejects activation when NODE_ENV=production
15
+ * 3. Prints warning to stdout on activation
16
+ * 4. All output contains mode=recovery-stub marker
17
+ *
18
+ * Activation:
19
+ * PM_EXECUTOR_MODE=recovery-stub
20
+ * PM_RECOVERY_SCENARIO=timeout|blocked|fail-closed
21
+ *
22
+ * Behaviors:
23
+ * TIMEOUT: Block indefinitely until watchdog kills (hard timeout)
24
+ * BLOCKED: Return output with interactive prompt patterns
25
+ * FAIL_CLOSED: Return ERROR status immediately
26
+ *
27
+ * E2E Verification Criteria:
28
+ * - Wrapper must recover from all scenarios
29
+ * - Exit code must be 0, 1, or 2 (graceful termination)
30
+ * - Immediate Summary must be visible (RESULT/TASK/HINT)
31
+ * - No RUNNING residue in session state
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.RecoveryExecutor = void 0;
35
+ exports.isProductionEnvironment = isProductionEnvironment;
36
+ exports.isRecoveryMode = isRecoveryMode;
37
+ exports.assertRecoveryModeAllowed = assertRecoveryModeAllowed;
38
+ exports.printRecoveryModeWarning = printRecoveryModeWarning;
39
+ exports.getRecoveryScenario = getRecoveryScenario;
40
+ exports.createRecoveryExecutor = createRecoveryExecutor;
41
+ /**
42
+ * Check if running in production environment
43
+ */
44
+ function isProductionEnvironment() {
45
+ return process.env.NODE_ENV === 'production';
46
+ }
47
+ /**
48
+ * Check if recovery mode is enabled
49
+ *
50
+ * SAFETY: Returns false if NODE_ENV=production
51
+ */
52
+ function isRecoveryMode() {
53
+ // Production safety: reject recovery-stub in production
54
+ if (isProductionEnvironment()) {
55
+ return false;
56
+ }
57
+ return process.env.PM_EXECUTOR_MODE === 'recovery-stub';
58
+ }
59
+ /**
60
+ * Attempt to enable recovery mode in production
61
+ * This will fail-closed with process.exit(1) if attempted
62
+ *
63
+ * Call this early in the process to catch production misuse
64
+ */
65
+ function assertRecoveryModeAllowed() {
66
+ if (process.env.PM_EXECUTOR_MODE === 'recovery-stub' && isProductionEnvironment()) {
67
+ console.error('[FATAL] recovery-stub is forbidden in production (NODE_ENV=production)');
68
+ console.error('[FATAL] mode=recovery-stub rejected');
69
+ process.exit(1);
70
+ }
71
+ }
72
+ /**
73
+ * Print warning when recovery mode is activated
74
+ * This MUST be visible in stdout for E2E verification
75
+ */
76
+ function printRecoveryModeWarning() {
77
+ console.log('WARNING: recovery-stub enabled (test-only)');
78
+ console.log('mode=recovery-stub');
79
+ }
80
+ /**
81
+ * Get the current recovery scenario
82
+ */
83
+ function getRecoveryScenario() {
84
+ const scenario = process.env.PM_RECOVERY_SCENARIO;
85
+ if (scenario === 'timeout' || scenario === 'blocked' || scenario === 'fail-closed') {
86
+ return scenario;
87
+ }
88
+ return null;
89
+ }
90
+ /**
91
+ * RecoveryExecutor - For E2E recovery testing
92
+ *
93
+ * Simulates failure scenarios that require wrapper recovery.
94
+ * Each scenario tests a different recovery path.
95
+ *
96
+ * SAFETY: Constructor prints warning to stdout
97
+ */
98
+ class RecoveryExecutor {
99
+ scenario;
100
+ constructor(scenario) {
101
+ // Print warning on construction (visible in stdout)
102
+ printRecoveryModeWarning();
103
+ this.scenario = scenario || getRecoveryScenario() || 'timeout';
104
+ }
105
+ async isClaudeCodeAvailable() {
106
+ // In recovery mode, we simulate Claude Code availability
107
+ return true;
108
+ }
109
+ async execute(task) {
110
+ const startTime = Date.now();
111
+ const cwd = task.workingDir;
112
+ // Evidence marker for E2E verification
113
+ console.log(`[RecoveryExecutor] mode=recovery-stub`);
114
+ console.log(`[RecoveryExecutor] Scenario: ${this.scenario}, task: ${task.id}`);
115
+ switch (this.scenario) {
116
+ case 'timeout':
117
+ return this.simulateTimeout(task, startTime, cwd);
118
+ case 'blocked':
119
+ return this.simulateBlocked(task, startTime, cwd);
120
+ case 'fail-closed':
121
+ return this.simulateFailClosed(task, startTime, cwd);
122
+ default:
123
+ // Should never happen, but fail-closed for safety
124
+ return this.simulateFailClosed(task, startTime, cwd);
125
+ }
126
+ }
127
+ /**
128
+ * TIMEOUT scenario:
129
+ * Block for a long time to trigger hard timeout in the wrapper.
130
+ * The wrapper should detect no output and terminate.
131
+ */
132
+ async simulateTimeout(task, startTime, cwd) {
133
+ console.log('[RecoveryExecutor] Simulating TIMEOUT - blocking for extended period');
134
+ // Block for a very long time (the wrapper should kill us before this completes)
135
+ // Using a reasonable time that exceeds hard timeout (default 120s)
136
+ // For testing, we use a shorter time but longer than the test's configured timeout
137
+ const blockDuration = parseInt(process.env.RECOVERY_TIMEOUT_BLOCK_MS || '150000', 10);
138
+ await new Promise((resolve) => {
139
+ const timeout = setTimeout(resolve, blockDuration);
140
+ // Allow the timeout to be unrefd so the process can be killed
141
+ timeout.unref();
142
+ });
143
+ // If we reach here, the wrapper failed to terminate us (test failure case)
144
+ return {
145
+ executed: false,
146
+ output: '',
147
+ error: 'TIMEOUT simulation - wrapper failed to terminate',
148
+ files_modified: [],
149
+ duration_ms: Date.now() - startTime,
150
+ status: 'ERROR',
151
+ cwd,
152
+ verified_files: [],
153
+ unverified_files: [],
154
+ executor_blocked: true,
155
+ blocked_reason: 'TIMEOUT',
156
+ timeout_ms: Date.now() - startTime,
157
+ terminated_by: 'TIMEOUT',
158
+ };
159
+ }
160
+ /**
161
+ * BLOCKED scenario:
162
+ * Return output containing interactive prompt patterns.
163
+ * The wrapper should detect BLOCKED status and recover.
164
+ */
165
+ async simulateBlocked(task, startTime, cwd) {
166
+ console.log('[RecoveryExecutor] Simulating BLOCKED - returning interactive prompt output');
167
+ // Small delay to simulate some processing
168
+ await new Promise((resolve) => setTimeout(resolve, 100));
169
+ // Return result indicating blocked status
170
+ // This simulates what happens when Claude Code CLI hits an interactive prompt
171
+ return {
172
+ executed: false,
173
+ output: 'Would you like to continue? [Y/n]',
174
+ error: 'Executor blocked: INTERACTIVE_PROMPT',
175
+ files_modified: [],
176
+ duration_ms: Date.now() - startTime,
177
+ status: 'BLOCKED',
178
+ cwd,
179
+ verified_files: [],
180
+ unverified_files: [],
181
+ executor_blocked: true,
182
+ blocked_reason: 'INTERACTIVE_PROMPT',
183
+ timeout_ms: Date.now() - startTime,
184
+ terminated_by: 'REPL_FAIL_CLOSED',
185
+ };
186
+ }
187
+ /**
188
+ * FAIL_CLOSED scenario:
189
+ * Return ERROR status immediately.
190
+ * Simulates executor crash or unexpected termination.
191
+ */
192
+ async simulateFailClosed(task, startTime, cwd) {
193
+ console.log('[RecoveryExecutor] Simulating FAIL_CLOSED - returning error immediately');
194
+ // Small delay to simulate some processing
195
+ await new Promise((resolve) => setTimeout(resolve, 50));
196
+ // Return error result (simulates non-zero exit code)
197
+ return {
198
+ executed: false,
199
+ output: 'Fatal error: simulated crash',
200
+ error: 'Executor terminated unexpectedly (simulated FAIL_CLOSED)',
201
+ files_modified: [],
202
+ duration_ms: Date.now() - startTime,
203
+ status: 'ERROR',
204
+ cwd,
205
+ verified_files: [],
206
+ unverified_files: [],
207
+ executor_blocked: false,
208
+ };
209
+ }
210
+ }
211
+ exports.RecoveryExecutor = RecoveryExecutor;
212
+ /**
213
+ * Create recovery executor if in recovery mode
214
+ *
215
+ * SAFETY: Calls assertRecoveryModeAllowed() to reject production usage
216
+ */
217
+ function createRecoveryExecutor() {
218
+ // Early fail-closed for production misuse
219
+ assertRecoveryModeAllowed();
220
+ if (isRecoveryMode()) {
221
+ const scenario = getRecoveryScenario();
222
+ if (scenario) {
223
+ return new RecoveryExecutor(scenario);
224
+ }
225
+ }
226
+ return null;
227
+ }
228
+ //# sourceMappingURL=recovery-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-executor.js","sourceRoot":"","sources":["../../src/executor/recovery-executor.ts"],"names":[],"mappings":"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"}
@@ -3,11 +3,14 @@
3
3
  *
4
4
  * Per spec 10_REPL_UX.md Section 2.3:
5
5
  * - /keys: show status of all API keys (SET/NOT SET)
6
+ * - /keys set <provider> <key>: set API key in global config
6
7
  * - /keys check: validate API key format
7
8
  *
8
9
  * Per spec 06_CORRECTNESS_PROPERTIES.md Property 24:
9
10
  * - API keys must NEVER appear in logs or evidence
10
11
  * - Only "SET" or "NOT SET" status is allowed
12
+ *
13
+ * API keys are stored in global config file (~/.pm-orchestrator-runner/config.json)
11
14
  */
12
15
  /**
13
16
  * Key status result
@@ -39,9 +42,23 @@ export declare class KeysCommand {
39
42
  * Per spec 06_CORRECTNESS_PROPERTIES.md Property 24:
40
43
  * - Only show SET/NOT SET, never the actual key value
41
44
  *
45
+ * Checks both:
46
+ * - Global config file (~/.pm-orchestrator-runner/config.json)
47
+ * - Environment variables (legacy support)
48
+ *
42
49
  * @returns Keys result
43
50
  */
44
51
  getKeyStatus(): Promise<KeysResult>;
52
+ /**
53
+ * Set API key in global config
54
+ * Per spec 06_CORRECTNESS_PROPERTIES.md Property 24:
55
+ * - API key value is stored but NEVER displayed
56
+ *
57
+ * @param provider - Provider ID (openai or anthropic)
58
+ * @param key - API key value
59
+ * @returns Keys result
60
+ */
61
+ setKey(provider: string, key: string): Promise<KeysResult>;
45
62
  /**
46
63
  * Check if a specific provider's API key is configured
47
64
  *
@@ -1 +1 @@
1
- {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../../src/repl/commands/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,cAAc,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB;;;;;;OAMG;IACG,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC;IAsBzC;;;;;OAKG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAgC/D;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM;CA0B3C"}
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../../src/repl/commands/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAeH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,cAAc,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB;;;;;;;;;;OAUG;IACG,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC;IAoCzC;;;;;;;;OAQG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAyChE;;;;;OAKG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAgC/D;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM;CA+B3C"}
@@ -4,17 +4,21 @@
4
4
  *
5
5
  * Per spec 10_REPL_UX.md Section 2.3:
6
6
  * - /keys: show status of all API keys (SET/NOT SET)
7
+ * - /keys set <provider> <key>: set API key in global config
7
8
  * - /keys check: validate API key format
8
9
  *
9
10
  * Per spec 06_CORRECTNESS_PROPERTIES.md Property 24:
10
11
  * - API keys must NEVER appear in logs or evidence
11
12
  * - Only "SET" or "NOT SET" status is allowed
13
+ *
14
+ * API keys are stored in global config file (~/.pm-orchestrator-runner/config.json)
12
15
  */
13
16
  Object.defineProperty(exports, "__esModule", { value: true });
14
17
  exports.KeysCommand = void 0;
15
18
  const sensitive_data_masker_1 = require("../../logging/sensitive-data-masker");
16
19
  const repl_1 = require("../../models/repl");
17
20
  const model_registry_1 = require("../../models/repl/model-registry");
21
+ const global_config_1 = require("../../config/global-config");
18
22
  /**
19
23
  * Keys Command class
20
24
  */
@@ -24,18 +28,35 @@ class KeysCommand {
24
28
  * Per spec 06_CORRECTNESS_PROPERTIES.md Property 24:
25
29
  * - Only show SET/NOT SET, never the actual key value
26
30
  *
31
+ * Checks both:
32
+ * - Global config file (~/.pm-orchestrator-runner/config.json)
33
+ * - Environment variables (legacy support)
34
+ *
27
35
  * @returns Keys result
28
36
  */
29
37
  async getKeyStatus() {
30
38
  const providers = (0, model_registry_1.getAllProviders)();
31
39
  const keys = [];
32
40
  for (const provider of providers) {
41
+ // Check global config first
42
+ const globalKey = (0, global_config_1.getApiKey)(provider.id);
43
+ // Then check environment variables (legacy)
33
44
  const keyCheck = (0, sensitive_data_masker_1.checkApiKeyForProvider)(provider.id);
45
+ // Use global config if set, otherwise fall back to env var
46
+ const isSet = !!globalKey || keyCheck.status === 'SET';
47
+ // Determine status: NOT_REQUIRED for providers that don't need keys
48
+ let status;
49
+ if (!keyCheck.required) {
50
+ status = 'NOT_REQUIRED';
51
+ }
52
+ else {
53
+ status = isSet ? 'SET' : 'NOT SET';
54
+ }
34
55
  keys.push({
35
56
  provider: provider.displayName,
36
57
  envVar: keyCheck.envVar,
37
58
  required: keyCheck.required,
38
- status: keyCheck.status,
59
+ status,
39
60
  });
40
61
  }
41
62
  return {
@@ -44,6 +65,52 @@ class KeysCommand {
44
65
  keys,
45
66
  };
46
67
  }
68
+ /**
69
+ * Set API key in global config
70
+ * Per spec 06_CORRECTNESS_PROPERTIES.md Property 24:
71
+ * - API key value is stored but NEVER displayed
72
+ *
73
+ * @param provider - Provider ID (openai or anthropic)
74
+ * @param key - API key value
75
+ * @returns Keys result
76
+ */
77
+ async setKey(provider, key) {
78
+ // Validate provider
79
+ const validProviders = ['openai', 'anthropic'];
80
+ if (!validProviders.includes(provider.toLowerCase())) {
81
+ return {
82
+ success: false,
83
+ message: 'Invalid provider',
84
+ error: {
85
+ code: 'E102',
86
+ message: 'Invalid provider: ' + provider + '. Valid providers: openai, anthropic',
87
+ },
88
+ };
89
+ }
90
+ // Validate key format
91
+ if (!key || key.length < 10) {
92
+ return {
93
+ success: false,
94
+ message: 'Invalid API key',
95
+ error: {
96
+ code: 'E108',
97
+ message: 'API key appears to be invalid (too short)',
98
+ },
99
+ };
100
+ }
101
+ // Set the key in global config
102
+ (0, global_config_1.setApiKey)(provider.toLowerCase(), key);
103
+ return {
104
+ success: true,
105
+ message: 'API key set successfully for ' + provider,
106
+ keys: [{
107
+ provider: provider,
108
+ envVar: null,
109
+ required: true,
110
+ status: 'SET',
111
+ }],
112
+ };
113
+ }
47
114
  /**
48
115
  * Check if a specific provider's API key is configured
49
116
  *
@@ -97,14 +164,18 @@ class KeysCommand {
97
164
  else {
98
165
  const statusIcon = key.status === 'SET' ? '[OK]' : '[MISSING]';
99
166
  output += ' Status: ' + statusIcon + ' ' + key.status + '\n';
100
- output += ' Env Var: ' + key.envVar + '\n';
167
+ if (key.envVar) {
168
+ output += ' Legacy Env Var: ' + key.envVar + '\n';
169
+ }
101
170
  }
102
171
  output += '\n';
103
172
  }
173
+ // Add config file info
174
+ output += 'Config file: ' + (0, global_config_1.getConfigFilePath)() + '\n\n';
104
175
  // Add help text
105
- output += 'To set an API key, export the environment variable:\n';
106
- output += ' export OPENAI_API_KEY=sk-...\n';
107
- output += ' export ANTHROPIC_API_KEY=sk-ant-...\n';
176
+ output += 'To set an API key:\n';
177
+ output += ' /keys set openai <your-api-key>\n';
178
+ output += ' /keys set anthropic <your-api-key>\n';
108
179
  output += '\n';
109
180
  output += 'Note: API keys are NEVER displayed for security reasons.';
110
181
  return output;
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../src/repl/commands/keys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../src/repl/commands/keys.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,22 @@
1
1
  /**
2
2
  * Status Commands Handler
3
3
  * Manages /status and /tasks commands
4
+ *
5
+ * UX Improvements (v2):
6
+ * - Tasks are categorized into Active/Completed/Failed/Pending sections
7
+ * - ERROR tasks no longer shown as "Current Tasks"
8
+ * - Human-readable error messages with guidance
9
+ * - Alert banners for failed tasks
4
10
  */
5
11
  import { RunnerCore } from '../../core/runner-core';
12
+ /**
13
+ * Translate technical error messages to human-readable form
14
+ */
15
+ export declare function getHumanReadableError(errorMessage: string): string;
16
+ /**
17
+ * Get guidance for specific error types
18
+ */
19
+ export declare function getErrorGuidance(status: string): string[];
6
20
  /**
7
21
  * REPL session state (shared with repl-interface)
8
22
  */
@@ -24,9 +38,13 @@ export declare class StatusCommands {
24
38
  */
25
39
  getStatus(): Promise<string>;
26
40
  /**
27
- * Get current tasks
41
+ * Get current tasks - with improved categorization
28
42
  */
29
43
  getTasks(): Promise<string>;
44
+ /**
45
+ * Categorize tasks by status
46
+ */
47
+ private categorizeTasks;
30
48
  /**
31
49
  * Format no session message
32
50
  */
@@ -44,9 +62,9 @@ export declare class StatusCommands {
44
62
  */
45
63
  private formatStatus;
46
64
  /**
47
- * Format tasks list
65
+ * Format tasks list - IMPROVED with categorization and guidance
48
66
  */
49
- private formatTasks;
67
+ private formatTasksImproved;
50
68
  /**
51
69
  * Get status icon
52
70
  */
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/repl/commands/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAWpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,GAAG,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;CACvC;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAc;gBAEjB,OAAO,EAAE,WAAW;IAIhC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAwBlC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAsBjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAoCnB;;OAEG;IACH,OAAO,CAAC,aAAa;CActB"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/repl/commands/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAWpD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAqBlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAqCzD;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,GAAG,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;CACvC;AAYD;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAc;gBAEjB,OAAO,EAAE,WAAW;IAIhC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAwBlC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAsBjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAiCvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;IACH,OAAO,CAAC,YAAY;IA4BpB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkF3B;;OAEG;IACH,OAAO,CAAC,aAAa;CActB"}