@ottocode/sdk 0.1.237 → 0.1.242

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.
@@ -5,6 +5,7 @@ const OAUTH_MODEL_PREFIXES: Partial<Record<ProviderId, string[]>> = {
5
5
  'claude-haiku-4-5',
6
6
  'claude-opus-4-5',
7
7
  'claude-opus-4-6',
8
+ 'claude-opus-4-7',
8
9
  'claude-sonnet-4-5',
9
10
  'claude-sonnet-4-6',
10
11
  ],
@@ -19,6 +20,7 @@ const OAUTH_MODEL_IDS: Partial<Record<ProviderId, string[]>> = {
19
20
  'gpt-5.2-codex',
20
21
  'gpt-5.3-codex',
21
22
  'gpt-5.4',
23
+ 'gpt-5.4-mini',
22
24
  ],
23
25
  };
24
26
 
@@ -40,7 +40,7 @@ const PREFERRED_FAST_MODELS: Partial<Record<ProviderId, string[]>> = {
40
40
  };
41
41
 
42
42
  const PREFERRED_FAST_MODELS_OAUTH: Partial<Record<ProviderId, string[]>> = {
43
- openai: ['gpt-5.1-codex-mini'],
43
+ openai: ['gpt-5.4-mini'],
44
44
  anthropic: ['claude-haiku-4-5'],
45
45
  };
46
46
 
