@otto-code/protocol 0.8.12 → 0.8.13

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 (37) hide show
  1. package/dist/agent-labels.d.ts +3 -0
  2. package/dist/agent-labels.js +10 -0
  3. package/dist/agent-personalities.d.ts +4 -3
  4. package/dist/agent-personalities.js +13 -20
  5. package/dist/agent-types.d.ts +24 -4
  6. package/dist/binary-frames/terminal.d.ts +4 -0
  7. package/dist/binary-frames/terminal.js +1 -0
  8. package/dist/brain.d.ts +91 -0
  9. package/dist/brain.js +19 -1
  10. package/dist/chat/rpc-schemas.js +1 -0
  11. package/dist/chat/types.js +1 -0
  12. package/dist/client-capabilities.d.ts +1 -0
  13. package/dist/client-capabilities.js +4 -0
  14. package/dist/daemon-config.d.ts +6 -0
  15. package/dist/daemon-config.js +6 -0
  16. package/dist/generated/validation/ws-outbound.aot.js +64093 -60274
  17. package/dist/loop/rpc-schemas.js +1 -0
  18. package/dist/messages.d.ts +3546 -422
  19. package/dist/messages.js +445 -13
  20. package/dist/provider-manifest.js +7 -0
  21. package/dist/provider-snapshot-codec.d.ts +18 -0
  22. package/dist/provider-snapshot-codec.js +71 -0
  23. package/dist/schedule/rpc-schemas.d.ts +8 -64
  24. package/dist/schedule/types.d.ts +3 -24
  25. package/dist/schedule/types.js +1 -11
  26. package/dist/search/text-match.d.ts +55 -0
  27. package/dist/search/text-match.js +262 -0
  28. package/dist/suggested-tasks.js +1 -1
  29. package/dist/terminal-input-mode.d.ts +4 -0
  30. package/dist/terminal-input-mode.js +35 -6
  31. package/dist/terminal-key-input.js +15 -6
  32. package/dist/terminal-profiles.d.ts +35 -0
  33. package/dist/terminal-profiles.js +246 -4
  34. package/dist/tool-call-display.d.ts +2 -2
  35. package/dist/tool-call-display.js +6 -6
  36. package/dist/validation/ws-outbound-schema-metadata.d.ts +587 -77
  37. package/package.json +1 -1
@@ -141,6 +141,13 @@ const MOCK_LOAD_TEST_MODES = [
141
141
  isUnattended: true,
142
142
  userSelectable: false,
143
143
  },
144
+ {
145
+ id: "approval-test",
146
+ label: "Approval Test",
147
+ description: "Alternate development-only permission mode for preference tests",
148
+ icon: "ShieldCheck",
149
+ colorTier: "safe",
150
+ },
144
151
  ];
