kiroo 0.8.0 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/config.js ADDED
@@ -0,0 +1,109 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { stableJSONStringify } from './deterministic.js';
4
+
5
+ const KIROO_DIR = '.kiroo';
6
+ const CONFIG_FILE = join(KIROO_DIR, 'config.json');
7
+
8
+ const DEFAULT_CONFIG_TEMPLATE = {
9
+ projectName: 'my-api-project',
10
+ baseUrl: '',
11
+ settings: {
12
+ determinism: {
13
+ sortKeys: true
14
+ },
15
+ redaction: {
16
+ enabled: true,
17
+ redactedValue: '<REDACTED>'
18
+ },
19
+ analysis: {
20
+ failOnSeverity: 'none',
21
+ provider: 'groq',
22
+ modelPriority: [
23
+ 'qwen/qwen3-32b',
24
+ 'moonshotai/kimi-k2-instruct-0905',
25
+ 'openai/gpt-oss-20b'
26
+ ],
27
+ maxCompletionTokens: 900
28
+ },
29
+ export: {
30
+ defaultFormat: 'postman'
31
+ },
32
+ ci: {
33
+ failOnSeverity: 'high'
34
+ }
35
+ }
36
+ };
37
+
38
+ function cloneDefaultConfig() {
39
+ return JSON.parse(JSON.stringify(DEFAULT_CONFIG_TEMPLATE));
40
+ }
41
+
42
+ function mergeWithDefaults(defaultObj, currentObj) {
43
+ if (Array.isArray(defaultObj)) {
44
+ if (Array.isArray(currentObj)) return currentObj;
45
+ return [...defaultObj];
46
+ }
47
+
48
+ if (defaultObj && typeof defaultObj === 'object') {
49
+ const merged = {};
50
+ const source = currentObj && typeof currentObj === 'object' ? currentObj : {};
51
+ const keys = new Set([...Object.keys(defaultObj), ...Object.keys(source)]);
52
+
53
+ for (const key of keys) {
54
+ if (key in defaultObj) {
55
+ merged[key] = mergeWithDefaults(defaultObj[key], source[key]);
56
+ } else {
57
+ merged[key] = source[key];
58
+ }
59
+ }
60
+ return merged;
61
+ }
62
+
63
+ return currentObj !== undefined ? currentObj : defaultObj;
64
+ }
65
+
66
+ function ensureConfigFile() {
67
+ if (!existsSync(KIROO_DIR)) {
68
+ mkdirSync(KIROO_DIR);
69
+ }
70
+
71
+ if (!existsSync(CONFIG_FILE)) {
72
+ const initialConfig = {
73
+ ...cloneDefaultConfig(),
74
+ createdAt: new Date().toISOString()
75
+ };
76
+ writeFileSync(CONFIG_FILE, stableJSONStringify(initialConfig));
77
+ }
78
+ }
79
+
80
+ export function loadKirooConfig() {
81
+ ensureConfigFile();
82
+
83
+ const raw = readFileSync(CONFIG_FILE, 'utf8');
84
+ const parsed = JSON.parse(raw);
85
+ const defaults = cloneDefaultConfig();
86
+ const normalized = mergeWithDefaults(defaults, parsed);
87
+
88
+ if (!normalized.createdAt) {
89
+ normalized.createdAt = new Date().toISOString();
90
+ }
91
+
92
+ const normalizedRaw = stableJSONStringify(normalized);
93
+ if (normalizedRaw !== raw) {
94
+ writeFileSync(CONFIG_FILE, normalizedRaw);
95
+ }
96
+
97
+ return normalized;
98
+ }
99
+
100
+ export function saveKirooConfig(partialConfig = {}) {
101
+ const current = loadKirooConfig();
102
+ const merged = mergeWithDefaults(current, partialConfig);
103
+ writeFileSync(CONFIG_FILE, stableJSONStringify(merged));
104
+ return merged;
105
+ }
106
+
107
+ export function getDefaultKirooConfig() {
108
+ return cloneDefaultConfig();
109
+ }
@@ -0,0 +1,22 @@
1
+ function sortObjectKeysDeep(value) {
2
+ if (Array.isArray(value)) {
3
+ return value.map((item) => sortObjectKeysDeep(item));
4
+ }
5
+
6
+ if (value && typeof value === 'object') {
7
+ const sorted = {};
8
+ const keys = Object.keys(value).sort((a, b) => a.localeCompare(b));
9
+ for (const key of keys) {
10
+ sorted[key] = sortObjectKeysDeep(value[key]);
11
+ }
12
+ return sorted;
13
+ }
14
+
15
+ return value;
16
+ }
17
+
18
+ export function stableJSONStringify(value, space = 2) {
19
+ return JSON.stringify(sortObjectKeysDeep(value), null, space);
20
+ }
21
+
22
+ export { sortObjectKeysDeep };
package/src/env.js CHANGED
@@ -1,6 +1,33 @@
1
1
  import chalk from 'chalk';