@@ -74,6 +74,7 @@ export async function discoverSkills(
74
74
  let current = cwd;
75
75
  const visited = new Set<string>();
76
76
  while (current && !visited.has(current)) {
77
+ if (repoRoot && !current.startsWith(repoRoot)) break;
77
78
  visited.add(current);
78
79
  const scope: SkillScope =
79
80
  current === cwd ? 'cwd' : current === repoRoot ? 'repo' : 'parent';
@@ -82,7 +83,6 @@ export async function discoverSkills(
82
83
  }
83
84
  const parent = dirname(current);
84
85
  if (parent === current) break;
85
- if (repoRoot && !current.startsWith(repoRoot)) break;
86
86
  current = parent;
87
87
  }
88
88
 
@@ -35,50 +35,219 @@ function parseYamlFrontmatter(
35
35
  ): Record<string, unknown> {
36
36
  const result: Record<string, unknown> = {};
37
37
  const lines = yaml.split('\n');
38
- let currentKey: string | null = null;
39
- let currentIndent = 0;
40
- let nestedObject: Record<string, string> | null = null;
38
+ let index = 0;
41
39
 
42
- for (const line of lines) {
43
- if (!line.trim()) continue;
40
+ while (index < lines.length) {
41
+ const line = lines[index];
42
+ if (!line || !line.trim()) {
43
+ index += 1;
44
+ continue;
45
+ }
44
46
 
45
47
  const indent = line.search(/\S/);
48
+ if (indent > 0) {
49
+ index += 1;
50
+ continue;
51
+ }
52
+
46
53
  const trimmed = line.trim();
54
+ const colonIdx = trimmed.indexOf(':');
55
+ if (colonIdx === -1) {
56
+ index += 1;
57
+ continue;
58
+ }
47
59
 
48
- if (indent === 0 || (indent <= currentIndent && nestedObject)) {
49
- if (nestedObject && currentKey) {
50
- result[currentKey] = nestedObject;
51
- nestedObject = null;
52
- currentKey = null;
53
- }
60
+ const key = normalizeKey(trimmed.slice(0, colonIdx).trim());
61
+ const value = trimmed.slice(colonIdx + 1).trim();
62
+
63
+ if (value === '|' || value === '>') {
64
+ const { content, nextIndex } = readBlockScalar(
65
+ lines,
66
+ index + 1,
67
+ indent,
68
+ value,
69
+ );
70
+ result[key] = content;
71
+ index = nextIndex;
72
+ continue;
73
+ }
74
+
75
+ if (!value) {
76
+ const { content, nextIndex } = readIndentedValue(
77
+ lines,
78
+ index + 1,
79
+ indent,
80
+ );
81
+ result[key] = content;
82
+ index = nextIndex;
83
+ continue;
84
+ }
85
+
86
+ result[key] = parseYamlValue(value);
87
+ index += 1;
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+ function readIndentedValue(
94
+ lines: string[],
95
+ startIndex: number,
96
+ parentIndent: number,
97
+ ): { content: Record<string, string> | string; nextIndex: number } {
98
+ for (let index = startIndex; index < lines.length; index += 1) {
99
+ const line = lines[index];
100
+ if (!line || !line.trim()) continue;
101
+
102
+ const indent = line.search(/\S/);
103
+ if (indent <= parentIndent) {
104
+ return { content: '', nextIndex: index };
54
105
  }
55
106
 
107
+ if (isNestedObjectLine(line.trim())) {
108
+ return readNestedObject(lines, startIndex, parentIndent);
109
+ }
110
+
111
+ return readIndentedScalar(lines, startIndex, parentIndent);
112
+ }
113
+
114
+ return { content: '', nextIndex: lines.length };
115
+ }
116
+
117
+ function readNestedObject(
118
+ lines: string[],
119
+ startIndex: number,
120
+ parentIndent: number,
121
+ ): { content: Record<string, string>; nextIndex: number } {
122
+ const result: Record<string, string> = {};
123
+ let index = startIndex;
124
+
125
+ while (index < lines.length) {
126
+ const line = lines[index];
127
+ if (!line || !line.trim()) {
128
+ index += 1;
129
+ continue;
130
+ }
131
+
132
+ const indent = line.search(/\S/);
133
+ if (indent <= parentIndent) break;
134
+
135
+ const trimmed = line.trim();
56
136
  const colonIdx = trimmed.indexOf(':');
57
- if (colonIdx === -1) continue;
137
+ if (colonIdx === -1) {
138
+ index += 1;
139
+ continue;
140
+ }
58
141
 
59
- const key = trimmed.slice(0, colonIdx).trim();
142
+ const key = normalizeKey(trimmed.slice(0, colonIdx).trim());
60
143
  const value = trimmed.slice(colonIdx + 1).trim();
61
144
 
62
- if (indent > 0 && nestedObject) {
63
- nestedObject[key] = parseYamlValue(value);
145
+ if (value === '|' || value === '>') {
146
+ const block = readBlockScalar(lines, index + 1, indent, value);
147
+ result[key] = block.content;
148
+ index = block.nextIndex;
64
149
  continue;
65
150
  }
66
151
 
67
- if (!value) {
68
- currentKey = normalizeKey(key);
69
- currentIndent = indent;
70
- nestedObject = {};
152
+ result[key] = String(parseYamlValue(value));
153
+ index += 1;
154
+ }
155
+
156
+ return { content: result, nextIndex: index };
157
+ }
158
+
159
+ function readIndentedScalar(
160
+ lines: string[],
161
+ startIndex: number,
162
+ parentIndent: number,
163
+ ): { content: string; nextIndex: number } {
164
+ const scalarLines: string[] = [];
165
+ let index = startIndex;
166
+ let contentIndent: number | null = null;
167
+
168
+ while (index < lines.length) {
169
+ const line = lines[index];
170
+ if (!line) {
171
+ scalarLines.push('');
172
+ index += 1;
173
+ continue;
174
+ }
175
+
176
+ if (!line.trim()) {
177
+ scalarLines.push('');
178
+ index += 1;
179
+ continue;
180
+ }
181
+
182
+ const indent = line.search(/\S/);
183
+ if (indent <= parentIndent) break;
184
+
185
+ contentIndent ??= indent;
186
+ scalarLines.push(line.slice(contentIndent));
187
+ index += 1;
188
+ }
189
+
190
+ return { content: foldBlockScalar(scalarLines), nextIndex: index };
191
+ }
192
+
193
+ function readBlockScalar(
194
+ lines: string[],
195
+ startIndex: number,
196
+ parentIndent: number,
197
+ style: '|' | '>',
198
+ ): { content: string; nextIndex: number } {
199
+ const blockLines: string[] = [];
200
+ let index = startIndex;
201
+ let contentIndent: number | null = null;
202
+
203
+ while (index < lines.length) {
204
+ const line = lines[index];
205
+ if (!line) {
206
+ blockLines.push('');
207
+ index += 1;
208
+ continue;
209
+ }
210
+
211
+ if (!line.trim()) {
212
+ blockLines.push('');
213
+ index += 1;
71
214
  continue;
72
215
  }
73
216
 
74
- result[normalizeKey(key)] = parseYamlValue(value);
217
+ const indent = line.search(/\S/);
218
+ if (indent <= parentIndent) break;
219
+
220
+ contentIndent ??= indent;
221
+ blockLines.push(line.slice(contentIndent));
222
+ index += 1;
75
223
  }
76
224
 
77
- if (nestedObject && currentKey) {
78
- result[currentKey] = nestedObject;
225
+ const content =
226
+ style === '>' ? foldBlockScalar(blockLines) : blockLines.join('\n').trim();
227
+ return { content, nextIndex: index };
228
+ }
229
+
230
+ function foldBlockScalar(lines: string[]): string {
231
+ const segments: string[] = [];
232
+ let current = '';
233
+
234
+ for (const line of lines) {
235
+ if (!line.trim()) {
236
+ if (current) {
237
+ segments.push(current.trim());
238
+ current = '';
239
+ }
240
+ continue;
241
+ }
242
+
243
+ current = current ? `${current} ${line.trim()}` : line.trim();
79
244
  }
80
245
 
81
- return result;
246
+ if (current) {
247
+ segments.push(current.trim());
248
+ }
249
+
250
+ return segments.join('\n');
82
251
  }
83
252
 
84
253
  function normalizeKey(key: string): string {
@@ -86,13 +255,29 @@ function normalizeKey(key: string): string {
86
255
  return key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
87
256
  }
88
257
 
89
- function parseYamlValue(value: string): string {
258
+ function isNestedObjectLine(line: string): boolean {
259
+ return /^[A-Za-z0-9_-]+\s*:/.test(line);
260
+ }
261
+
262
+ function parseYamlValue(value: string): unknown {
90
263
  if (
91
264
  (value.startsWith('"') && value.endsWith('"')) ||
92
265
  (value.startsWith("'") && value.endsWith("'"))
93
266
  ) {
94
267
  return value.slice(1, -1);
95
268
  }
269
+
270
+ if (
271
+ (value.startsWith('{') && value.endsWith('}')) ||
272
+ (value.startsWith('[') && value.endsWith(']'))
273
+ ) {
274
+ try {
275
+ return JSON.parse(value) as unknown;
276
+ } catch {
277
+ return value;
278
+ }
279
+ }
280
+
96
281
  return value;
97
282
  }
98
283
 
@@ -8,7 +8,7 @@ export type Scope = 'global' | 'local';
8
8
  /**
9
9
  * Default settings for the CLI
10
10
  */
11
- export type ToolApprovalMode = 'auto' | 'dangerous' | 'all';
11
+ export type ToolApprovalMode = 'auto' | 'dangerous' | 'all' | 'yolo';
12
12
  export type ReasoningLevel =
13
13
  | 'minimal'
14
14
  | 'low'
@@ -27,6 +27,7 @@ export type DefaultConfig = {
27
27
  reasoningLevel?: ReasoningLevel;
28
28
  theme?: string;
29
29
  fullWidthContent?: boolean;
30
+ autoCompactThresholdTokens?: number | null;
30
31
  };
31
32
 
32
33
  export type ProviderSettings = Record<