145
152
  const MOCK_SLOW_MODES = [
146
153
  {
@@ -0,0 +1,18 @@
1
+ import type { AgentModelDefinition, AgentSelectOption, ProviderSnapshotEntry } from "./agent-types.js";
2
+ export interface CompactProviderSnapshotModel extends Omit<AgentModelDefinition, "provider" | "thinkingOptions"> {
3
+ thinkingSet?: number;
4
+ }
5
+ export interface CompactProviderSnapshotEntry extends Omit<ProviderSnapshotEntry, "models"> {
6
+ models?: CompactProviderSnapshotModel[];
7
+ }
8
+ export interface ProviderSnapshotThinkingSet {
9
+ options: AgentSelectOption[];
10
+ defaultOptionId?: string;
11
+ }
12
+ export interface CompactProviderSnapshot {
13
+ entries: CompactProviderSnapshotEntry[];
14
+ thinkingSets: ProviderSnapshotThinkingSet[];
15
+ }
16
+ export declare function compactProviderSnapshot(entries: ProviderSnapshotEntry[]): CompactProviderSnapshot;
17
+ export declare function expandProviderSnapshot(snapshot: CompactProviderSnapshot): ProviderSnapshotEntry[];
18
+ //# sourceMappingURL=provider-snapshot-codec.d.ts.map
@@ -0,0 +1,71 @@
1
+ function thinkingSetKey(set) {
2
+ return JSON.stringify(set);
3
+ }
4
+ function compactModel({ provider: _provider, thinkingOptions, defaultThinkingOptionId, ...modelFields }, thinkingSets, thinkingSetIndexes) {
5
+ const compact = modelFields;
6
+ if (thinkingOptions === undefined) {
7
+ if (defaultThinkingOptionId !== undefined) {
8
+ compact.defaultThinkingOptionId = defaultThinkingOptionId;
9
+ }
10
+ return compact;
11
+ }
12
+ const thinkingSet = {
13
+ options: thinkingOptions,
14
+ ...(defaultThinkingOptionId !== undefined ? { defaultOptionId: defaultThinkingOptionId } : {}),
15
+ };
16
+ const key = thinkingSetKey(thinkingSet);
17
+ const existingIndex = thinkingSetIndexes.get(key);
18
+ if (existingIndex !== undefined) {
19
+ compact.thinkingSet = existingIndex;
20
+ return compact;
21
+ }
22
+ const index = thinkingSets.length;
23
+ thinkingSets.push(thinkingSet);
24
+ thinkingSetIndexes.set(key, index);
25
+ compact.thinkingSet = index;
26
+ return compact;
27
+ }
28
+ export function compactProviderSnapshot(entries) {
29
+ const thinkingSets = [];
30
+ const thinkingSetIndexes = new Map();
31
+ const compactEntries = entries.map((entry) => {
32
+ if (entry.models === undefined) {
33
+ return entry;
34
+ }
35
+ return {
36
+ ...entry,
37
+ models: entry.models.map((model) => compactModel(model, thinkingSets, thinkingSetIndexes)),
38
+ };
39
+ });
40
+ return { entries: compactEntries, thinkingSets };
41
+ }
42
+ function expandModel(provider, model, thinkingSets) {
43
+ const { thinkingSet: thinkingSetIndex, ...modelFields } = model;
44
+ if (thinkingSetIndex === undefined) {
45
+ return { provider, ...modelFields };
46
+ }
47
+ const thinkingSet = thinkingSets[thinkingSetIndex];
48
+ if (!thinkingSet) {
49
+ throw new RangeError(`Provider snapshot references missing thinking set ${thinkingSetIndex}`);
50
+ }
51
+ return {
52
+ provider,
53
+ ...modelFields,
54
+ thinkingOptions: thinkingSet.options,
55
+ ...(thinkingSet.defaultOptionId !== undefined
56
+ ? { defaultThinkingOptionId: thinkingSet.defaultOptionId }
57
+ : {}),
58
+ };
59
+ }
60
+ export function expandProviderSnapshot(snapshot) {
61
+ return snapshot.entries.map((entry) => {
62
+ const { models, ...entryFields } = entry;
63
+ if (models === undefined)
64
+ return entryFields;
65
+ return {
66
+ ...entryFields,
67
+ models: models.map((model) => expandModel(entryFields.provider, model, snapshot.thinkingSets)),
68
+ };
69
+ });
70
+ }
71
+ //# sourceMappingURL=provider-snapshot-codec.js.map
@@ -33,15 +33,8 @@ export declare const ScheduleCreateRequestSchema: z.ZodObject<{
33
33
  local: "local";
34
34
  }>>;
35
35
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
36
- approvalPolicy: z.ZodOptional<z.ZodString>;
37
- sandboxMode: z.ZodOptional<z.ZodString>;
38
- networkAccess: z.ZodOptional<z.ZodBoolean>;
39
- webSearch: z.ZodOptional<z.ZodBoolean>;
36
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
40
37
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
41
- extra: z.ZodOptional<z.ZodObject<{
42
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
43
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
44
- }, z.core.$strip>>;
45
38
  systemPrompt: z.ZodOptional<z.ZodString>;
46
39
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
47
40
  }, z.core.$strip>;
@@ -148,15 +141,8 @@ export declare const ScheduleCreateResponseSchema: z.ZodObject<{
148
141
  local: "local";
149
142
  }>>;
150
143
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
151
- approvalPolicy: z.ZodOptional<z.ZodString>;
152
- sandboxMode: z.ZodOptional<z.ZodString>;
153
- networkAccess: z.ZodOptional<z.ZodBoolean>;
154
- webSearch: z.ZodOptional<z.ZodBoolean>;
144
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
155
145
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
156
- extra: z.ZodOptional<z.ZodObject<{
157
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
158
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
159
- }, z.core.$strip>>;
160
146
  systemPrompt: z.ZodOptional<z.ZodString>;
161
147
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
162
148
  }, z.core.$strip>;