2
2
  import Table from 'cli-table3';
3
3
  import { loadEnv, saveEnv } from './storage.js';
4
+ import { isSensitiveKey } from './sanitizer.js';
5
+
6
+ function maskEnvValue(key, value) {
7
+ if (!isSensitiveKey(key)) {
8
+ return String(value);
9
+ }
10
+
11
+ const raw = String(value || '');
12
+ if (raw.length <= 4) {
13
+ return '<REDACTED>';
14
+ }
15
+ return `${raw.slice(0, 2)}***${raw.slice(-2)}`;
16
+ }
17
+
18
+ export function getCurrentEnvVars() {
19
+ const env = loadEnv();
20
+ if (!env.environments[env.current]) {
21
+ env.environments[env.current] = {};
22
+ saveEnv(env);
23
+ }
24
+ return env.environments[env.current];
25
+ }
26
+
27
+ export function getEnvVar(key) {
28
+ const vars = getCurrentEnvVars();
29
+ return vars[key];
30
+ }
4
31
 
5
32
  export function listEnv() {
6
33
  const env = loadEnv();
@@ -19,8 +46,8 @@ export function listEnv() {
19
46
  colWidths: [20, 40]
20
47
  });
21
48
 
22
- Object.entries(currentVars).forEach(([k, v]) => {
23
- table.push([chalk.white(k), chalk.gray(String(v))]);
49
+ Object.entries(currentVars).sort(([a], [b]) => a.localeCompare(b)).forEach(([k, v]) => {
50
+ table.push([chalk.white(k), chalk.gray(maskEnvValue(k, v))]);
24
51
  });
25
52
  console.log(table.toString());
26
53
  } else {
@@ -49,7 +76,8 @@ export function setVar(key, value) {
49
76
  const env = loadEnv();
50
77
  env.environments[env.current][key] = value;
51
78
  saveEnv(env);
52
- console.log(chalk.green(` ✅ Set ${key}=${value} in`), chalk.white(env.current));
79
+ const printValue = isSensitiveKey(key) ? '<REDACTED>' : value;
80
+ console.log(chalk.green(` ✅ Set ${key}=${printValue} in`), chalk.white(env.current));
53
81
  }
54
82
 
55
83
  export function deleteVar(key) {
package/src/executor.js CHANGED
@@ -177,7 +177,7 @@ export async function executeRequest(method, url, options = {}) {
177
177
  spinner.succeed(chalk.green(`${response.status} ${response.statusText}`) + chalk.gray(` (${duration}ms)`));
178
178
 
179
179
  // Format and display response
180
- console.log(formatResponse(response));
180
+ console.log(await formatResponse(response, options.lang));
181
181
 
182
182
  // Handle --save option
183
183
  if (options.save) {
@@ -230,6 +230,23 @@ export async function executeRequest(method, url, options = {}) {
230
230
  console.error(chalk.red('\n ✗ Error:'), error.message, '\n');
231
231
  }
232
232
 
233
+ // Save failed interaction
234
+ await saveInteraction({
235
+ method,
236
+ url,
237
+ headers,
238
+ body,
239
+ response: {
240
+ status: 0,
241
+ statusText: error.code || 'FAILED',
242
+ headers: {},
243
+ data: { error: error.message, code: error.code }
244
+ },
245
+ duration,
246
+ saves: [],
247
+ uses: Array.from(usedKeys)
248
+ });
249
+
233
250
  process.exit(1);
234
251
  }
235
252
  }