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.
- package/dist/config/global-config.d.ts +69 -0
- package/dist/config/global-config.d.ts.map +1 -0
- package/dist/config/global-config.js +168 -0
- package/dist/config/global-config.js.map +1 -0
- package/dist/core/runner-core.d.ts.map +1 -1
- package/dist/core/runner-core.js +6 -0
- package/dist/core/runner-core.js.map +1 -1
- package/dist/executor/recovery-executor.d.ts +101 -0
- package/dist/executor/recovery-executor.d.ts.map +1 -0
- package/dist/executor/recovery-executor.js +228 -0
- package/dist/executor/recovery-executor.js.map +1 -0
- package/dist/repl/commands/keys.d.ts +17 -0
- package/dist/repl/commands/keys.d.ts.map +1 -1
- package/dist/repl/commands/keys.js +76 -5
- package/dist/repl/commands/keys.js.map +1 -1
- package/dist/repl/commands/status.d.ts +21 -3
- package/dist/repl/commands/status.d.ts.map +1 -1
- package/dist/repl/commands/status.js +205 -60
- package/dist/repl/commands/status.js.map +1 -1
- package/dist/repl/repl-interface.d.ts +63 -1
- package/dist/repl/repl-interface.d.ts.map +1 -1
- package/dist/repl/repl-interface.js +252 -11
- package/dist/repl/repl-interface.js.map +1 -1
- package/package.json +4 -2
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|
106
|
-
output += '
|
|
107
|
-
output += '
|
|
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":";AAAA
|
|
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
|
|
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
|
|
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"}
|