@@ -219,15 +205,8 @@ export declare const ScheduleListResponseSchema: z.ZodObject<{
219
205
  local: "local";
220
206
  }>>;
221
207
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
222
- approvalPolicy: z.ZodOptional<z.ZodString>;
223
- sandboxMode: z.ZodOptional<z.ZodString>;
224
- networkAccess: z.ZodOptional<z.ZodBoolean>;
225
- webSearch: z.ZodOptional<z.ZodBoolean>;
208
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
226
209
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
227
- extra: z.ZodOptional<z.ZodObject<{
228
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
229
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
230
- }, z.core.$strip>>;
231
210
  systemPrompt: z.ZodOptional<z.ZodString>;
232
211
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
233
212
  }, z.core.$strip>;
@@ -290,15 +269,8 @@ export declare const ScheduleInspectResponseSchema: z.ZodObject<{
290
269
  local: "local";
291
270
  }>>;
292
271
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
293
- approvalPolicy: z.ZodOptional<z.ZodString>;
294
- sandboxMode: z.ZodOptional<z.ZodString>;
295
- networkAccess: z.ZodOptional<z.ZodBoolean>;
296
- webSearch: z.ZodOptional<z.ZodBoolean>;
272
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
297
273
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
298
- extra: z.ZodOptional<z.ZodObject<{
299
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
300
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
301
- }, z.core.$strip>>;
302
274
  systemPrompt: z.ZodOptional<z.ZodString>;
303
275
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
304
276
  }, z.core.$strip>;
@@ -404,15 +376,8 @@ export declare const SchedulePauseResponseSchema: z.ZodObject<{
404
376
  local: "local";
405
377
  }>>;
406
378
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
407
- approvalPolicy: z.ZodOptional<z.ZodString>;
408
- sandboxMode: z.ZodOptional<z.ZodString>;
409
- networkAccess: z.ZodOptional<z.ZodBoolean>;
410
- webSearch: z.ZodOptional<z.ZodBoolean>;
379
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
411
380
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
412
- extra: z.ZodOptional<z.ZodObject<{
413
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
414
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
415
- }, z.core.$strip>>;
416
381
  systemPrompt: z.ZodOptional<z.ZodString>;
417
382
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
418
383
  }, z.core.$strip>;
@@ -475,15 +440,8 @@ export declare const ScheduleResumeResponseSchema: z.ZodObject<{
475
440
  local: "local";
476
441
  }>>;
477
442
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
478
- approvalPolicy: z.ZodOptional<z.ZodString>;
479
- sandboxMode: z.ZodOptional<z.ZodString>;
480
- networkAccess: z.ZodOptional<z.ZodBoolean>;
481
- webSearch: z.ZodOptional<z.ZodBoolean>;
443
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
482
444
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
483
- extra: z.ZodOptional<z.ZodObject<{
484
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
485
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
486
- }, z.core.$strip>>;
487
445
  systemPrompt: z.ZodOptional<z.ZodString>;
488
446
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
489
447
  }, z.core.$strip>;
@@ -554,15 +512,8 @@ export declare const ScheduleRunOnceResponseSchema: z.ZodObject<{
554
512
  local: "local";
555
513
  }>>;
556
514
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
557
- approvalPolicy: z.ZodOptional<z.ZodString>;
558
- sandboxMode: z.ZodOptional<z.ZodString>;
559
- networkAccess: z.ZodOptional<z.ZodBoolean>;
560
- webSearch: z.ZodOptional<z.ZodBoolean>;
515
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
561
516
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
562
- extra: z.ZodOptional<z.ZodObject<{
563
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
564
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
565
- }, z.core.$strip>>;
566
517
  systemPrompt: z.ZodOptional<z.ZodString>;
