prompt-language-shell 0.8.2 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/configuration/io.js +85 -0
  2. package/dist/configuration/messages.js +30 -0
  3. package/dist/configuration/schema.js +167 -0
  4. package/dist/configuration/transformation.js +55 -0
  5. package/dist/configuration/types.js +30 -0
  6. package/dist/configuration/validation.js +52 -0
  7. package/dist/execution/handlers.js +135 -0
  8. package/dist/execution/processing.js +35 -0
  9. package/dist/execution/reducer.js +148 -0
  10. package/dist/execution/types.js +12 -0
  11. package/dist/execution/validation.js +12 -0
  12. package/dist/index.js +1 -1
  13. package/dist/services/anthropic.js +43 -56
  14. package/dist/services/colors.js +2 -1
  15. package/dist/services/components.js +40 -24
  16. package/dist/services/config-labels.js +15 -15
  17. package/dist/services/filesystem.js +114 -0
  18. package/dist/services/loader.js +8 -5
  19. package/dist/services/logger.js +26 -1
  20. package/dist/services/messages.js +32 -1
  21. package/dist/services/parser.js +3 -1
  22. package/dist/services/refinement.js +10 -10
  23. package/dist/services/router.js +43 -27
  24. package/dist/services/skills.js +12 -11
  25. package/dist/services/validator.js +4 -3
  26. package/dist/types/guards.js +4 -6
  27. package/dist/types/handlers.js +1 -0
  28. package/dist/types/schemas.js +103 -0
  29. package/dist/types/types.js +1 -0
  30. package/dist/ui/Answer.js +38 -16
  31. package/dist/ui/Command.js +48 -22
  32. package/dist/ui/Component.js +147 -33
  33. package/dist/ui/Config.js +69 -78
  34. package/dist/ui/Confirm.js +34 -21
  35. package/dist/ui/Execute.js +151 -178
  36. package/dist/ui/Feedback.js +1 -0
  37. package/dist/ui/Introspect.js +54 -25
  38. package/dist/ui/Label.js +1 -1
  39. package/dist/ui/Main.js +10 -6
  40. package/dist/ui/Refinement.js +8 -1
  41. package/dist/ui/Schedule.js +76 -53
  42. package/dist/ui/Validate.js +77 -77
  43. package/dist/ui/Workflow.js +60 -61
  44. package/package.json +3 -2
  45. package/dist/services/configuration.js +0 -409