567
518
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
568
519
  }, z.core.$strip>;
@@ -643,15 +594,8 @@ export declare const ScheduleUpdateResponseSchema: z.ZodObject<{
643
594
  local: "local";
644
595
  }>>;
645
596
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
646
- approvalPolicy: z.ZodOptional<z.ZodString>;
647
- sandboxMode: z.ZodOptional<z.ZodString>;
648
- networkAccess: z.ZodOptional<z.ZodBoolean>;
649
- webSearch: z.ZodOptional<z.ZodBoolean>;
597
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
650
598
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
651
- extra: z.ZodOptional<z.ZodObject<{
652
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
653
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
654
- }, z.core.$strip>>;
655
599
  systemPrompt: z.ZodOptional<z.ZodString>;
656
600
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
657
601
  }, z.core.$strip>;
@@ -32,15 +32,8 @@ export declare const ScheduleTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
32
32
  local: "local";
33
33
  }>>;
34
34
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
- approvalPolicy: z.ZodOptional<z.ZodString>;
36
- sandboxMode: z.ZodOptional<z.ZodString>;
37
- networkAccess: z.ZodOptional<z.ZodBoolean>;
38
- webSearch: z.ZodOptional<z.ZodBoolean>;
35
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
39
36
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
40
- extra: z.ZodOptional<z.ZodObject<{
41
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
42
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
43
- }, z.core.$strip>>;
44
37
  systemPrompt: z.ZodOptional<z.ZodString>;
45
38
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
46
39
  }, z.core.$strip>;
@@ -95,15 +88,8 @@ export declare const StoredScheduleSchema: z.ZodObject<{
95
88
  local: "local";
96
89
  }>>;
97
90
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
98
- approvalPolicy: z.ZodOptional<z.ZodString>;
99
- sandboxMode: z.ZodOptional<z.ZodString>;
100
- networkAccess: z.ZodOptional<z.ZodBoolean>;
101
- webSearch: z.ZodOptional<z.ZodBoolean>;
91
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
102
92
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
103
- extra: z.ZodOptional<z.ZodObject<{
104
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
105
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
106
- }, z.core.$strip>>;
107
93
  systemPrompt: z.ZodOptional<z.ZodString>;
108
94
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
109
95
  }, z.core.$strip>;
@@ -178,15 +164,8 @@ export declare const ScheduleSummarySchema: z.ZodObject<{
178
164
  local: "local";
179
165
  }>>;
180
166
  title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
181
- approvalPolicy: z.ZodOptional<z.ZodString>;
182
- sandboxMode: z.ZodOptional<z.ZodString>;
183
- networkAccess: z.ZodOptional<z.ZodBoolean>;
184
- webSearch: z.ZodOptional<z.ZodBoolean>;
167
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
185
168
  featureValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
186
- extra: z.ZodOptional<z.ZodObject<{
187
- codex: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
188
- claude: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
189
- }, z.core.$strip>>;
190
169
  systemPrompt: z.ZodOptional<z.ZodString>;
191
170
  mcpServers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
192
171
  }, z.core.$strip>;
@@ -32,18 +32,8 @@ export const ScheduleTargetSchema = z.discriminatedUnion("type", [
32
32
  archiveOnFinish: z.boolean().optional(),
33
33
  isolation: z.enum(["local", "worktree"]).optional(),
34
34
  title: z.string().trim().min(1).nullable().optional(),
35
- approvalPolicy: z.string().trim().min(1).optional(),
36
- sandboxMode: z.string().trim().min(1).optional(),
37
- networkAccess: z.boolean().optional(),
38
- webSearch: z.boolean().optional(),
35
+ providerOptions: z.record(z.string(), z.json()).optional(),
39
36
  featureValues: z.record(z.string(), z.unknown()).optional(),
40
- extra: z
41
- .object({
42
- codex: z.record(z.string(), z.unknown()).optional(),
43
- claude: z.record(z.string(), z.unknown()).optional(),
44
- })
45
- .partial()
46
- .optional(),
47
37
  systemPrompt: z.string().optional(),
48
38
  mcpServers: z.record(z.string(), z.unknown()).optional(),
49
39
  }),
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Ranked text matching shared by the app's pickers and the daemon's history
3
+ * search. A match is a tier plus the offset it was found at; lower is better on
4
+ * both, so callers sort ascending and never have to invent a scale.
5
+ *
6
+ * Typo tolerance is opt-in via `fuzzy`. The pickers leave it off — a combobox
7
+ * over a known list wants exact narrowing — while history search turns it on
8
+ * because the user is recalling a title from memory.
9
+ */
10
+ export interface MatchScore {
11
+ tier: number;
12
+ offset: number;
13
+ spread?: number;
14
+ }
15
+ export interface MatchOptions {
16
+ /** Omit or pass null to match exactly. `fuzzyPolicyForToken` picks a policy. */
17
+ fuzzy?: FuzzyPolicy | null;
18
+ }
19
+ /**
20
+ * How much a typo in one query token is forgiven. Short tokens get
21
+ * transpositions and nothing else: at four characters a free substitution turns
22
+ * "main" into "mail", "maid", and "rain", while a swap can only ever reach the
23
+ * word the user meant. Null means the token is matched exactly.
24
+ */
25
+ export interface FuzzyPolicy {
26
+ maxEdits: number;
27
+ transpositionsOnly: boolean;
28
+ }
29
+ export declare function fuzzyPolicyForToken(token: string): FuzzyPolicy | null;
30
+ export declare function scoreMatch(query: string, text: string, options?: MatchOptions): MatchScore | null;
31
+ export interface MatchRange {
32
+ start: number;
33
+ length: number;
34
+ }
35
+ /**
36
+ * Where a score's match actually landed, so a caller can mark it. Derived from
37
+ * a score rather than produced alongside one: ranking touches every candidate
38
+ * and needs no ranges, while only the handful of rows that get rendered do.
39
+ *
40
+ * The tier decides the shape. A substring hit is one span; a subsequence hit is
41
+ * the scattered characters it walked; a typo hit marks the whole word, because
42
+ * the characters the user got wrong are not in the text to point at.
43
+ */
44
+ export declare function matchRanges(query: string, text: string, score: MatchScore): MatchRange[];
45
+ export declare function compareMatchScores(a: MatchScore, b: MatchScore): number;
46
+ export declare function tokenizeQuery(query: string): string[];
47
+ export interface TextFieldsOptions {
48
+ /**
49
+ * Forgive typos. The budget is per token rather than per query, because a
50
+ * query mixes long words that can absorb an edit with short ones that cannot.
51
+ */
52
+ typoTolerant?: boolean;
53
+ }
54
+ export declare function scoreTextFields(query: string, fields: string[], options?: TextFieldsOptions): MatchScore | null;
55
+ //# sourceMappingURL=text-match.d.ts.map
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Ranked text matching shared by the app's pickers and the daemon's history
3
+ * search. A match is a tier plus the offset it was found at; lower is better on
4
+ * both, so callers sort ascending and never have to invent a scale.
5
+ *
6
+ * Typo tolerance is opt-in via `fuzzy`. The pickers leave it off — a combobox
7
+ * over a known list wants exact narrowing — while history search turns it on
8
+ * because the user is recalling a title from memory.
9
+ */
10
+ /** Exact tiers, best to worst. The fuzzy tier always sorts after all of them. */
11
+ const TIER_EXACT = 0;
12
+ const TIER_WHOLE_WORD = 1;
13
+ const TIER_PREFIX = 2;
14
+ const TIER_WORD_START = 3;
15
+ const TIER_SUBSTRING = 4;
16
+ const TIER_SUBSEQUENCE = 5;
17
+ const TIER_FUZZY = 6;
18
+ function isWordBoundaryChar(ch) {
19
+ if (ch === undefined)
20
+ return true;
21
+ return !/[a-z0-9]/.test(ch);
22
+ }
23
+ function scoreSubstringMatch(query, text) {
24
+ let best = null;
25
+ let pos = 0;
26
+ while (pos <= text.length - query.length) {
27
+ const found = text.indexOf(query, pos);
28
+ if (found === -1)
29
+ break;
30
+ const before = found > 0 ? text[found - 1] : undefined;
31
+ const after = text[found + query.length];
32
+ const startsAtBoundary = found === 0 || isWordBoundaryChar(before);
33
+ const endsAtBoundary = after === undefined || isWordBoundaryChar(after);
34
+ let tier;
35
+ if (startsAtBoundary && endsAtBoundary) {
36
+ tier = TIER_WHOLE_WORD;
37
+ }
38
+ else if (found === 0) {
39
+ tier = TIER_PREFIX;
40
+ }
41
+ else if (startsAtBoundary) {
42
+ tier = TIER_WORD_START;
43
+ }
44
+ else {
45
+ tier = TIER_SUBSTRING;
46
+ }
47
+ if (!best || tier < best.tier || (tier === best.tier && found < best.offset)) {
48
+ best = { tier, offset: found };
49
+ }
50
+ pos = found + 1;
51
+ }
52
+ return best;
53
+ }
54
+ function scoreSubsequenceMatch(query, text) {
55
+ let queryIndex = 0;
56
+ let firstIndex = -1;
57
+ let lastIndex = -1;
58
+ for (let textIndex = 0; textIndex < text.length && queryIndex < query.length; textIndex += 1) {
59
+ if (text[textIndex] !== query[queryIndex])
60
+ continue;
61
+ if (firstIndex === -1)
62
+ firstIndex = textIndex;
63
+ lastIndex = textIndex;
64
+ queryIndex += 1;
65
+ }
66
+ if (queryIndex !== query.length || firstIndex === -1)
67
+ return null;
68
+ return { tier: TIER_SUBSEQUENCE, offset: firstIndex, spread: lastIndex - firstIndex + 1 };
69
+ }
70
+ /**
71
+ * Damerau-Levenshtein distance, abandoned as soon as every cell in a row is
72
+ * over budget. Bounding it is what keeps the fuzzy tier affordable to run
73
+ * against every word of every candidate.
74
+ */
75
+ function boundedEditDistance(query, word, budget) {
76
+ if (Math.abs(query.length - word.length) > budget)
77
+ return null;
78
+ let twoRowsBack = [];
79
+ let previousRow = Array.from({ length: word.length + 1 }, (_, index) => index);
80
+ for (let queryIndex = 1; queryIndex <= query.length; queryIndex += 1) {
81
+ const currentRow = [queryIndex];
82
+ let rowBest = queryIndex;
83
+ for (let wordIndex = 1; wordIndex <= word.length; wordIndex += 1) {
84
+ const substitutionCost = query[queryIndex - 1] === word[wordIndex - 1] ? 0 : 1;
85
+ let cost = Math.min(currentRow[wordIndex - 1] + 1, previousRow[wordIndex] + 1, previousRow[wordIndex - 1] + substitutionCost);
86
+ const isTransposition = queryIndex > 1 &&
87
+ wordIndex > 1 &&
88
+ query[queryIndex - 1] === word[wordIndex - 2] &&
89
+ query[queryIndex - 2] === word[wordIndex - 1];
90
+ if (isTransposition) {
91
+ cost = Math.min(cost, twoRowsBack[wordIndex - 2] + 1);
92
+ }
93
+ currentRow.push(cost);
94
+ rowBest = Math.min(rowBest, cost);
95
+ }
96
+ if (rowBest > budget)
97
+ return null;
98
+ twoRowsBack = previousRow;
99
+ previousRow = currentRow;
100
+ }
101
+ const distance = previousRow[word.length];
102
+ return distance <= budget ? distance : null;
103
+ }
104
+ function transpositionDistance(query, word) {
105
+ return isAdjacentTransposition(query, word) ? 1 : null;
106
+ }
107
+ /** True when the two differ only by one swap of neighbouring characters. */
108
+ function isAdjacentTransposition(query, word) {
109
+ if (query.length !== word.length)
110
+ return false;
111
+ let index = 0;
112
+ while (index < query.length && query[index] === word[index])
113
+ index += 1;
114
+ if (index >= query.length - 1)
115
+ return false;
116
+ if (query[index] !== word[index + 1] || query[index + 1] !== word[index])
117
+ return false;
118
+ return query.slice(index + 2) === word.slice(index + 2);
119
+ }
120
+ export function fuzzyPolicyForToken(token) {
121
+ if (token.length <= 3)
122
+ return null;
123
+ if (token.length === 4)
124
+ return { maxEdits: 1, transpositionsOnly: true };
125
+ if (token.length <= 7)
126
+ return { maxEdits: 1, transpositionsOnly: false };
127
+ return { maxEdits: 2, transpositionsOnly: false };
128
+ }
129
+ /**
130
+ * Words are what people mistype, so the fuzzy tier compares the query against
131
+ * each word rather than against the whole string — otherwise a long title's
132
+ * length difference alone would blow the budget.
133
+ */
134
+ function scoreFuzzyMatch(query, text, policy) {
135
+ if (policy.maxEdits <= 0 || query.length <= policy.maxEdits)
136
+ return null;
137
+ let best = null;
138
+ const wordPattern = /[a-z0-9]+/g;
139
+ let word = wordPattern.exec(text);
140
+ while (word !== null) {
141
+ // Compare against the whole word and against its leading slices, so a typo
142
+ // in a prefix ("confug" for "configuration") still lands — the length gap
143
+ // to the full word would otherwise blow the budget on its own.
144
+ const candidates = new Set([
145
+ word[0],
146
+ word[0].slice(0, query.length),
147
+ word[0].slice(0, query.length + policy.maxEdits),
148
+ ]);
149
+ for (const candidate of candidates) {
150
+ const distance = policy.transpositionsOnly
151
+ ? transpositionDistance(query, candidate)
152
+ : boundedEditDistance(query, candidate, policy.maxEdits);
153
+ if (distance === null)
154
+ continue;
155
+ const score = { tier: TIER_FUZZY, offset: word.index, spread: distance };
156
+ if (!best || compareMatchScores(score, best) < 0) {
157
+ best = score;
158
+ }
159
+ }
160
+ word = wordPattern.exec(text);
161
+ }
162
+ return best;
163
+ }
164
+ export function scoreMatch(query, text, options = {}) {
165
+ if (!query)
166
+ return { tier: TIER_EXACT, offset: 0 };
167
+ const q = query.toLowerCase();
168
+ const t = text.toLowerCase();
169
+ if (t === q)
170
+ return { tier: TIER_EXACT, offset: 0 };
171
+ const exact = scoreSubstringMatch(q, t) ?? scoreSubsequenceMatch(q, t);
172
+ if (exact)
173
+ return exact;
174
+ const fuzzy = options.fuzzy;
175
+ return fuzzy ? scoreFuzzyMatch(q, t, fuzzy) : null;
176
+ }
177
+ function mergeAdjacentRanges(indices) {
178
+ const ranges = [];
179
+ for (const index of indices) {
180
+ const last = ranges.at(-1);
181
+ if (last && last.start + last.length === index) {
182
+ last.length += 1;
183
+ continue;
184
+ }
185
+ ranges.push({ start: index, length: 1 });
186
+ }
187
+ return ranges;
188
+ }
189
+ function wordRangeAt(text, offset) {
190
+ let end = offset;
191
+ while (end < text.length && /[a-z0-9]/.test(text[end]))
192
+ end += 1;
193
+ return { start: offset, length: Math.max(end - offset, 1) };
194
+ }
195
+ /**
196
+ * Where a score's match actually landed, so a caller can mark it. Derived from
197
+ * a score rather than produced alongside one: ranking touches every candidate
198
+ * and needs no ranges, while only the handful of rows that get rendered do.
199
+ *
200
+ * The tier decides the shape. A substring hit is one span; a subsequence hit is
201
+ * the scattered characters it walked; a typo hit marks the whole word, because
202
+ * the characters the user got wrong are not in the text to point at.
203
+ */
204
+ export function matchRanges(query, text, score) {
205
+ if (!query)
206
+ return [];
207
+ const q = query.toLowerCase();
208
+ const t = text.toLowerCase();
209
+ if (score.tier === TIER_EXACT)
210
+ return [{ start: 0, length: text.length }];
211
+ if (score.tier === TIER_FUZZY)
212
+ return [wordRangeAt(t, score.offset)];
213
+ if (score.tier === TIER_SUBSEQUENCE) {
214
+ const indices = [];
215
+ let queryIndex = 0;
216
+ for (let textIndex = 0; textIndex < t.length && queryIndex < q.length; textIndex += 1) {
217
+ if (t[textIndex] !== q[queryIndex])
218
+ continue;
219
+ indices.push(textIndex);
220
+ queryIndex += 1;
221
+ }
222
+ return mergeAdjacentRanges(indices);
223
+ }
224
+ return [{ start: score.offset, length: q.length }];
225
+ }
226
+ export function compareMatchScores(a, b) {
227
+ if (a.tier !== b.tier)
228
+ return a.tier - b.tier;
229
+ if (a.offset !== b.offset)
230
+ return a.offset - b.offset;
231
+ return (a.spread ?? 0) - (b.spread ?? 0);
232
+ }
233
+ export function tokenizeQuery(query) {
234
+ return query
235
+ .trim()
236
+ .toLowerCase()
237
+ .split(/\s+/)
238
+ .filter((token) => token.length > 0);
239
+ }
240
+ export function scoreTextFields(query, fields, options = {}) {
241
+ const tokens = tokenizeQuery(query);
242
+ if (tokens.length === 0)
243
+ return { tier: TIER_EXACT, offset: 0, spread: 0 };
244
+ const aggregate = { tier: TIER_EXACT, offset: 0, spread: 0 };
245
+ for (const token of tokens) {
246
+ const fuzzy = options.typoTolerant ? fuzzyPolicyForToken(token) : null;
247
+ let best = null;
248
+ for (const field of fields) {
249
+ const score = scoreMatch(token, field, { fuzzy });
250
+ if (score && (!best || compareMatchScores(score, best) < 0)) {
251
+ best = score;
252
+ }
253
+ }
254
+ if (!best)
255
+ return null;
256
+ aggregate.tier += best.tier;
257
+ aggregate.offset += best.offset;
258
+ aggregate.spread = (aggregate.spread ?? 0) + (best.spread ?? token.length);
259
+ }
260
+ return aggregate;
261
+ }
262
+ //# sourceMappingURL=text-match.js.map
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  /**
3
3
  * Otto suggested-task wire schemas: the tasks.suggested.* start and dismiss RPCs and the suggested-task payloads. Fork-only capability, so it owns its schemas; messages.ts re-exports them.
4
4
  */