@@ -1,409 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'fs';
2
- import { homedir } from 'os';
3
- import { join } from 'path';
4
- import YAML from 'yaml';
5
- import { getConfigLabel } from './config-labels.js';
6
- import { flattenConfig } from './config-utils.js';
7
- /**
8
- * Convert a dotted config key to a readable label
9
- * Example: "project.alpha.repo" -> "Project Alpha Repo"
10
- */
11
- function keyToLabel(key) {
12
- return key
13
- .split('.')
14
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
15
- .join(' ');
16
- }
17
- export var AnthropicModel;
18
- (function (AnthropicModel) {
19
- AnthropicModel["Sonnet"] = "claude-sonnet-4-5";
20
- AnthropicModel["Haiku"] = "claude-haiku-4-5";
21
- AnthropicModel["Opus"] = "claude-opus-4-1";
22
- })(AnthropicModel || (AnthropicModel = {}));
23
- export const SUPPORTED_MODELS = Object.values(AnthropicModel);
24
- export var DebugLevel;
25
- (function (DebugLevel) {
26
- DebugLevel["None"] = "none";
27
- DebugLevel["Info"] = "info";
28
- DebugLevel["Verbose"] = "verbose";
29
- })(DebugLevel || (DebugLevel = {}));
30
- export const SUPPORTED_DEBUG_LEVELS = Object.values(DebugLevel);
31
- export var ConfigDefinitionType;
32
- (function (ConfigDefinitionType) {
33
- ConfigDefinitionType["RegExp"] = "regexp";
34
- ConfigDefinitionType["String"] = "string";
35
- ConfigDefinitionType["Enum"] = "enum";
36
- ConfigDefinitionType["Number"] = "number";
37
- ConfigDefinitionType["Boolean"] = "boolean";
38
- })(ConfigDefinitionType || (ConfigDefinitionType = {}));
39
- export class ConfigError extends Error {
40
- origin;
41
- constructor(message, origin) {
42
- super(message);
43
- this.name = 'ConfigError';
44
- this.origin = origin;
45
- }
46
- }
47
- function getConfigFile() {
48
- return join(homedir(), '.plsrc');
49
- }
50
- function parseYamlConfig(content) {
51
- try {
52
- return YAML.parse(content);
53
- }
54
- catch (error) {
55
- throw new ConfigError('Failed to parse configuration file', error instanceof Error ? error : undefined);
56
- }
57
- }
58
- function validateConfig(parsed) {
59
- if (!parsed || typeof parsed !== 'object') {
60
- throw new ConfigError('Invalid configuration format');
61
- }
62
- const config = parsed;
63
- // Validate anthropic section
64
- if (!config.anthropic || typeof config.anthropic !== 'object') {
65
- throw new ConfigError('Missing or invalid anthropic configuration');
66
- }
67
- const { key, model } = config.anthropic;
68
- if (!key || typeof key !== 'string') {
69
- throw new ConfigError('Missing or invalid API key');
70
- }
71
- const validatedConfig = {
72
- anthropic: {
73
- key,
74
- },
75
- };
76
- // Optional model - only set if valid
77
- if (model && typeof model === 'string' && isValidAnthropicModel(model)) {
78
- validatedConfig.anthropic.model = model;
79
- }
80
- // Optional settings section
81
- if (config.settings && typeof config.settings === 'object') {
82
- const settings = config.settings;
83
- validatedConfig.settings = {};
84
- if ('debug' in settings) {
85
- // Handle migration from boolean to enum
86
- if (typeof settings.debug === 'boolean') {
87
- validatedConfig.settings.debug = settings.debug
88
- ? DebugLevel.Info
89
- : DebugLevel.None;
90
- }
91
- else if (typeof settings.debug === 'string' &&
92
- SUPPORTED_DEBUG_LEVELS.includes(settings.debug)) {
93
- validatedConfig.settings.debug = settings.debug;
94
- }
95
- }
96
- }
97
- return validatedConfig;
98
- }
99
- export function loadConfig() {
100
- const configFile = getConfigFile();
101
- if (!existsSync(configFile)) {
102
- throw new ConfigError('Configuration not found');
103
- }
104
- const content = readFileSync(configFile, 'utf-8');
105
- const parsed = parseYamlConfig(content);
106
- return validateConfig(parsed);
107
- }
108
- export function getConfigPath() {
109
- return getConfigFile();
110
- }
111
- export function configExists() {
112
- return existsSync(getConfigFile());
113
- }
114
- export function isValidAnthropicApiKey(key) {
115
- // Anthropic API keys format: sk-ant-api03-XXXXX (108 chars total)
116
- // - Prefix: sk-ant-api03- (13 chars)
117
- // - Key body: 95 characters (uppercase, lowercase, digits, hyphens, underscores)
118
- const apiKeyPattern = /^sk-ant-api03-[A-Za-z0-9_-]{95}$/;
119
- return apiKeyPattern.test(key);
120
- }
121
- export function isValidAnthropicModel(model) {
122
- return SUPPORTED_MODELS.includes(model);
123
- }
124
- export function hasValidAnthropicKey() {
125
- try {
126
- const config = loadConfig();
127
- return (!!config.anthropic.key && isValidAnthropicApiKey(config.anthropic.key));
128
- }
129
- catch {
130
- return false;
131
- }
132
- }
133
- export function mergeConfig(existingContent, sectionName, newValues) {
134
- const parsed = existingContent.trim()
135
- ? YAML.parse(existingContent)
136
- : {};
137
- // Update or add section
138
- const section = parsed[sectionName] ?? {};
139
- for (const [key, value] of Object.entries(newValues)) {
140
- section[key] = value;
141
- }
142
- parsed[sectionName] = section;
143
- // Sort sections alphabetically
144
- const sortedKeys = Object.keys(parsed).sort();
145
- const sortedConfig = {};
146
- for (const key of sortedKeys) {
147
- sortedConfig[key] = parsed[key];
148
- }
149
- // Convert back to YAML
150
- return YAML.stringify(sortedConfig);
151
- }
152
- export function saveConfig(section, config) {
153
- const configFile = getConfigFile();
154
- const existingContent = existsSync(configFile)
155
- ? readFileSync(configFile, 'utf-8')
156
- : '';
157
- const newContent = mergeConfig(existingContent, section, config);
158
- writeFileSync(configFile, newContent, 'utf-8');
159
- }
160
- export function saveAnthropicConfig(config) {
161
- saveConfig('anthropic', config);
162
- return loadConfig();
163
- }
164
- export function saveDebugSetting(debug) {
165
- saveConfig('settings', { debug });
166
- }
167
- export function loadDebugSetting() {
168
- try {
169
- const config = loadConfig();
170
- return config.settings?.debug ?? DebugLevel.None;
171
- }
172
- catch {
173
- return DebugLevel.None;
174
- }
175
- }
176
- /**
177
- * Returns a message requesting initial setup.
178
- * Provides natural language variations that sound like a professional concierge
179
- * preparing to serve, avoiding technical jargon.
180
- *
181
- * @param forFutureUse - If true, indicates setup is for future requests rather than
182
- * an immediate task
183
- */
184
- export function getConfigurationRequiredMessage(forFutureUse = false) {
185
- if (forFutureUse) {
186
- const messages = [
187
- "Before I can assist with your requests, let's get a few things ready.",
188
- 'Let me set up a few things so I can help you in the future.',
189
- "I'll need to prepare a few things before I can assist you.",
190
- "Let's get everything ready so I can help with your tasks.",
191
- "I need to set up a few things first, then I'll be ready to assist.",
192
- 'Let me prepare everything so I can help you going forward.',
193
- ];
194
- return messages[Math.floor(Math.random() * messages.length)];
195
- }
196
- const messages = [
197
- 'Before I can help, let me get a few things ready.',
198
- 'I need to set up a few things first.',
199
- 'Let me prepare everything before we begin.',
200
- 'Just a moment while I get ready to assist you.',
201
- "I'll need to get set up before I can help with that.",
202
- 'Let me get everything ready for you.',
203
- ];
204
- return messages[Math.floor(Math.random() * messages.length)];
205
- }
206
- /**
207
- * Core configuration schema - defines structure and types for system settings
208
- */
209
- const coreConfigSchema = {
210
- 'anthropic.key': {
211
- type: ConfigDefinitionType.RegExp,
212
- required: true,
213
- pattern: /^sk-ant-api03-[A-Za-z0-9_-]{95}$/,
214
- description: 'Anthropic API key',
215
- },
216
- 'anthropic.model': {
217
- type: ConfigDefinitionType.Enum,
218
- required: true,
219
- values: SUPPORTED_MODELS,
220
- default: AnthropicModel.Haiku,
221
- description: 'Anthropic model',
222
- },
223
- 'settings.debug': {
224
- type: ConfigDefinitionType.Enum,
225
- required: false,
226
- values: SUPPORTED_DEBUG_LEVELS,
227
- default: DebugLevel.None,
228
- description: 'Debug mode',
229
- },
230
- };
231
- /**
232
- * Get complete configuration schema
233
- * Currently returns core schema only
234
- * Future: will merge with skill-declared schemas
235
- */
236
- export function getConfigSchema() {
237
- return {
238
- ...coreConfigSchema,
239
- // Future: ...loadSkillSchemas()
240
- };
241
- }
242
- /**
243
- * Get missing required configuration keys
244
- * Returns array of keys that are required but not present or invalid in config
245
- */
246
- export function getMissingConfigKeys() {
247
- const schema = getConfigSchema();
248
- const missing = [];
249
- let currentConfig = null;
250
- try {
251
- currentConfig = loadConfig();
252
- }
253
- catch {
254
- // Config doesn't exist
255
- }
256
- for (const [key, definition] of Object.entries(schema)) {
257
- if (!definition.required) {
258
- continue;
259
- }
260
- // Get current value for this key
261
- const parts = key.split('.');
262
- let value = currentConfig;
263
- for (const part of parts) {
264
- if (value && typeof value === 'object' && part in value) {
265
- value = value[part];
266
- }
267
- else {
268
- value = undefined;
269
- break;
270
- }
271
- }
272
- // Check if value is missing or invalid
273
- if (value === undefined || value === null) {
274
- missing.push(key);
275
- continue;
276
- }
277
- // Validate based on type
278
- let isValid = false;
279
- switch (definition.type) {
280
- case ConfigDefinitionType.RegExp:
281
- isValid = typeof value === 'string' && definition.pattern.test(value);
282
- break;
283
- case ConfigDefinitionType.String:
284
- isValid = typeof value === 'string';
285
- break;
286
- case ConfigDefinitionType.Enum:
287
- isValid =
288
- typeof value === 'string' && definition.values.includes(value);
289
- break;
290
- case ConfigDefinitionType.Number:
291
- isValid = typeof value === 'number';
292
- break;
293
- case ConfigDefinitionType.Boolean:
294
- isValid = typeof value === 'boolean';
295
- break;
296
- }
297
- if (!isValid) {
298
- missing.push(key);
299
- }
300
- }
301
- return missing;
302
- }
303
- /**
304
- * Get list of configured keys from config file
305
- * Returns array of dot-notation keys that exist in the config file
306
- */
307
- export function getConfiguredKeys() {
308
- try {
309
- const configFile = getConfigFile();
310
- if (!existsSync(configFile)) {
311
- return [];
312
- }
313
- const content = readFileSync(configFile, 'utf-8');
314
- const parsed = YAML.parse(content);
315
- // Flatten nested config to dot notation
316
- const flatConfig = flattenConfig(parsed);
317
- return Object.keys(flatConfig);
318
- }
319
- catch {
320
- return [];
321
- }
322
- }
323
- /**
324
- * Get available config structure for CONFIG tool
325
- * Returns keys with descriptions only (no values for privacy)
326
- * Marks optional keys as "(optional)"
327
- */
328
- export function getAvailableConfigStructure() {
329
- const schema = getConfigSchema();
330
- const structure = {};
331
- // Try to load existing config to see which keys are already set
332
- let flatConfig = {};
333
- try {
334
- const configFile = getConfigFile();
335
- if (existsSync(configFile)) {
336
- const content = readFileSync(configFile, 'utf-8');
337
- const parsed = YAML.parse(content);
338
- // Flatten nested config to dot notation
339
- flatConfig = flattenConfig(parsed);
340
- }
341
- }
342
- catch {
343
- // Config file doesn't exist or can't be read
344
- }
345
- // Add schema keys with descriptions
346
- for (const [key, definition] of Object.entries(schema)) {
347
- structure[key] = definition.description;
348
- }
349
- // Add discovered keys that aren't in schema
350
- for (const key of Object.keys(flatConfig)) {
351
- if (!(key in structure)) {
352
- structure[key] = getConfigLabel(key) || keyToLabel(key);
353
- }
354
- }
355
- return structure;
356
- }
357
- /**
358
- * Convert string value to appropriate type based on schema definition
359
- */
360
- function parseConfigValue(key, stringValue, schema) {
361
- // If we have a schema definition, use its type
362
- if (key in schema) {
363
- const definition = schema[key];
364
- switch (definition.type) {
365
- case ConfigDefinitionType.Boolean:
366
- return stringValue === 'true';
367
- case ConfigDefinitionType.Number:
368
- return Number(stringValue);
369
- case ConfigDefinitionType.String:
370
- case ConfigDefinitionType.RegExp:
371
- case ConfigDefinitionType.Enum:
372
- return stringValue;
373
- }
374
- }
375
- // No schema definition - try to infer type from string value
376
- // This handles skill-defined configs that may not be in schema yet
377
- if (stringValue === 'true' || stringValue === 'false') {
378
- return stringValue === 'true';
379
- }
380
- if (!isNaN(Number(stringValue)) && stringValue.trim() !== '') {
381
- return Number(stringValue);
382
- }
383
- return stringValue;
384
- }
385
- /**
386
- * Unflatten dotted keys into nested structure
387
- * Example: { "product.alpha.path": "value" } -> { product: { alpha: { path: "value" } } }
388
- * Converts string values to appropriate types based on config schema
389
- */
390
- export function unflattenConfig(dotted) {
391
- const result = {};
392
- const schema = getConfigSchema();
393
- for (const [dottedKey, stringValue] of Object.entries(dotted)) {
394
- const parts = dottedKey.split('.');
395
- const section = parts[0];
396
- // Initialize section if needed
397
- result[section] = result[section] ?? {};
398
- // Build nested structure for this section
399
- let current = result[section];
400
- for (let i = 1; i < parts.length - 1; i++) {
401
- current[parts[i]] = current[parts[i]] ?? {};
402
- current = current[parts[i]];
403
- }
404
- // Convert string value to appropriate type and set
405
- const typedValue = parseConfigValue(dottedKey, stringValue, schema);
406
- current[parts[parts.length - 1]] = typedValue;
407
- }
408
- return result;
409
- }