5
- // A suggested task an agent surfaced via the `spawn_task` tool (Claude Desktop
5
+ // A suggested task a chat surfaced via the `suggest_task` tool (Claude Desktop
6
6
  // parity). Renders as a chip in the parent agent's session; the user starts it
7
7
  // (new worktree / local / this session) or dismisses it. The `prompt` is
8
8
  // deliberately NOT part of this wire shape - it stays server-side and is only
@@ -5,6 +5,8 @@ export interface TerminalInputModeFeedResult {
5
5
  export interface TerminalInputModeState {
6
6
  kittyKeyboardFlags: number;
7
7
  win32InputMode: boolean;
8
+ applicationCursorKeys?: boolean;
9
+ bracketedPaste?: boolean;
8
10
  }
9
11
  export declare const DEFAULT_TERMINAL_INPUT_MODE_STATE: TerminalInputModeState;
10
12
  export declare function terminalInputModeSupportsModifiedEnter(state: TerminalInputModeState): boolean;
@@ -12,6 +14,8 @@ export declare function terminalInputModeStatesEqual(left: TerminalInputModeStat
12
14
  export declare class TerminalInputModeTracker {
13
15
  private kittyKeyboardFlags;
14
16
  private win32InputMode;
17
+ private applicationCursorKeys;
18
+ private bracketedPaste;
15
19
  private readonly kittyKeyboardStack;
16
20
  private pending;
17
21
  feed(data: string): TerminalInputModeFeedResult;