.agents/skills/builtin-skills/SKILL.mdnew file+42
@@ -0,0 +1,42 @@
4+ Use when creating a new builtin skill for Crush, editing an existing builtin
5+ skill (internal/skills/builtin/), or when the user needs to understand how the
6+ embedded skill system works.
11+Crush embeds skills directly into the binary via `internal/skills/builtin/`.
12+These are always available without user configuration.
16+- Each skill lives in `internal/skills/builtin/<skill-name>/SKILL.md`.
17+- The tree is embedded at compile time via `//go:embed builtin/*` in
18+ `internal/skills/embed.go`.
19+- `DiscoverBuiltin()` walks the embedded FS, parses each `SKILL.md`, and sets
20+ paths with the `crush://skills/` prefix (e.g., `crush://skills/jq/SKILL.md`).
21+- The View tool resolves `crush://` paths from the embedded FS, not disk.
22+- User skills with the same name override builtins (last occurrence wins in
25+## Adding a New Builtin Skill
27+1. Create `internal/skills/builtin/<skill-name>/SKILL.md` with YAML frontmatter
28+ (`name`, `description`) and markdown instructions. The directory name must
29+ match the `name` field.
30+2. No extra wiring needed — `//go:embed builtin/*` picks up new directories
32+3. Add a test assertion in `TestDiscoverBuiltin` in
33+ `internal/skills/skills_test.go` to verify discovery.
34+4. Build and test: `go build . && go test ./internal/skills/...`
36+## Existing Builtin Skills
38+| Skill | Directory | Description |
39+| -------------- | ----------------------- | ------------------------------------------ |
40+| `crush-config` | `builtin/crush-config/` | Crush configuration help |
41+| `crush-hooks` | `builtin/crush-hooks/` | Authoring, configuring and debugging hooks |
42+| `jq` | `builtin/jq/` | jq JSON processor usage guide |
.agents/skills/shell-builtins/SKILL.mdnew file+72
@@ -0,0 +1,72 @@
3+description: Use when creating a new shell builtin command for Crush (internal/shell/), editing an existing one, or when the user needs to understand how commands are intercepted in Crush's embedded shell.
8+Crush's shell (`internal/shell/`) uses `mvdan.cc/sh/v3` for POSIX shell
9+emulation. Commands can be intercepted before they reach the OS by adding
10+**builtins** — functions handled in-process.
14+Builtins live in `builtinHandler()` in `internal/shell/run.go`. This is an
15+`interp.ExecHandlerFunc` middleware registered in `standardHandlers()`
16+**before** the block handler, so builtins run even for commands that would
17+otherwise be blocked. The same handler chain is shared by the stateful
18+`Shell` type and the stateless `Run` entrypoint used by the hook runner,
19+so builtins are available identically in the `bash` tool and in hooks.
21+The handler is a switch on `args[0]`. Each case either handles the command
22+inline or delegates to a helper function.
24+## Adding a New Builtin
26+1. **Add the case** to the switch in `builtinHandler()` in `run.go`.
27+2. **Get I/O from the handler context**, not from `os.Stdin`/`os.Stdout`.
28+ This ensures the builtin works with pipes and redirections:
31+ hc := interp.HandlerCtx(ctx)
32+ return handleMyCommand(ctx, args, hc.Stdin, hc.Stdout, hc.Stderr)
34+3. **Implement the handler** in its own file (e.g.,
35+ `internal/shell/mycommand.go`). The function signature must accept a
36+ `context.Context` as the first parameter, plus args, stdin, stdout, and
39+ func handleMyCommand(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) error {
40+ // args[0] is the command name ("mycommand"), args[1:] are arguments.
41+ // Write output to stdout, errors to stderr.
42+ // Return nil on success, or interp.ExitStatus(n) for non-zero exit codes.
45+4. **Poll `ctx` in every unbounded loop.** Builtins that iterate over
46+ input, emit values in a generator-style loop, or do any other work
47+ that can exceed a few milliseconds MUST check `ctx.Err()` on each
48+ iteration and return it verbatim when non-nil. Hook timeouts rely on
49+ this: an unbounded builtin that never polls ctx cannot be interrupted
50+ by a hook's `timeout_sec`, and the hook runner will have to abandon
51+ the goroutine (see `internal/hooks/runner.go`). Returning `ctx.Err()`
52+ (not `interp.ExitStatus(n)`) lets callers distinguish "command exited
53+ non-zero" from "we ran out of time".
55+ for _, item := range items {
56+ if err := ctx.Err(); err != nil {
62+5. **Return values**: return `nil` for success, `interp.ExitStatus(n)` for
63+ non-zero exit codes, or `ctx.Err()` on cancellation. Write error
64+ messages to `stderr` before returning.
65+6. **No extra wiring needed** — `builtinHandler()` is already registered
66+ in `standardHandlers()`.
70+| Command | File | Description |
71+|---------|------|-------------|
72+| `jq` | `jq.go` | JSON processor using `github.com/itchyny/gojq` |
@@ -1,2 +1,4 @@
1*.golden linguist-generated=true -text
1*.golden linguist-generated=true -text
2.github/crush-schema.json linguist-generated=true
2.github/crush-schema.json linguist-generated=true
3+internal/agent/hyper/provider.json linguist-generated=true
4+internal/agent/testdata/**/*.yaml -diff linguist-generated=true
.github/CODEOWNERSdeleted−1
.github/cla-signatures.jsonnew file+2100
@@ -0,0 +1,2100 @@
2+ "signedContributors": [
6+ "comment_id": 3133376230,
7+ "created_at": "2025-07-29T17:11:51Z",
12+ "name": "raphamorim",
14+ "comment_id": 3133374793,
15+ "created_at": "2025-07-29T17:11:19Z",
20+ "name": "raphamorim",
22+ "comment_id": 3133379333,
23+ "created_at": "2025-07-29T17:13:00Z",
28+ "name": "aymanbagabas",
30+ "comment_id": 3133374319,
31+ "created_at": "2025-07-29T17:11:08Z",
36+ "name": "aymanbagabas",
38+ "comment_id": 3133398259,
39+ "created_at": "2025-07-29T17:19:30Z",
44+ "name": "andreynering",
46+ "comment_id": 3133398174,
47+ "created_at": "2025-07-29T17:19:29Z",
54+ "comment_id": 3133486409,
55+ "created_at": "2025-07-29T17:51:25Z",
60+ "name": "meowgorithm",
62+ "comment_id": 3134117697,
63+ "created_at": "2025-07-29T21:23:05Z",
68+ "name": "kujtimiihoxha",
70+ "comment_id": 3135739620,
71+ "created_at": "2025-07-30T10:35:23Z",
78+ "comment_id": 3136448851,
79+ "created_at": "2025-07-30T13:51:45Z",
86+ "comment_id": 3136721507,
87+ "created_at": "2025-07-30T14:55:51Z",
94+ "comment_id": 3138718122,
95+ "created_at": "2025-07-31T06:31:11Z",
100+ "name": "fluffypony",
102+ "comment_id": 3139828932,
103+ "created_at": "2025-07-31T12:45:05Z",
104+ "repoId": 987670088,
105+ "pullRequestNo": 400
110+ "comment_id": 3140242221,
111+ "created_at": "2025-07-31T14:39:23Z",
112+ "repoId": 987670088,
113+ "pullRequestNo": 408
118+ "comment_id": 3140319096,
119+ "created_at": "2025-07-31T15:01:49Z",
120+ "repoId": 987670088,
121+ "pullRequestNo": 409
126+ "comment_id": 3140446226,
127+ "created_at": "2025-07-31T15:40:05Z",
128+ "repoId": 987670088,
129+ "pullRequestNo": 414
134+ "comment_id": 3141170246,
135+ "created_at": "2025-07-31T19:54:14Z",
136+ "repoId": 987670088,
137+ "pullRequestNo": 429
140+ "name": "petersanchez",
142+ "comment_id": 3141358800,
143+ "created_at": "2025-07-31T21:14:55Z",
144+ "repoId": 987670088,
145+ "pullRequestNo": 434
148+ "name": "alvaro17f",
150+ "comment_id": 3144148093,
151+ "created_at": "2025-08-01T10:50:27Z",
152+ "repoId": 987670088,
153+ "pullRequestNo": 451
156+ "name": "bbrodriges",
158+ "comment_id": 3144263924,
159+ "created_at": "2025-08-01T11:33:11Z",
160+ "repoId": 987670088,
161+ "pullRequestNo": 454
164+ "name": "SyedaAnshrahGillani",
166+ "comment_id": 3144865858,
167+ "created_at": "2025-08-01T14:57:07Z",
168+ "repoId": 987670088,
169+ "pullRequestNo": 460
172+ "name": "spachava753",
174+ "comment_id": 3145329017,
175+ "created_at": "2025-08-01T17:49:37Z",
176+ "repoId": 987670088,
177+ "pullRequestNo": 469
180+ "name": "tabletcorry",
182+ "comment_id": 3145908475,
183+ "created_at": "2025-08-01T22:18:28Z",
184+ "repoId": 987670088,
185+ "pullRequestNo": 480
190+ "comment_id": 3146472558,
191+ "created_at": "2025-08-02T12:24:29Z",
192+ "repoId": 987670088,
193+ "pullRequestNo": 504
198+ "comment_id": 3146962342,
199+ "created_at": "2025-08-03T04:07:16Z",
200+ "repoId": 987670088,
201+ "pullRequestNo": 519
206+ "comment_id": 3148713433,
207+ "created_at": "2025-08-03T21:35:15Z",
208+ "repoId": 987670088,
209+ "pullRequestNo": 527
214+ "comment_id": 3150375016,
215+ "created_at": "2025-08-04T12:16:16Z",
216+ "repoId": 987670088,
217+ "pullRequestNo": 539
222+ "comment_id": 3150846779,
223+ "created_at": "2025-08-04T14:01:30Z",
224+ "repoId": 987670088,
225+ "pullRequestNo": 546
230+ "comment_id": 3152513500,
231+ "created_at": "2025-08-04T21:55:42Z",
232+ "repoId": 987670088,
233+ "pullRequestNo": 564
238+ "comment_id": 3152872109,
239+ "created_at": "2025-08-05T00:24:50Z",
240+ "repoId": 987670088,
241+ "pullRequestNo": 569
244+ "name": "mohseenrm",
246+ "comment_id": 3153159347,
247+ "created_at": "2025-08-05T03:39:12Z",
248+ "repoId": 987670088,
249+ "pullRequestNo": 574
254+ "comment_id": 3157331134,
255+ "created_at": "2025-08-06T04:07:52Z",
256+ "repoId": 987670088,
257+ "pullRequestNo": 584
262+ "comment_id": 3157402768,
263+ "created_at": "2025-08-06T04:56:35Z",
264+ "repoId": 987670088,
265+ "pullRequestNo": 585
270+ "comment_id": 3157429309,
271+ "created_at": "2025-08-06T05:14:23Z",
272+ "repoId": 987670088,
273+ "pullRequestNo": 585
278+ "comment_id": 3159014183,
279+ "created_at": "2025-08-06T10:04:39Z",
280+ "repoId": 987670088,
281+ "pullRequestNo": 593
284+ "name": "taciturnaxolotl",
286+ "comment_id": 3160702345,
287+ "created_at": "2025-08-06T15:48:47Z",
288+ "repoId": 987670088,
289+ "pullRequestNo": 606
292+ "name": "bashbunni",
294+ "comment_id": 3160746002,
295+ "created_at": "2025-08-06T16:02:06Z",
296+ "repoId": 987670088,
297+ "pullRequestNo": 187
300+ "name": "edafonseca",
302+ "comment_id": 3161714270,
303+ "created_at": "2025-08-06T21:41:34Z",
304+ "repoId": 987670088,
305+ "pullRequestNo": 618
310+ "comment_id": 3161853491,
311+ "created_at": "2025-08-06T22:51:42Z",
312+ "repoId": 987670088,
313+ "pullRequestNo": 620
318+ "comment_id": 3163327861,
319+ "created_at": "2025-08-07T09:39:26Z",
320+ "repoId": 987670088,
321+ "pullRequestNo": 628
326+ "comment_id": 3164728921,
327+ "created_at": "2025-08-07T15:33:23Z",
328+ "repoId": 987670088,
329+ "pullRequestNo": 631
334+ "comment_id": 3165875211,
335+ "created_at": "2025-08-07T21:45:30Z",
336+ "repoId": 987670088,
337+ "pullRequestNo": 638
340+ "name": "maxjustus",
342+ "comment_id": 3166599830,
343+ "created_at": "2025-08-08T05:12:37Z",
344+ "repoId": 987670088,
345+ "pullRequestNo": 645
348+ "name": "akaytatsu",
350+ "comment_id": 3167400968,
351+ "created_at": "2025-08-08T10:32:51Z",
352+ "repoId": 987670088,
353+ "pullRequestNo": 647
356+ "name": "theguy000",
358+ "comment_id": 3167442675,
359+ "created_at": "2025-08-08T10:46:15Z",
360+ "repoId": 987670088,
361+ "pullRequestNo": 648
364+ "name": "pwnintended",
366+ "comment_id": 3169309904,
367+ "created_at": "2025-08-08T21:08:45Z",
368+ "repoId": 987670088,
369+ "pullRequestNo": 668
374+ "comment_id": 3169412729,
375+ "created_at": "2025-08-08T22:05:40Z",
376+ "repoId": 987670088,
377+ "pullRequestNo": 672
382+ "comment_id": 3170486027,
383+ "created_at": "2025-08-09T08:15:27Z",
384+ "repoId": 987670088,
385+ "pullRequestNo": 681
388+ "name": "jamestrew",
390+ "comment_id": 3171975481,
391+ "created_at": "2025-08-09T17:55:31Z",
392+ "repoId": 987670088,
393+ "pullRequestNo": 689
398+ "comment_id": 3172676799,
399+ "created_at": "2025-08-10T14:35:04Z",
400+ "repoId": 987670088,
401+ "pullRequestNo": 702
406+ "comment_id": 3181859171,
407+ "created_at": "2025-08-13T01:01:30Z",
408+ "repoId": 987670088,
409+ "pullRequestNo": 746
412+ "name": "samiulsami",
414+ "comment_id": 3189231059,
415+ "created_at": "2025-08-14T17:12:20Z",
416+ "repoId": 987670088,
417+ "pullRequestNo": 779
420+ "name": "neomantra",
422+ "comment_id": 3189674073,
423+ "created_at": "2025-08-14T19:42:53Z",
424+ "repoId": 987670088,
425+ "pullRequestNo": 752
430+ "comment_id": 3190313833,
431+ "created_at": "2025-08-15T00:58:11Z",
432+ "repoId": 987670088,
433+ "pullRequestNo": 782
436+ "name": "lpmitchell",
438+ "comment_id": 3191789654,
439+ "created_at": "2025-08-15T15:23:59Z",
440+ "repoId": 987670088,
441+ "pullRequestNo": 790
444+ "name": "marcosktsz",
446+ "comment_id": 3193569650,
447+ "created_at": "2025-08-16T10:29:10Z",
448+ "repoId": 987670088,
449+ "pullRequestNo": 798
452+ "name": "sainadh-d",
454+ "comment_id": 3193680786,
455+ "created_at": "2025-08-16T13:49:03Z",
456+ "repoId": 987670088,
457+ "pullRequestNo": 803
460+ "name": "ericcoleta",
462+ "comment_id": 3201263288,
463+ "created_at": "2025-08-19T15:38:48Z",
464+ "repoId": 987670088,
465+ "pullRequestNo": 835
470+ "comment_id": 3209540243,
471+ "created_at": "2025-08-21T08:29:20Z",
472+ "repoId": 987670088,
473+ "pullRequestNo": 850
476+ "name": "khareyash05",
478+ "comment_id": 3213528951,
479+ "created_at": "2025-08-22T08:26:23Z",
480+ "repoId": 987670088,
481+ "pullRequestNo": 860
486+ "comment_id": 3214796891,
487+ "created_at": "2025-08-22T15:35:12Z",
488+ "repoId": 987670088,
489+ "pullRequestNo": 865
492+ "name": "xPrimeTime",
494+ "comment_id": 3217970106,
495+ "created_at": "2025-08-24T09:28:11Z",
496+ "repoId": 987670088,
497+ "pullRequestNo": 873
500+ "name": "mercmobily",
502+ "comment_id": 3219992206,
503+ "created_at": "2025-08-25T12:00:54Z",
504+ "repoId": 987670088,
505+ "pullRequestNo": 882
510+ "comment_id": 3221119175,
511+ "created_at": "2025-08-25T17:26:06Z",
512+ "repoId": 987670088,
513+ "pullRequestNo": 892
516+ "name": "henrebotha",
518+ "comment_id": 3223793535,
519+ "created_at": "2025-08-26T11:34:17Z",
520+ "repoId": 987670088,
521+ "pullRequestNo": 900
526+ "comment_id": 3232462357,
527+ "created_at": "2025-08-28T08:23:46Z",
528+ "repoId": 987670088,
529+ "pullRequestNo": 914
534+ "comment_id": 3235052544,
535+ "created_at": "2025-08-28T21:53:00Z",
536+ "repoId": 987670088,
537+ "pullRequestNo": 921
540+ "name": "andersonjoseph",
542+ "comment_id": 3237655829,
543+ "created_at": "2025-08-29T16:54:00Z",
544+ "repoId": 987670088,
545+ "pullRequestNo": 926
550+ "comment_id": 3240239275,
551+ "created_at": "2025-08-31T15:58:52Z",
552+ "repoId": 987670088,
553+ "pullRequestNo": 944
558+ "comment_id": 3259367914,
559+ "created_at": "2025-09-05T18:29:58Z",
560+ "repoId": 987670088,
561+ "pullRequestNo": 968
564+ "name": "vadiminshakov",
566+ "comment_id": 3267808993,
567+ "created_at": "2025-09-08T20:13:33Z",
568+ "repoId": 987670088,
569+ "pullRequestNo": 998
574+ "comment_id": 3270041072,
575+ "created_at": "2025-09-09T10:30:49Z",
576+ "repoId": 987670088,
577+ "pullRequestNo": 1000
580+ "name": "SubodhSenpai",
582+ "comment_id": 3275351636,
583+ "created_at": "2025-09-10T14:55:25Z",
584+ "repoId": 987670088,
585+ "pullRequestNo": 1008
588+ "name": "tauraamui",
590+ "comment_id": 3279503814,
591+ "created_at": "2025-09-11T09:31:52Z",
592+ "repoId": 987670088,
593+ "pullRequestNo": 1016
598+ "comment_id": 3282025022,
599+ "created_at": "2025-09-11T17:37:57Z",
600+ "repoId": 987670088,
601+ "pullRequestNo": 1017
606+ "comment_id": 3285628360,
607+ "created_at": "2025-09-12T15:00:12Z",
608+ "repoId": 987670088,
609+ "pullRequestNo": 1025
612+ "name": "WhiskeyJack96",
614+ "comment_id": 3290164209,
615+ "created_at": "2025-09-15T01:16:08Z",
616+ "repoId": 987670088,
617+ "pullRequestNo": 1037
622+ "comment_id": 3290570050,
623+ "created_at": "2025-09-15T05:42:29Z",
624+ "repoId": 987670088,
625+ "pullRequestNo": 1042
630+ "comment_id": 3296702457,
631+ "created_at": "2025-09-16T08:48:17Z",
632+ "repoId": 987670088,
633+ "pullRequestNo": 1056
636+ "name": "khushveer007",
638+ "comment_id": 3301369568,
639+ "created_at": "2025-09-17T05:32:53Z",
640+ "repoId": 987670088,
641+ "pullRequestNo": 1065
644+ "name": "msteinert",
646+ "comment_id": 3312218015,
647+ "created_at": "2025-09-19T13:31:42Z",
648+ "repoId": 987670088,
649+ "pullRequestNo": 1084
654+ "comment_id": 3314945939,
655+ "created_at": "2025-09-20T12:37:42Z",
656+ "repoId": 987670088,
657+ "pullRequestNo": 1095
662+ "comment_id": 3338743039,
663+ "created_at": "2025-09-26T13:30:16Z",
664+ "repoId": 987670088,
665+ "pullRequestNo": 1135
670+ "comment_id": 3341700737,
671+ "created_at": "2025-09-27T13:09:22Z",
672+ "repoId": 987670088,
673+ "pullRequestNo": 1141
678+ "comment_id": 3344526018,
679+ "created_at": "2025-09-29T01:19:40Z",
680+ "repoId": 987670088,
681+ "pullRequestNo": 1148
684+ "name": "kucukkanat",
686+ "comment_id": 3369230313,
687+ "created_at": "2025-10-05T18:13:57Z",
688+ "repoId": 987670088,
689+ "pullRequestNo": 1195
694+ "comment_id": 3369149503,
695+ "created_at": "2025-10-05T15:59:55Z",
696+ "repoId": 987670088,
697+ "pullRequestNo": 1194
702+ "comment_id": 3373586148,
703+ "created_at": "2025-10-06T19:31:50Z",
704+ "repoId": 987670088,
705+ "pullRequestNo": 1200
710+ "comment_id": 3395964275,
711+ "created_at": "2025-10-13T05:56:20Z",
712+ "repoId": 987670088,
713+ "pullRequestNo": 1223
716+ "name": "BrunoKrugel",
718+ "comment_id": 3411978929,
719+ "created_at": "2025-10-16T17:30:07Z",
720+ "repoId": 987670088,
721+ "pullRequestNo": 1245
724+ "name": "dpolishuk",
726+ "comment_id": 3418756045,
727+ "created_at": "2025-10-18T19:24:00Z",
728+ "repoId": 987670088,
729+ "pullRequestNo": 1254
732+ "name": "Jesssullivan",
734+ "comment_id": 3439361465,
735+ "created_at": "2025-10-23T21:50:17Z",
736+ "repoId": 987670088,
737+ "pullRequestNo": 1292
742+ "comment_id": 3440286180,
743+ "created_at": "2025-10-24T01:32:47Z",
744+ "repoId": 987670088,
745+ "pullRequestNo": 1294
750+ "comment_id": 3444483981,
751+ "created_at": "2025-10-24T18:59:01Z",
752+ "repoId": 987670088,
753+ "pullRequestNo": 1296
756+ "name": "Supratim69",
758+ "comment_id": 3444891894,
759+ "created_at": "2025-10-24T20:58:01Z",
760+ "repoId": 987670088,
761+ "pullRequestNo": 1299
766+ "comment_id": 3446669312,
767+ "created_at": "2025-10-25T12:52:04Z",
768+ "repoId": 987670088,
769+ "pullRequestNo": 1302
774+ "comment_id": 3456210693,
775+ "created_at": "2025-10-28T12:24:21Z",
776+ "repoId": 987670088,
777+ "pullRequestNo": 1312
780+ "name": "bradflaugher",
782+ "comment_id": 3458922489,
783+ "created_at": "2025-10-28T23:13:15Z",
784+ "repoId": 987670088,
785+ "pullRequestNo": 1324
790+ "comment_id": 3465825058,
791+ "created_at": "2025-10-30T02:04:26Z",
792+ "repoId": 987670088,
793+ "pullRequestNo": 1335
796+ "name": "heynemann",
798+ "comment_id": 3475594747,
799+ "created_at": "2025-11-01T03:21:03Z",
800+ "repoId": 987670088,
801+ "pullRequestNo": 1357
804+ "name": "niklasschaeffer",
806+ "comment_id": 3476119118,
807+ "created_at": "2025-11-01T10:06:05Z",
808+ "repoId": 987670088,
809+ "pullRequestNo": 1358
812+ "name": "LarsArtmann",
814+ "comment_id": 3488527230,
815+ "created_at": "2025-11-05T00:18:02Z",
816+ "repoId": 987670088,
817+ "pullRequestNo": 1384
820+ "name": "danielmerja",
822+ "comment_id": 3492618827,
823+ "created_at": "2025-11-05T17:59:51Z",
824+ "repoId": 987670088,
825+ "pullRequestNo": 1387
828+ "name": "nanvenomous",
830+ "comment_id": 3497693075,
831+ "created_at": "2025-11-06T15:05:00Z",
832+ "repoId": 987670088,
833+ "pullRequestNo": 1392
836+ "name": "novalis78",
838+ "comment_id": 3506836115,
839+ "created_at": "2025-11-08T19:53:10Z",
840+ "repoId": 987670088,
841+ "pullRequestNo": 1408
844+ "name": "alewtschuk",
846+ "comment_id": 3520127241,
847+ "created_at": "2025-11-12T05:44:54Z",
848+ "repoId": 987670088,
849+ "pullRequestNo": 1429
854+ "comment_id": 3536325469,
855+ "created_at": "2025-11-15T10:46:24Z",
856+ "repoId": 987670088,
857+ "pullRequestNo": 1450
862+ "comment_id": 3539345738,
863+ "created_at": "2025-11-16T20:55:47Z",
864+ "repoId": 987670088,
865+ "pullRequestNo": 1457
868+ "name": "micahwalter",
870+ "comment_id": 3553482361,
871+ "created_at": "2025-11-19T15:59:07Z",
872+ "repoId": 987670088,
873+ "pullRequestNo": 1478
876+ "name": "heimoshuiyu",
878+ "comment_id": 3565689668,
879+ "created_at": "2025-11-22T05:23:17Z",
880+ "repoId": 987670088,
881+ "pullRequestNo": 1496
884+ "name": "masroor-ahmad",
886+ "comment_id": 3592527587,
887+ "created_at": "2025-11-30T12:55:09Z",
888+ "repoId": 987670088,
889+ "pullRequestNo": 1532
894+ "comment_id": 3595049411,
895+ "created_at": "2025-12-01T07:39:02Z",
896+ "repoId": 987670088,
897+ "pullRequestNo": 1534
900+ "name": "marifcelik",
902+ "comment_id": 3610641638,
903+ "created_at": "2025-12-04T07:17:10Z",
904+ "repoId": 987670088,
905+ "pullRequestNo": 1546
910+ "comment_id": 3615055552,
911+ "created_at": "2025-12-05T02:26:29Z",
912+ "repoId": 987670088,
913+ "pullRequestNo": 1553
918+ "comment_id": 3617461839,
919+ "created_at": "2025-12-05T15:51:04Z",
920+ "repoId": 987670088,
921+ "pullRequestNo": 1555
926+ "comment_id": 3620605876,
927+ "created_at": "2025-12-06T15:43:45Z",
928+ "repoId": 987670088,
929+ "pullRequestNo": 1558
932+ "name": "Gustave-241021",
934+ "comment_id": 3620851967,
935+ "created_at": "2025-12-06T18:13:11Z",
936+ "repoId": 987670088,
937+ "pullRequestNo": 1560
942+ "comment_id": 3636765109,
943+ "created_at": "2025-12-10T12:04:50Z",
944+ "repoId": 987670088,
945+ "pullRequestNo": 1592
948+ "name": "nonsleepr",
950+ "comment_id": 3644171671,
951+ "created_at": "2025-12-11T23:09:21Z",
952+ "repoId": 987670088,
953+ "pullRequestNo": 1611
956+ "name": "strawberry-code",
958+ "comment_id": 3650628850,
959+ "created_at": "2025-12-14T09:41:12Z",
960+ "repoId": 987670088,
961+ "pullRequestNo": 1628
964+ "name": "flatsponge",
966+ "comment_id": 3673002560,
967+ "created_at": "2025-12-19T01:11:45Z",
968+ "repoId": 987670088,
969+ "pullRequestNo": 1668
974+ "comment_id": 3674853134,
975+ "created_at": "2025-12-19T12:14:08Z",
976+ "repoId": 987670088,
977+ "pullRequestNo": 1675
980+ "name": "Mr777x-enf",
982+ "comment_id": 3682737876,
983+ "created_at": "2025-12-22T16:07:47Z",
984+ "repoId": 987670088,
985+ "pullRequestNo": 1694
990+ "comment_id": 3687495909,
991+ "created_at": "2025-12-23T17:59:11Z",
992+ "repoId": 987670088,
993+ "pullRequestNo": 1709
998+ "comment_id": 3693734613,
999+ "created_at": "2025-12-27T06:01:58Z",
1000+ "repoId": 987670088,
1001+ "pullRequestNo": 1723
1004+ "name": "nikolayk812",
1006+ "comment_id": 3704102069,
1007+ "created_at": "2026-01-01T21:00:07Z",
1008+ "repoId": 987670088,
1009+ "pullRequestNo": 1748
1012+ "name": "mohaanymo",
1014+ "comment_id": 3725028621,
1015+ "created_at": "2026-01-08T18:01:11Z",
1016+ "repoId": 987670088,
1017+ "pullRequestNo": 1799
1022+ "comment_id": 3725966281,
1023+ "created_at": "2026-01-08T21:44:05Z",
1024+ "repoId": 987670088,
1025+ "pullRequestNo": 1801
1028+ "name": "aleksclark",
1030+ "comment_id": 3729687747,
1031+ "created_at": "2026-01-09T16:28:21Z",
1032+ "repoId": 987670088,
1033+ "pullRequestNo": 1811
1036+ "name": "jeis4wpi",
1038+ "comment_id": 3735501265,
1039+ "created_at": "2026-01-11T19:19:03Z",
1040+ "repoId": 987670088,
1041+ "pullRequestNo": 1827
1046+ "comment_id": 3738688581,
1047+ "created_at": "2026-01-12T13:58:05Z",
1048+ "repoId": 987670088,
1049+ "pullRequestNo": 1830
1052+ "name": "andreasdotorg",
1054+ "comment_id": 3740767910,
1055+ "created_at": "2026-01-12T22:16:05Z",
1056+ "repoId": 987670088,
1057+ "pullRequestNo": 1841
1062+ "comment_id": 3747622477,
1063+ "created_at": "2026-01-14T04:18:44Z",
1064+ "repoId": 987670088,
1065+ "pullRequestNo": 1864
1070+ "comment_id": 3749703014,
1071+ "created_at": "2026-01-14T14:02:04Z",
1072+ "repoId": 987670088,
1073+ "pullRequestNo": 1870
1076+ "name": "huaiyuWangh",
1078+ "comment_id": 3785195950,
1079+ "created_at": "2026-01-22T15:58:33Z",
1080+ "repoId": 987670088,
1081+ "pullRequestNo": 1943
1084+ "name": "akitaonrails",
1086+ "comment_id": 3786408984,
1087+ "created_at": "2026-01-22T19:57:59Z",
1088+ "repoId": 987670088,
1089+ "pullRequestNo": 1945
1094+ "comment_id": 3787591535,
1095+ "created_at": "2026-01-23T00:44:49Z",
1096+ "repoId": 987670088,
1097+ "pullRequestNo": 1950
1100+ "name": "jerilynzheng",
1102+ "comment_id": 3788071777,
1103+ "created_at": "2026-01-23T04:00:52Z",
1104+ "repoId": 987670088,
1105+ "pullRequestNo": 1951
1110+ "comment_id": 3791901071,
1111+ "created_at": "2026-01-23T19:14:55Z",
1112+ "repoId": 987670088,
1113+ "pullRequestNo": 1967
1116+ "name": "billycao",
1118+ "comment_id": 3793624061,
1119+ "created_at": "2026-01-24T03:06:50Z",
1120+ "repoId": 987670088,
1121+ "pullRequestNo": 1971
1126+ "comment_id": 3795660594,
1127+ "created_at": "2026-01-24T22:42:46Z",
1128+ "repoId": 987670088,
1129+ "pullRequestNo": 1978
1134+ "comment_id": 3811704206,
1135+ "created_at": "2026-01-28T14:42:29Z",
1136+ "repoId": 987670088,
1137+ "pullRequestNo": 2022
1140+ "name": "liannnix",
1142+ "comment_id": 3815867093,
1143+ "created_at": "2026-01-29T07:05:12Z",
1144+ "repoId": 987670088,
1145+ "pullRequestNo": 2043
1150+ "comment_id": 3824931235,
1151+ "created_at": "2026-01-30T17:52:15Z",
1152+ "repoId": 987670088,
1153+ "pullRequestNo": 2065
1158+ "comment_id": 3832667774,
1159+ "created_at": "2026-02-02T03:06:23Z",
1160+ "repoId": 987670088,
1161+ "pullRequestNo": 2080
1164+ "name": "khalilgharbaoui",
1166+ "comment_id": 3832796060,
1167+ "created_at": "2026-02-02T04:04:04Z",
1168+ "repoId": 987670088,
1169+ "pullRequestNo": 2081
1172+ "name": "acmacalister",
1174+ "comment_id": 3837172797,
1175+ "created_at": "2026-02-02T19:27:08Z",
1176+ "repoId": 987670088,
1177+ "pullRequestNo": 2095
1180+ "name": "zhiquanchi",
1182+ "comment_id": 3845838711,
1183+ "created_at": "2026-02-04T07:39:06Z",
1184+ "repoId": 987670088,
1185+ "pullRequestNo": 2112
1190+ "comment_id": 3849304908,
1191+ "created_at": "2026-02-04T19:22:33Z",
1192+ "repoId": 987670088,
1193+ "pullRequestNo": 2124
1196+ "name": "nickgrim",
1198+ "comment_id": 3852565144,
1199+ "created_at": "2026-02-05T10:17:46Z",
1200+ "repoId": 987670088,
1201+ "pullRequestNo": 2131
1204+ "name": "francescoalemanno",
1206+ "comment_id": 3858464719,
1207+ "created_at": "2026-02-06T07:16:50Z",
1208+ "repoId": 987670088,
1209+ "pullRequestNo": 2142
1214+ "comment_id": 3866503536,
1215+ "created_at": "2026-02-08T08:15:11Z",
1216+ "repoId": 987670088,
1217+ "pullRequestNo": 2164
1220+ "name": "mishudark",
1222+ "comment_id": 3866939317,
1223+ "created_at": "2026-02-08T10:27:09Z",
1224+ "repoId": 987670088,
1225+ "pullRequestNo": 2165
1228+ "name": "portertech",
1230+ "comment_id": 3878650318,
1231+ "created_at": "2026-02-10T15:39:14Z",
1232+ "repoId": 987670088,
1233+ "pullRequestNo": 2183
1236+ "name": "wallacegibbon",
1238+ "comment_id": 3890517245,
1239+ "created_at": "2026-02-12T11:58:04Z",
1240+ "repoId": 987670088,
1241+ "pullRequestNo": 2203
1244+ "name": "PHPCraftdream",
1246+ "comment_id": 3893502046,
1247+ "created_at": "2026-02-12T21:34:20Z",
1248+ "repoId": 987670088,
1249+ "pullRequestNo": 2212
1252+ "name": "maxbrunet",
1254+ "comment_id": 3905030983,
1255+ "created_at": "2026-02-15T19:14:26Z",
1256+ "repoId": 987670088,
1257+ "pullRequestNo": 2229
1260+ "name": "0xarcher",
1262+ "comment_id": 3907297580,
1263+ "created_at": "2026-02-16T09:16:57Z",
1264+ "repoId": 987670088,
1265+ "pullRequestNo": 2236
1268+ "name": "julienrbrt",
1270+ "comment_id": 3920039276,
1271+ "created_at": "2026-02-18T10:37:53Z",
1272+ "repoId": 987670088,
1273+ "pullRequestNo": 2246
1276+ "name": "erikstmartin",
1278+ "comment_id": 3937646631,
1279+ "created_at": "2026-02-20T23:35:55Z",
1280+ "repoId": 987670088,
1281+ "pullRequestNo": 2274
1284+ "name": "Jaylonnet",
1286+ "comment_id": 3944717192,
1287+ "created_at": "2026-02-23T13:12:50Z",
1288+ "repoId": 987670088,
1289+ "pullRequestNo": 2293
1294+ "comment_id": 3966463081,
1295+ "created_at": "2026-02-26T12:56:51Z",
1296+ "repoId": 987670088,
1297+ "pullRequestNo": 2314
1302+ "comment_id": 3968065934,
1303+ "created_at": "2026-02-26T17:23:44Z",
1304+ "repoId": 987670088,
1305+ "pullRequestNo": 2315
1310+ "comment_id": 3976601253,
1311+ "created_at": "2026-02-28T07:36:40Z",
1312+ "repoId": 987670088,
1313+ "pullRequestNo": 2326
1316+ "name": "taoeffect",
1318+ "comment_id": 3979067985,
1319+ "created_at": "2026-03-01T04:22:00Z",
1320+ "repoId": 987670088,
1321+ "pullRequestNo": 2333
1326+ "comment_id": 3980616480,
1327+ "created_at": "2026-03-01T17:51:04Z",
1328+ "repoId": 987670088,
1329+ "pullRequestNo": 2337
1332+ "name": "ZeitbyteRepo",
1334+ "comment_id": 4025287397,
1335+ "created_at": "2026-03-09T17:00:06Z",
1336+ "repoId": 987670088,
1337+ "pullRequestNo": 2390
1340+ "name": "seroperson",
1342+ "comment_id": 4047392328,
1343+ "created_at": "2026-03-12T14:53:20Z",
1344+ "repoId": 987670088,
1345+ "pullRequestNo": 2401
1348+ "name": "xulongwu4",
1350+ "comment_id": 4062024320,
1351+ "created_at": "2026-03-15T02:30:55Z",
1352+ "repoId": 987670088,
1353+ "pullRequestNo": 2410
1356+ "name": "nghiant03",
1358+ "comment_id": 4077213520,
1359+ "created_at": "2026-03-17T18:41:50Z",
1360+ "repoId": 987670088,
1361+ "pullRequestNo": 2421
1364+ "name": "whatnick",
1366+ "comment_id": 4102155868,
1367+ "created_at": "2026-03-21T03:49:12Z",
1368+ "repoId": 987670088,
1369+ "pullRequestNo": 2449
1372+ "name": "Alex-wuhu",
1374+ "comment_id": 4106451941,
1375+ "created_at": "2026-03-22T15:26:05Z",
1376+ "repoId": 987670088,
1377+ "pullRequestNo": 2454
1380+ "name": "hongquan",
1382+ "comment_id": 4112122644,
1383+ "created_at": "2026-03-23T16:51:09Z",
1384+ "repoId": 987670088,
1385+ "pullRequestNo": 2462
1390+ "comment_id": 4113326932,
1391+ "created_at": "2026-03-23T19:57:54Z",
1392+ "repoId": 987670088,
1393+ "pullRequestNo": 2465
1396+ "name": "UnderLotus",
1398+ "comment_id": 4118727062,
1399+ "created_at": "2026-03-24T14:25:40Z",
1400+ "repoId": 987670088,
1401+ "pullRequestNo": 2475
1404+ "name": "malikwirin",
1406+ "comment_id": 4119816035,
1407+ "created_at": "2026-03-24T16:51:44Z",
1408+ "repoId": 987670088,
1409+ "pullRequestNo": 2476
1412+ "name": "fuleinist",
1414+ "comment_id": 4133146531,
1415+ "created_at": "2026-03-26T09:45:48Z",
1416+ "repoId": 987670088,
1417+ "pullRequestNo": 2492
1420+ "name": "iceymoss",
1422+ "comment_id": 4134659508,
1423+ "created_at": "2026-03-26T13:13:25Z",
1424+ "repoId": 987670088,
1425+ "pullRequestNo": 2493
1428+ "name": "srivilliamsai",
1430+ "comment_id": 4144200398,
1431+ "created_at": "2026-03-27T17:37:29Z",
1432+ "repoId": 987670088,
1433+ "pullRequestNo": 2511
1436+ "name": "Dexterity104",
1438+ "comment_id": 4153067126,
1439+ "created_at": "2026-03-30T08:05:56Z",
1440+ "repoId": 987670088,
1441+ "pullRequestNo": 2525
1444+ "name": "majiayu000",
1446+ "comment_id": 4160074332,
1447+ "created_at": "2026-03-31T05:44:38Z",
1448+ "repoId": 987670088,
1449+ "pullRequestNo": 2534
1452+ "name": "afsuyadi",
1454+ "comment_id": 4160431726,
1455+ "created_at": "2026-03-31T07:10:20Z",
1456+ "repoId": 987670088,
1457+ "pullRequestNo": 2532
1460+ "name": "owldev127",
1462+ "comment_id": 4161299761,
1463+ "created_at": "2026-03-31T09:44:52Z",
1464+ "repoId": 987670088,
1465+ "pullRequestNo": 2538
1470+ "comment_id": 4168509138,
1471+ "created_at": "2026-04-01T08:44:22Z",
1472+ "repoId": 987670088,
1473+ "pullRequestNo": 2544
1476+ "name": "Kartik33",
1478+ "comment_id": 4181386196,
1479+ "created_at": "2026-04-03T02:02:31Z",
1480+ "repoId": 987670088,
1481+ "pullRequestNo": 2554
1486+ "comment_id": 4182808517,
1487+ "created_at": "2026-04-03T09:56:29Z",
1488+ "repoId": 987670088,
1489+ "pullRequestNo": 2555
1492+ "name": "avianion",
1494+ "comment_id": 4186934644,
1495+ "created_at": "2026-04-04T10:54:16Z",
1496+ "repoId": 987670088,
1497+ "pullRequestNo": 2557
1500+ "name": "shahidshabbir-se",
1502+ "comment_id": 4191066791,
1503+ "created_at": "2026-04-06T08:11:08Z",
1504+ "repoId": 987670088,
1505+ "pullRequestNo": 2563
1510+ "comment_id": 4200126763,
1511+ "created_at": "2026-04-07T15:22:15Z",
1512+ "repoId": 987670088,
1513+ "pullRequestNo": 2575
1518+ "comment_id": 4216941498,
1519+ "created_at": "2026-04-09T19:22:39Z",
1520+ "repoId": 987670088,
1521+ "pullRequestNo": 2593
1524+ "name": "dshumphr",
1526+ "comment_id": 4229412078,
1527+ "created_at": "2026-04-11T12:20:44Z",
1528+ "repoId": 987670088,
1529+ "pullRequestNo": 2601
1532+ "name": "bensantora",
1534+ "comment_id": 4229507403,
1535+ "created_at": "2026-04-11T13:31:32Z",
1536+ "repoId": 987670088,
1537+ "pullRequestNo": 2602
1542+ "comment_id": 4231674482,
1543+ "created_at": "2026-04-12T14:14:41Z",
1544+ "repoId": 987670088,
1545+ "pullRequestNo": 2606
1548+ "name": "KimBioInfoStudio",
1550+ "comment_id": 4244355652,
1551+ "created_at": "2026-04-14T13:43:55Z",
1552+ "repoId": 987670088,
1553+ "pullRequestNo": 2622
1556+ "name": "taigong12",
1558+ "comment_id": 4259818851,
1559+ "created_at": "2026-04-16T11:50:25Z",
1560+ "repoId": 987670088,
1561+ "pullRequestNo": 2634
1566+ "comment_id": 4271523344,
1567+ "created_at": "2026-04-17T21:52:43Z",
1568+ "repoId": 987670088,
1569+ "pullRequestNo": 2643
1574+ "comment_id": 4272340887,
1575+ "created_at": "2026-04-18T01:47:04Z",
1576+ "repoId": 987670088,
1577+ "pullRequestNo": 2646
1582+ "comment_id": 4285449550,
1583+ "created_at": "2026-04-21T02:02:06Z",
1584+ "repoId": 987670088,
1585+ "pullRequestNo": 2612
1590+ "comment_id": 4293455788,
1591+ "created_at": "2026-04-22T04:15:18Z",
1592+ "repoId": 987670088,
1593+ "pullRequestNo": 2674
1598+ "comment_id": 4298985284,
1599+ "created_at": "2026-04-22T18:33:08Z",
1600+ "repoId": 987670088,
1601+ "pullRequestNo": 2681
1606+ "comment_id": 4303280163,
1607+ "created_at": "2026-04-23T09:29:30Z",
1608+ "repoId": 987670088,
1609+ "pullRequestNo": 2686
1612+ "name": "flynn-eye",
1614+ "comment_id": 4304378619,
1615+ "created_at": "2026-04-23T12:33:57Z",
1616+ "repoId": 987670088,
1617+ "pullRequestNo": 2688
1620+ "name": "georgeglarson",
1622+ "comment_id": 4341592963,
1623+ "created_at": "2026-04-29T07:08:48Z",
1624+ "repoId": 987670088,
1625+ "pullRequestNo": 2749
1628+ "name": "vorticalbox",
1630+ "comment_id": 4344669740,
1631+ "created_at": "2026-04-29T14:29:35Z",
1632+ "repoId": 987670088,
1633+ "pullRequestNo": 2751
1636+ "name": "lloydzhou",
1638+ "comment_id": 4346011097,
1639+ "created_at": "2026-04-29T17:27:37Z",
1640+ "repoId": 987670088,
1641+ "pullRequestNo": 2752
1644+ "name": "carlosgrillet",
1646+ "comment_id": 4351020450,
1647+ "created_at": "2026-04-30T08:48:52Z",
1648+ "repoId": 987670088,
1649+ "pullRequestNo": 2759
1654+ "comment_id": 4357189565,
1655+ "created_at": "2026-05-01T01:00:00Z",
1656+ "repoId": 987670088,
1657+ "pullRequestNo": 2691
1662+ "comment_id": 4358493210,
1663+ "created_at": "2026-05-01T08:25:06Z",
1664+ "repoId": 987670088,
1665+ "pullRequestNo": 2772
1668+ "name": "pragneshbagary",
1670+ "comment_id": 4359152162,
1671+ "created_at": "2026-05-01T11:54:16Z",
1672+ "repoId": 987670088,
1673+ "pullRequestNo": 2773
1676+ "name": "somjik-api",
1678+ "comment_id": 4364741275,
1679+ "created_at": "2026-05-02T21:17:55Z",
1680+ "repoId": 987670088,
1681+ "pullRequestNo": 2783
1686+ "comment_id": 4367211073,
1687+ "created_at": "2026-05-03T21:25:46Z",
1688+ "repoId": 987670088,
1689+ "pullRequestNo": 2790
1694+ "comment_id": 4377260996,
1695+ "created_at": "2026-05-05T07:22:31Z",
1696+ "repoId": 987670088,
1697+ "pullRequestNo": 2801
1700+ "name": "yeonuk-hwang",
1702+ "comment_id": 4407666773,
1703+ "created_at": "2026-05-08T15:33:03Z",
1704+ "repoId": 987670088,
1705+ "pullRequestNo": 2836
1708+ "name": "sven2718",
1710+ "comment_id": 4410098922,
1711+ "created_at": "2026-05-08T21:47:18Z",
1712+ "repoId": 987670088,
1713+ "pullRequestNo": 2840
1716+ "name": "acheong08",
1718+ "comment_id": 4410600427,
1719+ "created_at": "2026-05-08T23:37:33Z",
1720+ "repoId": 987670088,
1721+ "pullRequestNo": 2842
1724+ "name": "smeinecke",
1726+ "comment_id": 4411012852,
1727+ "created_at": "2026-05-09T01:47:08Z",
1728+ "repoId": 987670088,
1729+ "pullRequestNo": 2844
1734+ "comment_id": 4432309551,
1735+ "created_at": "2026-05-12T15:48:38Z",
1736+ "repoId": 987670088,
1737+ "pullRequestNo": 2886
1740+ "name": "johnjansen",
1742+ "comment_id": 4434007350,
1743+ "created_at": "2026-05-12T19:28:01Z",
1744+ "repoId": 987670088,
1745+ "pullRequestNo": 2887
1750+ "comment_id": 4435307961,
1751+ "created_at": "2026-05-12T22:25:09Z",
1752+ "repoId": 987670088,
1753+ "pullRequestNo": 2892
1756+ "name": "akhenakh",
1758+ "comment_id": 4446905473,
1759+ "created_at": "2026-05-14T02:28:13Z",
1760+ "repoId": 987670088,
1761+ "pullRequestNo": 2912
1764+ "name": "leonardoaraujosantos",
1766+ "comment_id": 3166308642,
1767+ "created_at": "2025-08-08T01:40:17Z",
1768+ "repoId": 987670088,
1769+ "pullRequestNo": 644
1772+ "name": "yookibooki",
1774+ "comment_id": 4459665029,
1775+ "created_at": "2026-05-15T12:16:26Z",
1776+ "repoId": 987670088,
1777+ "pullRequestNo": 2922
1782+ "comment_id": 4461676513,
1783+ "created_at": "2026-05-15T16:58:04Z",
1784+ "repoId": 987670088,
1785+ "pullRequestNo": 2925
1788+ "name": "Broderick-Westrope",
1790+ "comment_id": 4469173328,
1791+ "created_at": "2026-05-17T03:35:13Z",
1792+ "repoId": 987670088,
1793+ "pullRequestNo": 2937
1796+ "name": "processtrader",
1798+ "comment_id": 4480941961,
1799+ "created_at": "2026-05-18T18:58:31Z",
1800+ "repoId": 987670088,
1801+ "pullRequestNo": 2950
1806+ "comment_id": 4484181213,
1807+ "created_at": "2026-05-19T03:37:32Z",
1808+ "repoId": 987670088,
1809+ "pullRequestNo": 2954
1812+ "name": "mei2jun1",
1814+ "comment_id": 4495440988,
1815+ "created_at": "2026-05-20T06:53:43Z",
1816+ "repoId": 987670088,
1817+ "pullRequestNo": 2964
1822+ "comment_id": 4513096006,
1823+ "created_at": "2026-05-21T21:56:14Z",
1824+ "repoId": 987670088,
1825+ "pullRequestNo": 2979
1828+ "name": "Ricardo-M-L",
1830+ "comment_id": 4514494248,
1831+ "created_at": "2026-05-22T02:37:08Z",
1832+ "repoId": 987670088,
1833+ "pullRequestNo": 2847
1836+ "name": "Muttaqin86",
1838+ "comment_id": 4520181780,
1839+ "created_at": "2026-05-22T15:46:32Z",
1840+ "repoId": 987670088,
1841+ "pullRequestNo": 2984
1844+ "name": "officialasishkumar",
1846+ "comment_id": 4527874300,
1847+ "created_at": "2026-05-24T08:44:14Z",
1848+ "repoId": 987670088,
1849+ "pullRequestNo": 2995
1854+ "comment_id": 4528076561,
1855+ "created_at": "2026-05-24T10:19:27Z",
1856+ "repoId": 987670088,
1857+ "pullRequestNo": 2996
1860+ "name": "xulongzhe",
1862+ "comment_id": 4569454380,
1863+ "created_at": "2026-05-29T00:39:36Z",
1864+ "repoId": 987670088,
1865+ "pullRequestNo": 3036
1870+ "comment_id": 4589172224,
1871+ "created_at": "2026-06-01T02:48:53Z",
1872+ "repoId": 987670088,
1873+ "pullRequestNo": 3049
1876+ "name": "cak3ninja",
1878+ "comment_id": 4596570813,
1879+ "created_at": "2026-06-01T21:14:16Z",
1880+ "repoId": 987670088,
1881+ "pullRequestNo": 3059
1884+ "name": "GroovyCarrot",
1886+ "comment_id": 4623915928,
1887+ "created_at": "2026-06-04T16:01:30Z",
1888+ "repoId": 987670088,
1889+ "pullRequestNo": 3076
1892+ "name": "CnsMaple",
1894+ "comment_id": 4628808493,
1895+ "created_at": "2026-06-05T06:24:00Z",
1896+ "repoId": 987670088,
1897+ "pullRequestNo": 3080
1900+ "name": "yuseferi",
1902+ "comment_id": 4548802420,
1903+ "created_at": "2026-05-26T21:00:36Z",
1904+ "repoId": 987670088,
1905+ "pullRequestNo": 3019
1910+ "comment_id": 4651029942,
1911+ "created_at": "2026-06-08T16:18:06Z",
1912+ "repoId": 987670088,
1913+ "pullRequestNo": 3096
1916+ "name": "brianjlandau",
1918+ "comment_id": 4654867087,
1919+ "created_at": "2026-06-09T00:37:02Z",
1920+ "repoId": 987670088,
1921+ "pullRequestNo": 3098
1926+ "comment_id": 4687904764,
1927+ "created_at": "2026-06-12T05:55:06Z",
1928+ "repoId": 987670088,
1929+ "pullRequestNo": 3111
1932+ "name": "warmjademe",
1934+ "comment_id": 4720070206,
1935+ "created_at": "2026-06-16T14:48:33Z",
1936+ "repoId": 987670088,
1937+ "pullRequestNo": 3131
1940+ "name": "warmjademe",
1942+ "comment_id": 4720177856,
1943+ "created_at": "2026-06-16T14:58:33Z",
1944+ "repoId": 987670088,
1945+ "pullRequestNo": 3131
1948+ "name": "jialudev",
1950+ "comment_id": 4725593255,
1951+ "created_at": "2026-06-17T03:26:00Z",
1952+ "repoId": 987670088,
1953+ "pullRequestNo": 3137
1956+ "name": "knight110001",
1958+ "comment_id": 4741392218,
1959+ "created_at": "2026-06-18T11:16:02Z",
1960+ "repoId": 987670088,
1961+ "pullRequestNo": 3140
1966+ "comment_id": 4755333253,
1967+ "created_at": "2026-06-19T22:56:55Z",
1968+ "repoId": 987670088,
1969+ "pullRequestNo": 3158
1972+ "name": "xorangekiller",
1974+ "comment_id": 4758885426,
1975+ "created_at": "2026-06-20T16:00:01Z",
1976+ "repoId": 987670088,
1977+ "pullRequestNo": 3163
1980+ "name": "sithglan",
1982+ "comment_id": 4761251782,
1983+ "created_at": "2026-06-21T07:28:19Z",
1984+ "repoId": 987670088,
1985+ "pullRequestNo": 3168
1988+ "name": "macro-ss",
1990+ "comment_id": 4729268228,
1991+ "created_at": "2026-06-17T11:09:03Z",
1992+ "repoId": 987670088,
1993+ "pullRequestNo": 3140
1996+ "name": "andrinoff",
1998+ "comment_id": 4772633817,
1999+ "created_at": "2026-06-22T20:13:54Z",
2000+ "repoId": 987670088,
2001+ "pullRequestNo": 3184
2004+ "name": "calyptobai",
2006+ "comment_id": 4774213287,
2007+ "created_at": "2026-06-22T23:56:09Z",
2008+ "repoId": 987670088,
2009+ "pullRequestNo": 3189
2012+ "name": "truffle-dev",
2014+ "comment_id": 4783906418,
2015+ "created_at": "2026-06-23T22:07:28Z",
2016+ "repoId": 987670088,
2017+ "pullRequestNo": 3195
2020+ "name": "chardoncs",
2022+ "comment_id": 4786221902,
2023+ "created_at": "2026-06-24T05:36:39Z",
2024+ "repoId": 987670088,
2025+ "pullRequestNo": 3197
2030+ "comment_id": 4793889316,
2031+ "created_at": "2026-06-24T21:37:51Z",
2032+ "repoId": 987670088,
2033+ "pullRequestNo": 3202
2036+ "name": "vismaytiwari",
2038+ "comment_id": 4797847556,
2039+ "created_at": "2026-06-25T09:38:55Z",
2040+ "repoId": 987670088,
2041+ "pullRequestNo": 3205
2044+ "name": "feizhuzheng",
2046+ "comment_id": 4809880810,
2047+ "created_at": "2026-06-26T13:09:43Z",
2048+ "repoId": 987670088,
2049+ "pullRequestNo": 3211
2054+ "comment_id": 4817246953,
2055+ "created_at": "2026-06-27T11:44:54Z",
2056+ "repoId": 987670088,
2057+ "pullRequestNo": 3221
2060+ "name": "EduardF1",
2062+ "comment_id": 4818319813,
2063+ "created_at": "2026-06-27T14:15:50Z",
2064+ "repoId": 987670088,
2065+ "pullRequestNo": 3133
2070+ "comment_id": 4851979164,
2071+ "created_at": "2026-07-01T08:13:03Z",
2072+ "repoId": 987670088,
2073+ "pullRequestNo": 3235
2076+ "name": "Osamaali313",
2078+ "comment_id": 4870561813,
2079+ "created_at": "2026-07-02T21:19:15Z",
2080+ "repoId": 987670088,
2081+ "pullRequestNo": 3244
2084+ "name": "lockp111",
2086+ "comment_id": 4878248994,
2087+ "created_at": "2026-07-03T17:12:26Z",
2088+ "repoId": 987670088,
2089+ "pullRequestNo": 3247
2092+ "name": "TheRAWagent",
2094+ "comment_id": 4879276761,
2095+ "created_at": "2026-07-03T20:52:00Z",
2096+ "repoId": 987670088,
2097+ "pullRequestNo": 3251
.github/dependabot.yml+18−2
@@ -9,10 +9,22 @@ updates:
9 time: "05:00"
9 time: "05:00"
10 timezone: "America/New_York"
10 timezone: "America/New_York"
12− - "dependencies"
12+ - "area: dependencies"
13 commit-message:
13 commit-message:
14 prefix: "chore"
14 prefix: "chore"
15 include: "scope"
15 include: "scope"
21+ - dependency-name: github.com/charmbracelet/bubbletea/v2
24+ - dependency-name: github.com/charmbracelet/lipgloss/v2
27+ - dependency-name: mvdan.cc/sh/moreinterp
17 - package-ecosystem: "github-actions"
29 - package-ecosystem: "github-actions"
18 directory: "/"
30 directory: "/"
@@ -22,7 +34,11 @@ updates:
22 time: "05:00"
34 time: "05:00"
23 timezone: "America/New_York"
35 timezone: "America/New_York"
25− - "dependencies"
37+ - "area: dependencies"
26 commit-message:
38 commit-message:
27 prefix: "chore"
39 prefix: "chore"
28 include: "scope"
40 include: "scope"
.github/entitlements.plistnew file+8
@@ -0,0 +1,8 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
.github/labeler.ymlnew file+79
@@ -0,0 +1,79 @@
1+# NOTE(@andreynering): We should have a single entry per label, because if we
2+# have multiple the action would only apply the label if ALL of them match.
9+ - "/non-interactive/i"
13+ - "/(docs|documentation|readme)/i"
21+ - "/(mouse|scroll)/i"
27+ - "/(release|releasing|aur|brew|nix|npm|scoop|termux|winget)/i"
37+ - "/(android|termux)/i"
39+ - "/(linux|fedora|debian|ubuntu)/i"
41+ - "/(macos|osx|darwin)/i"
43+ - "/(windows|win10|win11|win32|wsl|scoop|winget)/i"
45+ - "/(panic|crash|segfault)/i"
46+"provider: anthropic claude":
47+ - "/(anthropic|claude)/i"
50+"provider: aws bedrock":
54+"provider: github copilot":
56+"provider: google gemini":
58+"provider: google vertex":
68+"provider: openai chatgpt":
70+"provider: openrouter":
77+ - "/(xai|x\\.ai|grok)/i"
79+ - "/(security|vulnerability|exploit)/i"
.github/workflows/build.yml+24−24
@@ -1,30 +1,30 @@
2−on: [push, pull_request]
2+on:
11+ group: build-${{ github.event.pull_request.number || github.ref }}
12+ cancel-in-progress: true
6− uses: charmbracelet/meta/.github/workflows/build.yml@main
16+ strategy:
8− go-version: ""
18+ os: [ubuntu-latest, macos-latest, windows-latest]
9− go-version-file: ./go.mod
19+ runs-on: ${{ matrix.os }}
11− gh_pat: "${{ secrets.PERSONAL_ACCESS_TOKEN }}"
15− runs-on: ubuntu-latest
19− if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'}}
21− - id: metadata
21+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
22− uses: dependabot/fetch-metadata@v2
22+ with:
23+ persist-credentials: false
24+ - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
24− github-token: "${{ secrets.GITHUB_TOKEN }}"
26+ go-version-file: go.mod
25− - run: |
27+ - run: go mod tidy
26− gh pr review --approve "$PR_URL"
28+ - run: git diff --exit-code
27− gh pr merge --squash --auto "$PR_URL"
29+ - run: go build -race ./...
28− env:
30+ - run: go test -race -failfast ./...
29− PR_URL: ${{github.event.pull_request.html_url}}
30− GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
.github/workflows/cla.ymlnew file+36
@@ -0,0 +1,36 @@
7+ types: [opened, closed, synchronize]
17+ if: github.repository == 'charmbracelet/crush'
18+ runs-on: ubuntu-latest
20+ - name: "CLA Assistant"
22+ github.event.comment.body == 'recheck' ||
23+ github.event.comment.body == 'I have read the Contributor License Agreement (CLA) and hereby sign the CLA.' ||
24+ github.event_name == 'pull_request_target'
25+ uses: contributor-assistant/github-action@58daaf842ac3e26d08c2bdf26770d6e9c5b965a9
27+ GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
29+ path-to-signatures: ".github/cla-signatures.json"
30+ path-to-document: "https://github.com/charmbracelet/crush/blob/main/CLA.md"
32+ allowlist: charmcli,charmcrush,dependabot[bot],Copilot
33+ custom-pr-sign-comment: "I have read the Contributor License Agreement (CLA) and hereby sign the CLA."
34+ custom-notsigned-prcomment: "Thank you for your submission. We really appreciate it! Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/charmbracelet/crush/blob/main/CLA.md) before we can accept your contribution. You can sign the CLA by just posting a Pull Request comment same as the below format."
35+ lock-pullrequest-aftermerge: false
36+ signed-commit-message: "chore(legal): @$contributorName has signed the CLA"
.github/workflows/dependabot-sync.ymldeleted−17
@@ -1,17 +0,0 @@
4− - cron: "0 0 * * 0" # every Sunday at midnight
5− workflow_dispatch: # allows manual triggering
13− uses: charmbracelet/meta/.github/workflows/dependabot-sync.yml@main
15− repo_name: ${{ github.event.repository.name }}
17− gh_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
.github/workflows/labeler.ymlnew file+30
@@ -0,0 +1,30 @@
11+ description: "Issue/PR #"
22+ runs-on: ubuntu-latest
24+ - uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4
26+ configuration-path: .github/labeler.yml
27+ enable-versioned-regex: 0
30+ issue-number: ${{ github.event.inputs.issue-number || github.event.issue.number || github.event.pull_request.number }}
.github/workflows/lint-sync.yml+3−3
@@ -1,8 +1,8 @@
1name: lint-sync
1name: lint-sync
3− schedule:
3+ # schedule:
4− # every Sunday at midnight
4+ # # every Sunday at midnight
5− - cron: "0 0 * * 0"
5+ # - cron: "0 0 * * 0"
6 workflow_dispatch: # allows manual triggering
6 workflow_dispatch: # allows manual triggering
8permissions:
8permissions:
.github/workflows/lint.yml+2
@@ -1,6 +1,7 @@
4 pull_request:
5 pull_request:
@@ -8,4 +9,5 @@ jobs:
8 uses: charmbracelet/meta/.github/workflows/lint.yml@main
9 uses: charmbracelet/meta/.github/workflows/lint.yml@main
10 golangci_path: .golangci.yml
11 golangci_path: .golangci.yml
12+ golangci_version: v2.11
11 timeout: 10m
13 timeout: 10m
.github/workflows/nightly.yml+1−1
@@ -11,7 +11,7 @@ jobs:
12 should_run: ${{ steps.check.outputs.should_run }}
12 should_run: ${{ steps.check.outputs.should_run }}
14− - uses: actions/checkout@v4
14+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
16 fetch-depth: 1
16 fetch-depth: 1
17 - id: check
17 - id: check
.github/workflows/release.yml+11−1
@@ -14,10 +14,20 @@ concurrency:
15 goreleaser:
15 goreleaser:
16 uses: charmbracelet/meta/.github/workflows/goreleaser.yml@main
16 uses: charmbracelet/meta/.github/workflows/goreleaser.yml@main
19+ macos_sign_entitlements: "./.github/entitlements.plist"
21+ docker_username: ${{ secrets.DOCKERHUB_USERNAME }}
22+ docker_token: ${{ secrets.DOCKERHUB_TOKEN }}
18 gh_pat: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
23 gh_pat: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
19 goreleaser_key: ${{ secrets.GORELEASER_KEY }}
24 goreleaser_key: ${{ secrets.GORELEASER_KEY }}
20 fury_token: ${{ secrets.FURY_TOKEN }}
25 fury_token: ${{ secrets.FURY_TOKEN }}
21 nfpm_gpg_key: ${{ secrets.NFPM_GPG_KEY }}
26 nfpm_gpg_key: ${{ secrets.NFPM_GPG_KEY }}
22 nfpm_passphrase: ${{ secrets.NFPM_PASSPHRASE }}
27 nfpm_passphrase: ${{ secrets.NFPM_PASSPHRASE }}
23− npm_token: ${{ secrets.NPM_TOKEN }}
28+ aur_key: ${{ secrets.AUR_KEY }}
29+ macos_sign_p12: ${{ secrets.MACOS_SIGN_P12 }}
30+ macos_sign_password: ${{ secrets.MACOS_SIGN_PASSWORD }}
31+ macos_notary_issuer_id: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
32+ macos_notary_key_id: ${{ secrets.MACOS_NOTARY_KEY_ID }}
33+ macos_notary_key: ${{ secrets.MACOS_NOTARY_KEY }}
.github/workflows/schema-update.yml+12−9
@@ -1,26 +1,29 @@
1−name: Update Schema
1+name: Update files
5 branches: [main]
5 branches: [main]
7 - "internal/config/**"
7 - "internal/config/**"
8+ - "internal/agent/hyper/**"
10 update-schema:
12 update-schema:
11 runs-on: ubuntu-latest
13 runs-on: ubuntu-latest
13− - uses: actions/checkout@v4
15+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
15− token: ${{ secrets.GITHUB_TOKEN }}
17+ token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
16− - uses: actions/setup-go@v5
18+ - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
18 go-version-file: go.mod
20 go-version-file: go.mod
19 - run: go run . schema > ./schema.json
21 - run: go run . schema > ./schema.json
22+ - run: go generate ./internal/agent/hyper/...
20− - uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # v5
23+ - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v5
22− commit_message: "chore: auto-update generated files"
25+ commit_message: "chore: auto-update files"
23 branch: main
26 branch: main
24− commit_user_name: actions-user
27+ commit_user_name: Charm
25− commit_user_email: actions@github.com
28+ commit_user_email: 124303983+charmcli@users.noreply.github.com
26− commit_author: actions-user <actions@github.com>
29+ commit_author: Charm <124303983+charmcli@users.noreply.github.com>
.github/workflows/security.ymlnew file+92
@@ -0,0 +1,92 @@
14+ group: security-${{ github.event.pull_request.number || github.ref }}
15+ cancel-in-progress: true
19+ runs-on: ubuntu-latest
23+ language: ["go", "actions"]
28+ security-events: write
30+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
32+ persist-credentials: false
33+ - uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
35+ languages: ${{ matrix.language }}
36+ - uses: github/codeql-action/autobuild@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
37+ - uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
40+ runs-on: ubuntu-latest
42+ security-events: write
46+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
48+ persist-credentials: false
49+ - uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0
54+ severity-cutoff: critical
55+ - uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
57+ sarif_file: ${{ steps.scan.outputs.sarif }}
60+ runs-on: ubuntu-latest
62+ security-events: write
65+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
67+ persist-credentials: false
68+ - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
71+ - name: Install govulncheck
72+ run: go install golang.org/x/vuln/cmd/govulncheck@latest
73+ - name: Run govulncheck
75+ govulncheck -C . -format sarif ./... > results.sarif
76+ - uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3
78+ sarif_file: results.sarif
81+ runs-on: ubuntu-latest
82+ if: github.event_name == 'pull_request'
86+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
88+ persist-credentials: false
89+ - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
91+ fail-on-severity: critical
92+ allow-licenses: BSD-2-Clause, BSD-3-Clause, MIT, MIT-0, Apache-2.0, MPL-2.0, ISC, LicenseRef-scancode-google-patent-license-golang, Unlicense
.github/workflows/snapshot.ymlnew file+34
@@ -0,0 +1,34 @@
12+ group: snapshot-${{ github.ref }}
13+ cancel-in-progress: true
18+ # Use our own large runners with more CPU and RAM for faster builds
21+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
24+ persist-credentials: false
25+ - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
27+ go-version-file: go.mod
28+ - uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
31+ distribution: goreleaser-pro
32+ args: build --snapshot --clean
34+ GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
@@ -42,10 +42,16 @@ Thumbs.db
45**/.crush/**
49**/.crush/**
50−completions/
55+completions/crush.*sh
51−!internal/tui/components/completions/
56+.prettierignore
@@ -2,6 +2,7 @@ version: "2"
4 - bodyclose
4 - bodyclose
5 # - exhaustive
6 # - exhaustive
6 # - goconst
7 # - goconst
@@ -9,6 +10,7 @@ linters:
9 # - gomoddirectives
10 # - gomoddirectives
10 - goprintffuncname
11 - goprintffuncname
12 - misspell
14 - misspell
13 # - nakedret
15 # - nakedret
14 # - nestif
16 # - nestif
@@ -23,16 +25,30 @@ linters:
23 - tparallel
25 - tparallel
24 # - unconvert
26 # - unconvert
25 # - unparam
27 # - unparam
26 - whitespace
29 - whitespace
27 # - wrapcheck
30 # - wrapcheck
32 exclusions:
31 exclusions:
33 generated: lax
32 generated: lax
35 - common-false-positives
34 - common-false-positives
35+ # Ignores the idiomatic-to-drop error family (*Close, *Flush,
36+ # Fprint*, os.Remove/RemoveAll, os.Setenv, stdout/stderr writes) so
37+ # errcheck only flags genuinely meaningful dropped errors.
40+ # Dropped errors in tests (setup writes, httptest encoders) are
41+ # low-signal — test failures surface them anyway.
45+ - text: '(slog|log)\.\w+'
48+ - path: internal/shell/run.go
49+ text: "SA1019.*interp.ExecHandler"
37 max-issues-per-linter: 0
53 max-issues-per-linter: 0
38 max-same-issues: 0
54 max-same-issues: 0
@@ -10,11 +10,13 @@ includes:
12 mod_timestamp: "{{ .CommitTimestamp }}"
12 mod_timestamp: "{{ .CommitTimestamp }}"
13− license: "MIT"
13+ license: "FSL-1.1-MIT"
14 homepage: "https://charm.sh/crush"
14 homepage: "https://charm.sh/crush"
15 description: "A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal."
15 description: "A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal."
16+ full_description: "A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal."
16 maintainers:
17 maintainers:
17 - "kujtimiihoxha <kujtim@charm.sh>"
18 - "kujtimiihoxha <kujtim@charm.sh>"
19+ - "caarlos0 <carlos@charm.sh>" # for aur
20 publish_release: true
22 publish_release: true
@@ -42,14 +44,15 @@ before:
44 - CGO_ENABLED=0
46 - CGO_ENABLED=0
47+ - GOEXPERIMENT=greenteagc
50− # TODO: those fail to build
51− # - openbsd
53+ - openbsd
52− # - netbsd
54+ - netbsd
@@ -57,9 +60,19 @@ builds:
62 - -s -w -X github.com/charmbracelet/crush/internal/version.Version={{.Version}}
73 - -s -w -X github.com/charmbracelet/crush/internal/version.Version={{.Version}}
65 - name_template: >-
78 - name_template: >-
@@ -83,15 +96,70 @@ archives:
84 name_template: "checksums.txt"
97 name_template: "checksums.txt"
100+ - private_key: "{{ .Env.AUR_KEY }}"
101+ disable: "{{ with .Prerelease }}true{{ end }}"
102+ git_url: "ssh://aur@aur.archlinux.org/crush.git"
105+ email: "charmcli@users.noreply.github.com"
114+ export CGO_CPPFLAGS="${CPPFLAGS}"
115+ export CGO_CFLAGS="${CFLAGS}"
116+ export CGO_CXXFLAGS="${CXXFLAGS}"
117+ export CGO_LDFLAGS="${LDFLAGS}"
118+ export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw"
119+ go build -ldflags="-w -s -buildid='' -linkmode=external -X github.com/charmbracelet/crush/internal/version.Version=v${pkgver}" .
120+ ./crush completion bash >./completions/crush.bash
121+ ./crush completion zsh >./completions/crush.zsh
122+ ./crush completion fish >./completions/crush.fish
123+ ./crush man | gzip -c >./manpages/crush.1.gz
126+ install -Dm755 "./crush" "${pkgdir}/usr/bin/crush"
128+ mkdir -p "${pkgdir}/usr/share/licenses/crush/"
129+ install -Dm644 ./LICENSE* "${pkgdir}/usr/share/licenses/crush/"
131+ mkdir -p "${pkgdir}/usr/share/bash-completion/completions/"
132+ mkdir -p "${pkgdir}/usr/share/zsh/site-functions/"
133+ mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/"
134+ install -Dm644 "./completions/crush.bash" "${pkgdir}/usr/share/bash-completion/completions/crush"
135+ install -Dm644 "./completions/crush.zsh" "${pkgdir}/usr/share/zsh/site-functions/_crush"
136+ install -Dm644 "./completions/crush.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/crush.fish"
138+ install -Dm644 "./manpages/crush.1.gz" "${pkgdir}/usr/share/man/man1/crush.1.gz"
140+ mkdir -pv "${pkgdir}/usr/share/doc/crush/"
141+ install -Dm644 README* "${pkgdir}/usr/share/doc/crush/"
87 - private_key: "{{ .Env.AUR_KEY }}"
144 - private_key: "{{ .Env.AUR_KEY }}"
145+ disable: "{{ with .Prerelease }}true{{ end }}"
88 git_url: "ssh://aur@aur.archlinux.org/crush-bin.git"
146 git_url: "ssh://aur@aur.archlinux.org/crush-bin.git"
149+ email: "charmcli@users.noreply.github.com"
89 provides:
150 provides:
91 conflicts:
152 conflicts:
93 package: |-
154 package: |-
157+ cd "${srcdir}/crush_${pkgver}_Linux_arm64"
94− cd "${srcdir}/crush_${pkgver}_Linux_${CARCH}"
160+ cd "${srcdir}/crush_${pkgver}_Linux_${CARCH}"
96 install -Dm755 "./crush" "${pkgdir}/usr/bin/crush"
164 install -Dm755 "./crush" "${pkgdir}/usr/bin/crush"
97 # license
165 # license
@@ -111,21 +179,42 @@ aurs:
111 install -Dm644 README* "${pkgdir}/usr/share/doc/crush/"
179 install -Dm644 README* "${pkgdir}/usr/share/doc/crush/"
114− - disable: "{{ .IsNightly }}"
182+ - disable: "{{ if (or .Prerelease .IsNightly) }}true{{ end }}"
115 account: "{{ with .Env.FURY_TOKEN }}charmcli{{ else }}{{ end }}"
183 account: "{{ with .Env.FURY_TOKEN }}charmcli{{ else }}{{ end }}"
116 secret_name: FURY_TOKEN
184 secret_name: FURY_TOKEN
118−homebrew_casks:
186+brews:
119 - repository:
187 - repository:
120 owner: charmbracelet
188 owner: charmbracelet
121 name: homebrew-tap
189 name: homebrew-tap
122 token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
190 token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
191+ skip_upload: "{{ with .Prerelease }}true{{ end }}"
194+ email: "charmcli@users.noreply.github.com"
197+ bash_completion.install "completions/{{ .ProjectName }}.bash" => "{{ .ProjectName }}"
198+ zsh_completion.install "completions/{{ .ProjectName }}.zsh" => "_{{ .ProjectName }}"
199+ fish_completion.install "completions/{{ .ProjectName }}.fish"
200+ man1.install "manpages/{{ .ProjectName }}.1.gz"
204+ owner: charmbracelet
206+ token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
207+ skip_upload: "{{ with .Prerelease }}true{{ end }}"
210+ email: "charmcli@users.noreply.github.com"
125 - name: "@charmland/crush"
213 - name: "@charmland/crush"
126 repository: "git+https://github.com/charmbracelet/crush.git"
214 repository: "git+https://github.com/charmbracelet/crush.git"
127 bugs: https://github.com/charmbracelet/crush/issues
215 bugs: https://github.com/charmbracelet/crush/issues
128 access: public
216 access: public
217+ disable: "{{ with .Prerelease }}true{{ end }}"
131 - formats:
220 - formats:
@@ -133,29 +222,68 @@ nfpms:
135 - archlinux
224 - archlinux
136 file_name_template: "{{ .ConventionalFileName }}"
226 file_name_template: "{{ .ConventionalFileName }}"
137 contents:
227 contents:
138 - src: ./completions/crush.bash
228 - src: ./completions/crush.bash
139− dst: /etc/bash_completion.d/crush
229+ dst: '{{ if eq .Format "termux.deb" }}/data/data/com.termux/files/usr{{ end }}/etc/bash_completion.d/crush'
140 - src: ./completions/crush.fish
230 - src: ./completions/crush.fish
141− dst: /usr/share/fish/vendor_completions.d/crush.fish
231+ dst: '{{ if eq .Format "termux.deb" }}/data/data/com.termux/files{{ end }}/usr/share/fish/vendor_completions.d/crush.fish'
142 - src: ./completions/crush.zsh
232 - src: ./completions/crush.zsh
143− dst: /usr/share/zsh/site-functions/_crush
233+ dst: '{{ if eq .Format "termux.deb" }}/data/data/com.termux/files{{ end }}/usr/share/zsh/site-functions/_crush'
144 - src: ./manpages/crush.1.gz
234 - src: ./manpages/crush.1.gz
145− dst: /usr/share/man/man1/crush.1.gz
235+ dst: '{{ if eq .Format "termux.deb" }}/data/data/com.termux/files{{ end }}/usr/share/man/man1/crush.1.gz'
238+ key_file: '{{ if ne (index .Env "GPG_KEY_PATH") "" }}{{ .Env.GPG_KEY_PATH }}{{ else }}{{ end }}'
241+ key_file: '{{ if ne (index .Env "GPG_KEY_PATH") "" }}{{ .Env.GPG_KEY_PATH }}{{ else }}{{ end }}'
245+ signature: "${artifact}.sigstore.json"
248+ - "--bundle=${signature}"
258+ - artifacts: archive
148 - repository:
263 - repository:
149 owner: "charmbracelet"
264 owner: "charmbracelet"
150 name: nur
265 name: nur
151 token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
266 token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
269+ email: "charmcli@users.noreply.github.com"
272+ skip_upload: "{{ with .Prerelease }}true{{ end }}"
152 extra_install: |-
273 extra_install: |-
153− installManPage ./manpages/crush.1.gz.
274+ installManPage ./manpages/crush.1.gz
154 installShellCompletion ./completions/*
275 installShellCompletion ./completions/*
157 - publisher: charmbracelet
278 - publisher: charmbracelet
158 copyright: Charmbracelet, Inc
279 copyright: Charmbracelet, Inc
280+ publisher_url: https://charm.land
281+ release_notes_url: "https://github.com/charmbracelet/crush/releases/tag/{{.Tag}}"
282+ license_url: https://github.com/charmbracelet/crush/blob/main/LICENSE.md
283+ skip_upload: "{{ with .Prerelease }}true{{ end }}"
286+ email: "charmcli@users.noreply.github.com"
159 repository:
287 repository:
160 owner: "charmbracelet"
288 owner: "charmbracelet"
161 name: winget-pkgs
289 name: winget-pkgs
@@ -169,10 +297,13 @@ winget:
169 owner: microsoft
297 owner: microsoft
170 name: winget-pkgs
298 name: winget-pkgs
171 branch: master
299 branch: master
173changelog:
303changelog:
174 sort: asc
304 sort: asc
175 disable: "{{ .IsNightly }}"
305 disable: "{{ .IsNightly }}"
178 - "^(build|ci): "
309 - "^(build|ci): "
@@ -183,10 +314,12 @@ changelog:
183 - "^chore: typo$"
314 - "^chore: typo$"
184 - "^chore: update schema$"
315 - "^chore: update schema$"
185 - "^chore: update$"
316 - "^chore: update$"
317+ - "^chore\\(legal\\): "
186 - "^chore\\(deps\\): "
318 - "^chore\\(deps\\): "
187 - "^docs: update$"
319 - "^docs: update$"
188 - "^test:"
320 - "^test:"
189 - "^test\\("
321 - "^test\\("
190 - "merge conflict"
323 - "merge conflict"
191 - "merge conflict"
324 - "merge conflict"
192 - Merge branch
325 - Merge branch
@@ -196,17 +329,23 @@ changelog:
196 - "^wip "
329 - "^wip "
197 - "^wip:"
330 - "^wip:"
199− - title: "New Features"
332+ - title: "Deps"
333+ regexp: "^.*\\(deps\\)*:+.*$"
200− regexp: '^.*?feat(\(.+\))??!?:.+$'
336+ regexp: "^.*feat[(\\w)]*:+.*$"
201 order: 100
337 order: 100
202− - title: "Security updates"
338+ - title: "Fixed"
203− regexp: '^.*?sec(\(.+\))??!?:.+$'
339+ regexp: "^.*fix[(\\w)]*:+.*$"
205− - title: "Bug fixes and improvements"
206− regexp: '^.*?(fix|refactor)(\(.+\))??!?:.+$'
207 order: 200
340 order: 200
208− - title: "Documentation updates"
341+ - title: "Docs"
209− regexp: ^.*?docs?(\(.+\))??!?:.+$
342+ regexp: "^.*docs[(\\w)]*:+.*$"
210 order: 400
343 order: 400
211− - title: Other work
344+ - title: "Other stuff"
212 order: 9999
345 order: 9999
351+ url: https://raw.githubusercontent.com/charmbracelet/meta/main/footer.md
@@ -0,0 +1,223 @@
1+# Crush Development Guide
5+Crush is a terminal-based AI coding assistant built in Go by
6+[Charm](https://charm.land). It connects to LLMs and gives them tools to read,
7+write, and execute code. It supports multiple providers (Anthropic, OpenAI,
8+Gemini, Bedrock, Copilot, Hyper, MiniMax, Vercel, and more), integrates with
9+LSPs for code intelligence, and supports extensibility via MCP servers and
12+The module path is `github.com/charmbracelet/crush`.
17+main.go CLI entry point (cobra via internal/cmd)
19+ app/app.go Top-level wiring: DB, config, agents, LSP, MCP, events
20+ cmd/ CLI commands (root, run, login, models, stats, sessions)
22+ config.go Config struct, context file paths, agent definitions
23+ load.go crush.json loading and validation
24+ provider.go Provider configuration and model resolution
26+ agent.go SessionAgent: runs LLM conversations per session
27+ coordinator.go Coordinator: manages named agents ("coder", "task")
28+ hooked_tool.go Decorator that runs PreToolUse hooks before tool execution
29+ prompts.go Loads Go-template system prompts
30+ templates/ System prompt templates (coder.md.tpl, task.md.tpl, etc.)
31+ tools/ All built-in tools (bash, edit, view, grep, glob, etc.)
32+ mcp/ MCP client integration
33+ hooks/ Hook engine: runs user shell commands on hook events
34+ hooks.go Decision types, aggregation logic, event constants
35+ runner.go Parallel hook execution, timeout, dedup
36+ input.go Stdin payload builder, env vars, stdout parsing (Crush + Claude Code compat)
37+ session/session.go Session CRUD backed by SQLite
38+ message/ Message model and content types
39+ db/ SQLite via sqlc, with migrations
40+ sql/ Raw SQL queries (consumed by sqlc)
41+ migrations/ Schema migrations
42+ lsp/ LSP client manager, auto-discovery, on-demand startup
43+ ui/ Bubble Tea v2 TUI (see internal/ui/AGENTS.md)
44+ permission/ Tool permission checking and allow-lists
45+ skills/ Skill file discovery and loading
46+ shell/ Bash command execution with background job support
47+ event/ Telemetry (PostHog)
48+ pubsub/ Internal pub/sub for cross-component messaging
49+ filetracker/ Tracks files touched per session
50+ history/ Prompt history
53+### Key Dependency Roles
55+- **`charm.land/fantasy`**: LLM provider abstraction layer. Handles protocol
56+ differences between Anthropic, OpenAI, Gemini, etc. Used in `internal/app`
57+ and `internal/agent`.
58+- **`charm.land/bubbletea/v2`**: TUI framework powering the interactive UI.
59+- **`charm.land/lipgloss/v2`**: Terminal styling.
60+- **`charm.land/glamour/v2`**: Markdown rendering in the terminal.
61+- **`charm.land/catwalk`**: Snapshot/golden-file testing for TUI components.
62+- **`sqlc`**: Generates Go code from SQL queries in `internal/db/sql/`.
66+- **Config is a Service**: accessed via `config.Service`, not global state.
67+- **Tools are self-documenting**: each tool has a `.go` implementation and a
68+ `.md` description file in `internal/agent/tools/`.
69+- **System prompts are Go templates**: `internal/agent/templates/*.md.tpl`
70+ with runtime data injected.
71+- **Context files**: Crush reads AGENTS.md, CRUSH.md, CLAUDE.md, GEMINI.md
72+ (and `.local` variants) from the working directory for project-specific
74+- **Persistence**: SQLite + sqlc. All queries live in `internal/db/sql/`,
75+ generated code in `internal/db/`. Migrations in `internal/db/migrations/`.
76+- **Pub/sub**: `internal/pubsub` for decoupled communication between agent,
78+- **Hooks**: User-defined shell commands in `crush.json` that fire before
79+ tool execution. The engine (`internal/hooks/`) is independent of fantasy
80+ and agent — it takes inputs, runs commands, returns decisions. The
81+ `hookedTool` decorator in `internal/agent/hooked_tool.go` wraps tools at
82+ the coordinator level. Hooks run before permission checks. See
83+ `HOOKS.md` for the user-facing protocol.
84+- **CGO disabled**: builds with `CGO_ENABLED=0` and
85+ `GOEXPERIMENT=greenteagc`.
87+## Build/Test/Lint Commands
89+- **Build**: `go build .` or `go run .`
90+- **Test**: `task test` or `go test ./...` (run single test:
91+ `go test ./internal/llm/prompt -run TestGetContextFromPaths`)
92+- **Update Golden Files**: `go test ./... -update` (regenerates `.golden`
93+ files when test output changes)
94+ - Update specific package:
95+ `go test ./internal/tui/components/core -update` (in this case,
96+ we're updating "core")
97+- **Lint**: `task lint:fix`
98+- **Format**: `task fmt` (`gofumpt -w .`)
99+- **Modernize**: `task modernize` (runs `modernize` which makes code
101+- **Dev**: `task dev` (runs with profiling enabled)
103+## Code Style Guidelines
105+- **Imports**: Use `goimports` formatting, group stdlib, external, internal
107+- **Formatting**: Use gofumpt (stricter than gofmt), enabled in
109+- **Naming**: Standard Go conventions — PascalCase for exported, camelCase
111+- **Types**: Prefer explicit types, use type aliases for clarity (e.g.,
112+ `type AgentName string`).
113+- **Error handling**: Return errors explicitly, use `fmt.Errorf` for
115+- **Context**: Always pass `context.Context` as first parameter for
117+- **Interfaces**: Define interfaces in consuming packages, keep them small
119+- **Structs**: Use struct embedding for composition, group related fields.
120+- **Constants**: Use typed constants with iota for enums, group in const
122+- **Testing**: Use testify's `require` package, parallel tests with
123+ `t.Parallel()`, `t.SetEnv()` to set environment variables. Always use
124+ `t.Tempdir()` when in need of a temporary directory. This directory does
125+ not need to be removed.
126+- **JSON tags**: Use snake_case for JSON field names.
127+- **File permissions**: Use octal notation (0o755, 0o644) for file
129+- **Log messages**: Log messages must start with a capital letter (e.g.,
130+ "Failed to save session" not "failed to save session").
131+ - This is enforced by `task lint:log` which runs as part of `task lint`.
132+- **Comments**: End comments in periods unless comments are at the end of the
135+## Testing with Mock Providers
137+When writing tests that involve provider configurations, use the mock
138+providers to avoid API calls:
141+func TestYourFunction(t *testing.T) {
142+ // Enable mock providers for testing
143+ originalUseMock := config.UseMockProviders
144+ config.UseMockProviders = true
146+ config.UseMockProviders = originalUseMock
147+ config.ResetProviders()
150+ // Reset providers to ensure fresh mock data
151+ config.ResetProviders()
153+ // Your test code here - providers will now return mock data
154+ providers := config.Providers()
161+- ALWAYS format any Go code you write.
162+ - First, try `gofumpt -w .`.
163+ - If `gofumpt` is not available, use `goimports`.
164+ - If `goimports` is not available, use `gofmt`.
165+ - You can also use `task fmt` to run `gofumpt -w .` on the entire project,
166+ as long as `gofumpt` is on the `PATH`.
170+- Comments that live on their own lines should start with capital letters and
171+ end with periods. Wrap comments at 78 columns.
175+- ALWAYS use semantic commits (`fix:`, `feat:`, `chore:`, `refactor:`,
176+ `docs:`, `sec:`, etc).
177+- Try to keep commits to one line, not including your attribution. Only use
178+ multi-line commits when additional context is truly necessary.
180+## Working on the TUI (UI)
182+Anytime you need to work on the TUI, read `internal/ui/AGENTS.md` before
187+The styling system lives in `internal/ui/styles/` and is organized into
190+- **`quickstyle.go`**: The stable base theme builder. `quickStyle(opts)`
191+ constructs a `Styles` struct from `quickStyleOpts` — a palette of
192+ design tokens (primary, secondary, fgBase, bgBase, success, error, etc.).
193+ `quickStyle` must be fully token-driven: never hardcode specific
194+ `charmtone.*` colors here (except Chroma syntax highlighting, which is
195+ pending tokenization). This lets any theme reuse the base without
196+ inheriting Charmtone-specific colors.
197+- **`themes.go`**: Defines concrete themes. Each theme function (e.g.
198+ `CharmtonePantera`) calls `quickStyle` with its palette, then applies
199+ theme-specific overrides as needed.
200+- **`styles.go`**: Defines the `Styles` struct and its documentation —
201+ the shape of what `quickStyle` produces.
203+**Adding theme-specific overrides**: When a style genuinely needs a
204+color that doesn't fit the token model (e.g. the bang prompt uses
205+Salt/Hazy/Larple), keep `quickStyle` on the closest semantic token and
206+override only the differing colors in the theme function:
209+func CharmtonePantera() Styles {
210+ s := quickStyle(quickStyleOpts{ /* palette */ })
212+ // Override only the colors that differ from the token defaults.
213+ s.Editor.PromptBangIconFocused = s.Editor.PromptBangIconFocused.
214+ Foreground(charmtone.Salt).
215+ Background(charmtone.Hazy)
221+**Adding a new theme**: Add a function in `themes.go` that returns the
222+result of `quickStyle` with a `quickStyleOpts` palette (plus any needed
223+overrides), then wire it into `ThemeForProvider`.
@@ -0,0 +1,18 @@
1+# Contributor License Agreement
3+Thank you for your interest in the open source project(s) managed by Charmbracelet, Inc. ("Company"). In order to clarify the intellectual property license granted with Contributions from any person or entity, Company must have a Contributor License Agreement ("CLA") on file that has been signed by each contributor, indicating agreement to the license terms below. This license is for your protection as a contributor as well as the protection of Company and its other contributors and users; it does not change your rights to use your own Contributions for any other purpose.
4+By submitting a contribution to this repository (e.g. opening a pull request) or otherwise agreeing in writing, You accept and agree to these terms and conditions for Your present and future Contributions submitted to Company. In return, Company shall consider Your Contributions for addition to the official Company open source project(s) for which they were submitted. Except for the license granted herein to Company and recipients of software distributed by Company, You reserve all right, title, and interest in and to Your Contributions.
7+ - "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is entering into this CLA with Company. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
8+ - "Contribution" shall mean any code, documentation or other original works of authorship, including any modifications or additions to an existing work, that are intentionally submitted by You to Company for inclusion in, or documentation of, any of the products owned or managed by Company (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Company or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Company for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
9+2. Grant of Copyright License. Subject to the terms and conditions of this CLA, You hereby grant to Company and to recipients of software distributed by Company a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
10+3. Grant of Patent License. Subject to the terms and conditions of this CLA, You hereby grant to Company and to recipients of software distributed by Company a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) were submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that Your Contribution, or the Work to which You have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this CLA for that Contribution or Work shall terminate as of the date such litigation is filed.
11+4. You represent and warrant that You are legally entitled to grant the above license. If You are an individual and Your employer(s) has rights to intellectual property that You create that includes Your Contributions, You represent that You have received permission to make Contributions on behalf of that employer, that Your employer has waived such rights for Your Contributions to Company, or that Your employer has entered into a separate CLA with Company covering Your Contributions. If You are a company, You represent further that each employee making a Contribution to Company under the company’s name is authorized to submit Contributions on behalf of the company.
12+5. You represent and warrant that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent and warrant that, to Your knowledge, none of Your Contributions infringe, violate, or misappropriate any third party intellectual property or other proprietary rights.
13+6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, except for the warranties set forth above, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
14+7. Should You wish to submit work that is not Your original creation, You may submit it to Company separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which You are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
15+8. You agree to notify Company of any facts or circumstances of which You become aware that would make the above representations and warranties inaccurate in any respect.
16+9. If You are entering into this CLA as a company, You represent and warrant that the individual accepting this CLA is duly authorized to enter into this CLA on the company’s behalf.
18+For any copyright notices or other communications, please contact us at [vt100@charm.land](mailto:vt100@charm.land).
@@ -1,58 +0,0 @@
1−# Crush Development Guide
3−## Build/Test/Lint Commands
5−- **Build**: `go build .` or `go run .`
6−- **Test**: `task test` or `go test ./...` (run single test: `go test ./internal/llm/prompt -run TestGetContextFromPaths`)
7−- **Lint**: `task lint-fix`
8−- **Format**: `task fmt` (gofumpt -w .)
9−- **Dev**: `task dev` (runs with profiling enabled)
11−## Code Style Guidelines
13−- **Imports**: Use goimports formatting, group stdlib, external, internal packages
14−- **Formatting**: Use gofumpt (stricter than gofmt), enabled in golangci-lint
15−- **Naming**: Standard Go conventions - PascalCase for exported, camelCase for unexported
16−- **Types**: Prefer explicit types, use type aliases for clarity (e.g., `type AgentName string`)
17−- **Error handling**: Return errors explicitly, use `fmt.Errorf` for wrapping
18−- **Context**: Always pass context.Context as first parameter for operations
19−- **Interfaces**: Define interfaces in consuming packages, keep them small and focused
20−- **Structs**: Use struct embedding for composition, group related fields
21−- **Constants**: Use typed constants with iota for enums, group in const blocks
22−- **Testing**: Use testify's `require` package, parallel tests with `t.Parallel()`,
23− `t.SetEnv()` to set environment variables.
24−- **JSON tags**: Use snake_case for JSON field names
25−- **File permissions**: Use octal notation (0o755, 0o644) for file permissions
26−- **Comments**: End comments in periods unless comments are at the end of the line.
28−## Testing with Mock Providers
30−When writing tests that involve provider configurations, use the mock providers to avoid API calls:
33−func TestYourFunction(t *testing.T) {
34− // Enable mock providers for testing
35− originalUseMock := config.UseMockProviders
36− config.UseMockProviders = true
38− config.UseMockProviders = originalUseMock
39− config.ResetProviders()
42− // Reset providers to ensure fresh mock data
43− config.ResetProviders()
45− // Your test code here - providers will now return mock data
46− providers := config.Providers()
53−- ALWAYS format any Go code you write.
54− - First, try `goftumpt -w .`.
55− - If `gofumpt` is not available, use `goimports`.
56− - If `goimports` is not available, use `gofmt`.
57− - You can also use `task fmt` to run `gofumpt -w .` on the entire project,
58− as long as `gofumpt` is on the `PATH`.
@@ -1,134 +0,0 @@
1−# Functional Source License, Version 1.1, MIT Future License
9−Copyright 2025 Charmbracelet, Inc
11−## Terms and Conditions
15−The party offering the Software under these Terms and Conditions.
19−The "Software" is each version of the software that we make available under
20−these Terms and Conditions, as indicated by our inclusion of these Terms and
21−Conditions with the Software.
25−Subject to your compliance with this License Grant and the Patents,
26−Redistribution and Trademark clauses below, we hereby grant you the right to
27−use, copy, modify, create derivative works, publicly perform, publicly display
28−and redistribute the Software for any Permitted Purpose identified below.
32−A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33−means making the Software available to others in a commercial product or
36−1. substitutes for the Software;
38−2. substitutes for any other product or service we offer using the Software
39− that exists as of the date we make the Software available; or
41−3. offers the same or substantially similar functionality as the Software.
43−Permitted Purposes specifically include using the Software:
45−1. for your internal use and access;
47−2. for non-commercial education;
49−3. for non-commercial research; and
51−4. in connection with professional services that you provide to a licensee
52− using the Software in accordance with these Terms and Conditions.
56−To the extent your use for a Permitted Purpose would necessarily infringe our
57−patents, the license grant above includes a license under our patents. If you
58−make a claim against any party that the Software infringes or contributes to
59−the infringement of any patent, then your patent license to the Software ends
64−The Terms and Conditions apply to all copies, modifications and derivatives of
67−If you redistribute any copies, modifications or derivatives of the Software,
68−you must include a copy of or a link to these Terms and Conditions and not
69−remove any copyright notices provided in or with the Software.
73−THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74−IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75−PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
77−IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78−SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79−EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
83−Except for displaying the License Details and identifying us as the origin of
84−the Software, you have no right under these Terms and Conditions to use our
85−trademarks, trade names, service marks or product names.
87−## Grant of Future License
89−We hereby irrevocably grant you an additional license to use the Software under
90−the MIT license that is effective on the second anniversary of the date we make
91−the Software available. On or after that date, you may use the Software under
92−the MIT license, in which case the following will apply:
94−Permission is hereby granted, free of charge, to any person obtaining a copy of
95−this software and associated documentation files (the "Software"), to deal in
96−the Software without restriction, including without limitation the rights to
97−use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98−of the Software, and to permit persons to whom the Software is furnished to do
99−so, subject to the following conditions:
101−The above copyright notice and this permission notice shall be included in all
102−copies or substantial portions of the Software.
104−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
105−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
106−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
107−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
108−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
109−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
116−Copyright (c) 2025-03-21 - 2025-05-30 Kujtim Hoxha
118−Permission is hereby granted, free of charge, to any person obtaining a copy
119−of this software and associated documentation files (the "Software"), to deal
120−in the Software without restriction, including without limitation the rights
121−to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
122−copies of the Software, and to permit persons to whom the Software is
123−furnished to do so, subject to the following conditions:
125−The above copyright notice and this permission notice shall be included in all
126−copies or substantial portions of the Software.
128−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
129−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
130−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
131−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
132−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
133−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
@@ -0,0 +1,134 @@
1+# Functional Source License, Version 1.1, MIT Future License
9+Copyright 2025-2026 Charmbracelet, Inc.
11+## Terms and Conditions
15+The party offering the Software under these Terms and Conditions.
19+The "Software" is each version of the software that we make available under
20+these Terms and Conditions, as indicated by our inclusion of these Terms and
21+Conditions with the Software.
25+Subject to your compliance with this License Grant and the Patents,
26+Redistribution and Trademark clauses below, we hereby grant you the right to
27+use, copy, modify, create derivative works, publicly perform, publicly display
28+and redistribute the Software for any Permitted Purpose identified below.
32+A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33+means making the Software available to others in a commercial product or
36+1. substitutes for the Software;
38+2. substitutes for any other product or service we offer using the Software
39+ that exists as of the date we make the Software available; or
41+3. offers the same or substantially similar functionality as the Software.
43+Permitted Purposes specifically include using the Software:
45+1. for your internal use and access;
47+2. for non-commercial education;
49+3. for non-commercial research; and
51+4. in connection with professional services that you provide to a licensee
52+ using the Software in accordance with these Terms and Conditions.
56+To the extent your use for a Permitted Purpose would necessarily infringe our
57+patents, the license grant above includes a license under our patents. If you
58+make a claim against any party that the Software infringes or contributes to
59+the infringement of any patent, then your patent license to the Software ends
64+The Terms and Conditions apply to all copies, modifications and derivatives of
67+If you redistribute any copies, modifications or derivatives of the Software,
68+you must include a copy of or a link to these Terms and Conditions and not
69+remove any copyright notices provided in or with the Software.
73+THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74+IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75+PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
77+IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78+SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79+EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
83+Except for displaying the License Details and identifying us as the origin of
84+the Software, you have no right under these Terms and Conditions to use our
85+trademarks, trade names, service marks or product names.
87+## Grant of Future License
89+We hereby irrevocably grant you an additional license to use the Software under
90+the MIT license that is effective on the second anniversary of the date we make
91+the Software available. On or after that date, you may use the Software under
92+the MIT license, in which case the following will apply:
94+Permission is hereby granted, free of charge, to any person obtaining a copy of
95+this software and associated documentation files (the "Software"), to deal in
96+the Software without restriction, including without limitation the rights to
97+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98+of the Software, and to permit persons to whom the Software is furnished to do
99+so, subject to the following conditions:
101+The above copyright notice and this permission notice shall be included in all
102+copies or substantial portions of the Software.
104+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
105+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
106+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
107+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
108+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
109+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
116+Copyright (c) 2025-03-21 - 2025-05-30 Kujtim Hoxha
118+Permission is hereby granted, free of charge, to any person obtaining a copy
119+of this software and associated documentation files (the "Software"), to deal
120+in the Software without restriction, including without limitation the rights
121+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
122+copies of the Software, and to permit persons to whom the Software is
123+furnished to do so, subject to the following conditions:
125+The above copyright notice and this permission notice shall be included in all
126+copies or substantial portions of the Software.
128+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
129+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
130+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
131+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
132+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
133+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
@@ -1,12 +1,16 @@
4+> This is a personal fork of [charmbracelet/crush](https://github.com/charmbracelet/crush) with UI/UX tweaks and performance improvements.
3<p align="center">
6<p align="center">
4− <a href="https://stuff.charm.sh/crush/charm-crush.png"><img width="450" alt="Charm Crush Logo" src="https://github.com/user-attachments/assets/adc1a6f4-b284-4603-836c-59038caa2e8b" /></a><br />
7+ <a href="https://stuff.charm.sh/crush/charm-crush.png"><img width="450" alt="Charm Crush Logo" src="https://github.com/user-attachments/assets/cf8ca3ce-8b02-43f0-9d0f-5a331488da4b" /></a><br />
5 <a href="https://github.com/charmbracelet/crush/releases"><img src="https://img.shields.io/github/release/charmbracelet/crush" alt="Latest Release"></a>
8 <a href="https://github.com/charmbracelet/crush/releases"><img src="https://img.shields.io/github/release/charmbracelet/crush" alt="Latest Release"></a>
6− <a href="https://github.com/charmbracelet/crush/actions"><img src="https://github.com/charmbracelet/crush/workflows/build/badge.svg" alt="Build Status"></a>
9+ <a href="https://github.com/charmbracelet/crush/actions"><img src="https://github.com/charmbracelet/crush/actions/workflows/build.yml/badge.svg" alt="Build Status"></a>
9<p align="center">Your new coding bestie, now available in your favourite terminal.<br />Your tools, your code, and your workflows, wired into your LLM of choice.</p>
12<p align="center">Your new coding bestie, now available in your favourite terminal.<br />Your tools, your code, and your workflows, wired into your LLM of choice.</p>
13+<p align="center">终端里的编程新搭档,<br />无缝接入你的工具、代码与工作流,全面兼容主流 LLM 模型。</p>
11<p align="center"><img width="800" alt="Crush Demo" src="https://github.com/user-attachments/assets/58280caf-851b-470a-b6f7-d5c4ea8a1968" /></p>
15<p align="center"><img width="800" alt="Crush Demo" src="https://github.com/user-attachments/assets/58280caf-851b-470a-b6f7-d5c4ea8a1968" /></p>
@@ -17,14 +21,15 @@
17- **Session-Based:** maintain multiple work sessions and contexts per project
21- **Session-Based:** maintain multiple work sessions and contexts per project
18- **LSP-Enhanced:** Crush uses LSPs for additional context, just like you do
22- **LSP-Enhanced:** Crush uses LSPs for additional context, just like you do
19- **Extensible:** add capabilities via MCPs (`http`, `stdio`, and `sse`)
23- **Extensible:** add capabilities via MCPs (`http`, `stdio`, and `sse`)
20−- **Works Everywhere:** first-class support in every terminal on macOS, Linux, Windows (PowerShell and WSL), and FreeBSD
24+- **Works Everywhere:** first-class support in every terminal on macOS, Linux, Windows (PowerShell and WSL), Android, FreeBSD, OpenBSD, and NetBSD
25+- **Industrial Grade:** built on the Charm ecosystem, powering 25k+ applications, from leading open source projects to business-critical infrastructure
22## Installation
27## Installation
24Use a package manager:
29Use a package manager:
27−# macOS or Linux
32+# Homebrew
28brew install charmbracelet/tap/crush
33brew install charmbracelet/tap/crush
@@ -33,13 +38,97 @@ npm install -g @charmland/crush
33# Arch Linux (btw)
38# Arch Linux (btw)
34yay -S crush-bin
39yay -S crush-bin
42+nix run github:numtide/nix-ai-tools#crush
36−# Windows (with Winget)
51+# Winget
37winget install charmbracelet.crush
52winget install charmbracelet.crush
55+scoop bucket add charm https://github.com/charmbracelet/scoop-bucket.git
60+<summary><strong>Nix (NUR)</strong></summary>
62+Crush is available via the official Charm [NUR](https://github.com/nix-community/NUR) in `nur.repos.charmbracelet.crush`, which is the most up-to-date way to get Crush in Nix.
64+You can also try out Crush via the NUR with `nix-shell`:
67+# Add the NUR channel.
68+nix-channel --add https://github.com/nix-community/NUR/archive/main.tar.gz nur
71+# Get Crush in a Nix shell.
40−nix-shell -p nur.repos.charmbracelet.crush
72+nix-shell -p '(import <nur> { pkgs = import <nixpkgs> {}; }).repos.charmbracelet.crush'
75+### NixOS & Home Manager Module Usage via NUR
77+Crush provides NixOS and Home Manager modules via NUR.
78+You can use these modules directly in your flake by importing them from NUR. Since it auto detects whether its a home manager or nixos context you can use the import the exact same way :)
83+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
84+ nur.url = "github:nix-community/NUR";
87+ outputs = { self, nixpkgs, nur, ... }: {
88+ nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem {
89+ system = "x86_64-linux";
91+ nur.modules.nixos.default
92+ nur.repos.charmbracelet.modules.crush
101+ base_url = "https://api.openai.com/v1";
103+ api_key = "sk-fake123456789abcdef...";
113+ go = { command = "gopls"; enabled = true; };
114+ nix = { command = "nil"; enabled = true; };
117+ context_paths = [ "/etc/nixos/configuration.nix" ];
118+ tui = { compact_mode = true; };
44<summary><strong>Debian/Ubuntu</strong></summary>
133<summary><strong>Debian/Ubuntu</strong></summary>
@@ -74,7 +163,7 @@ Or, download it:
75[releases]: https://github.com/charmbracelet/crush/releases
164[releases]: https://github.com/charmbracelet/crush/releases
77−Or just install it with go:
166+Or just install it with Go:
80go install github.com/charmbracelet/crush@latest
169go install github.com/charmbracelet/crush@latest
@@ -83,55 +172,105 @@ go install github.com/charmbracelet/crush@latest
83> [!WARNING]
172> [!WARNING]
84> Productivity may increase when using Crush and you may find yourself nerd
173> Productivity may increase when using Crush and you may find yourself nerd
85> sniped when first using the application. If the symptoms persist, join the
174> sniped when first using the application. If the symptoms persist, join the
86−> [Discord][discord] and nerd snipe the rest of us.
175+> [Slack][slack] or [Discord][discord] and nerd snipe the rest of us.
88## Getting Started
177## Getting Started
90The quickest way to get started is to grab an API key for your preferred
179The quickest way to get started is to grab an API key for your preferred
91−provider such as Anthropic, OpenAI, Groq, or OpenRouter and just start
180+provider such as Anthropic, OpenAI, Groq, OpenRouter, or Vercel AI Gateway and just start
92Crush. You'll be prompted to enter your API key.
181Crush. You'll be prompted to enter your API key.
94That said, you can also set environment variables for preferred providers.
183That said, you can also set environment variables for preferred providers.
97−<summary><strong>Supported Environment Variables</strong></summary>
99−| Environment Variable | Provider |
185+| Environment Variable | Provider |
100−| -------------------------- | -------------------------------------------------- |
186+| --------------------------- | -------------------------------------------------- |
187+| `HYPER_API_KEY` | Charm Hyper |
101−| `ANTHROPIC_API_KEY` | Anthropic |
188+| `ANTHROPIC_API_KEY` | Anthropic |
102−| `OPENAI_API_KEY` | OpenAI |
189+| `OPENAI_API_KEY` | OpenAI |
190+| `VERCEL_API_KEY` | Vercel AI Gateway |
103−| `GEMINI_API_KEY` | Google Gemini |
191+| `GEMINI_API_KEY` | Google Gemini |
104−| `VERTEXAI_PROJECT` | Google Cloud VertexAI (Gemini) |
192+| `SYNTHETIC_API_KEY` | Synthetic |
105−| `VERTEXAI_LOCATION` | Google Cloud VertexAI (Gemini) |
193+| `ZAI_API_KEY` | Z.ai |
194+| `MINIMAX_API_KEY` | MiniMax |
195+| `HF_TOKEN` | Hugging Face Inference |
196+| `CEREBRAS_API_KEY` | Cerebras |
197+| `OPENROUTER_API_KEY` | OpenRouter |
198+| `IONET_API_KEY` | io.net |
199+| `ALIBABA_SINGAPORE_API_KEY` | Alibaba (Singapore) |
200+| `ALIBABA_US_API_KEY` | Alibaba (United States) |
106−| `GROQ_API_KEY` | Groq |
201+| `GROQ_API_KEY` | Groq |
202+| `AVIAN_API_KEY` | Avian |
203+| `OPENCODE_API_KEY` | OpenCode Zen & Go |
204+| `VERTEXAI_PROJECT` | Google Cloud VertexAI (Gemini) |
205+| `VERTEXAI_LOCATION` | Google Cloud VertexAI (Gemini) |
107−| `AWS_ACCESS_KEY_ID` | AWS Bedrock (Claude) |
206+| `AWS_ACCESS_KEY_ID` | Amazon Bedrock (Claude) |
108−| `AWS_SECRET_ACCESS_KEY` | AWS Bedrock (Claude) |
207+| `AWS_SECRET_ACCESS_KEY` | Amazon Bedrock (Claude) |
109−| `AWS_REGION` | AWS Bedrock (Claude) |
208+| `AWS_REGION` | Amazon Bedrock (Claude) |
209+| `AWS_PROFILE` | Amazon Bedrock (Custom Profile) |
210+| `AWS_BEARER_TOKEN_BEDROCK` | Amazon Bedrock |
110−| `AZURE_OPENAI_ENDPOINT` | Azure OpenAI models |
211+| `AZURE_OPENAI_API_ENDPOINT` | Azure OpenAI models |
111−| `AZURE_OPENAI_API_KEY` | Azure OpenAI models (optional when using Entra ID) |
212+| `AZURE_OPENAI_API_KEY` | Azure OpenAI models (optional when using Entra ID) |
112−| `AZURE_OPENAI_API_VERSION` | Azure OpenAI models |
213+| `AZURE_OPENAI_API_VERSION` | Azure OpenAI models |
113−
214+| `MOONSHOT_API_KEY` | Moonshot |
218+If you prefer subscription-based usage, here are some plans that work well in
221+- [Synthetic](https://synthetic.new/pricing)
222+- [GLM Coding Plan](https://z.ai/subscribe)
223+- [Kimi Code](https://www.kimi.com/membership/pricing)
224+- [MiniMax Coding Plan](https://platform.minimax.io/subscribe/coding-plan)
228+Is there a provider you’d like to see in Crush? Is there an existing model that needs an update?
230+Crush’s default model listing is managed in [Catwalk](https://github.com/charmbracelet/catwalk), a community-supported, open source repository of Crush-compatible models, and you’re welcome to contribute.
232+<a href="https://github.com/charmbracelet/catwalk"><img width="174" height="174" alt="Catwalk Badge" src="https://github.com/user-attachments/assets/95b49515-fe82-4409-b10d-5beb0873787d" /></a>
116## Configuration
234## Configuration
237+> Crush ships with a builtin `crush-config` skill for configuring itself. In
238+> many cases you can simply ask Crush to configure itself.
118Crush runs great with no configuration. That said, if you do need or want to
240Crush runs great with no configuration. That said, if you do need or want to
119customize Crush, configuration can be added either local to the project itself,
241customize Crush, configuration can be added either local to the project itself,
120or globally, with the following priority:
242or globally, with the following priority:
122−1. `./.crush.json`
244+1. `.crush.json`
123−2. `./crush.json`
245+2. `crush.json`
1243. `$HOME/.config/crush/crush.json`
2463. `$HOME/.config/crush/crush.json`
126Configuration itself is stored as a JSON object:
248Configuration itself is stored as a JSON object:
130− "this-setting": { }
252+ "this-setting": { "this": "that" },
131− "that-setting": { }
253+ "that-setting": ["ceci", "cela"]
257+As an additional note, Crush also stores ephemeral data, such as application
258+state, in one additional location:
262+$HOME/.local/share/crush/crush.json
265+%LOCALAPPDATA%\crush\crush.json
269+> You can override the user and data config locations by setting:
271+> - `CRUSH_GLOBAL_CONFIG`
272+> - `CRUSH_GLOBAL_DATA`
137Crush can use LSPs for additional context to help inform its decisions, just
276Crush can use LSPs for additional context to help inform its decisions, just
@@ -142,7 +281,10 @@ like you would. LSPs can be added manually like so:
142 "$schema": "https://charm.land/crush.json",
281 "$schema": "https://charm.land/crush.json",
145− "command": "gopls"
284+ "command": "gopls",
286+ "GOTOOLCHAIN": "go1.24.5"
147 "typescript": {
289 "typescript": {
148 "command": "typescript-language-server",
290 "command": "typescript-language-server",
@@ -157,10 +299,36 @@ like you would. LSPs can be added manually like so:
160−Crush also supports Model Context Protocol (MCP) servers through three
302+Crush also supports Model Context Protocol (MCP) servers through three transport
161−transport types: `stdio` for command-line servers, `http` for HTTP endpoints,
303+types: `stdio` for command-line servers, `http` for HTTP endpoints, and `sse`
162−and `sse` for Server-Sent Events. Environment variable expansion is supported
304+for Server-Sent Events.
163−using `$(echo $VAR)` syntax.
305+
306+Shell-style value expansion (`$VAR`, `${VAR:-default}`, `$(command)`, quoting,
307+nesting) works in `command`, `args`, `env`, `headers`, and `url`, so
308+file-based secrets work out of the box. You can use values like `"$TOKEN"`
309+or `"$(cat /path/to/secret/token)"`. Expansion runs through Crush's embedded
310+shell, so the same syntax works on every supported system, Windows included.
312+Unset variables expand to the empty string by default, matching bash. For
313+required credentials, use `${VAR:?message}` so an unset variable fails loudly
314+at load time with `message` instead of silently resolving to empty:
317+{ "api_key": "${CODEBERG_TOKEN:?set CODEBERG_TOKEN}" }
320+Headers (both MCP `headers` and provider `extra_headers`) whose value
321+resolves to the empty string are dropped from the outgoing request rather
322+than sent as `Header:`. That keeps optional env-gated headers like
323+`"OpenAI-Organization": "$OPENAI_ORG_ID"` clean when the variable is unset.
325+Provider `extra_body` is a non-expanding JSON passthrough; put env-driven
326+values in `extra_headers` or the provider's `api_key` / `base_url`, all of
329+> **Security note:** `crush.json` is trusted code. Any `$(...)` in it runs at
330+> load time with your shell's privileges, before the UI appears. Don't launch
331+> Crush in a directory whose `crush.json` you haven't reviewed.
@@ -170,20 +338,28 @@ using `$(echo $VAR)` syntax.
170 "type": "stdio",
338 "type": "stdio",
171 "command": "node",
339 "command": "node",
172 "args": ["/path/to/mcp-server.js"],
340 "args": ["/path/to/mcp-server.js"],
343+ "disabled_tools": ["some-tool-name"],
174 "NODE_ENV": "production"
345 "NODE_ENV": "production"
177 "github": {
348 "github": {
178 "type": "http",
349 "type": "http",
179− "url": "https://example.com/mcp/",
350+ "url": "https://api.githubcopilot.com/mcp/",
353+ "disabled_tools": ["create_issue", "create_pull_request"],
180 "headers": {
354 "headers": {
181− "Authorization": "$(echo Bearer $EXAMPLE_MCP_TOKEN)"
355+ "Authorization": "Bearer $GH_PAT"
184 "streaming-service": {
358 "streaming-service": {
185 "type": "sse",
359 "type": "sse",
186 "url": "https://example.com/mcp/sse",
360 "url": "https://example.com/mcp/sse",
187 "headers": {
363 "headers": {
188 "API-Key": "$(echo $API_KEY)"
364 "API-Key": "$(echo $API_KEY)"
@@ -192,10 +368,86 @@ using `$(echo $VAR)` syntax.
195−### Whitelisting Tools
371+### Hooks
373+Crush has preliminary support for hooks. For details, see
374+[the hook guide](./docs/hooks/).
376+### Sharing a workspace across clients
378+When Crush is run against a shared backend (for example two TUIs talking to
379+the same `crush serve`), clients are grouped into **workspaces** keyed by
380+their resolved `--cwd`. Two clients with the same `--cwd` join the same
381+underlying workspace, so they share the session list, message history,
382+permission queue, LSP, and MCP state.
384+Joining is implicit: pointing a second client at the same working directory
385+attaches it to the existing workspace. Each new invocation, however, starts
386+in its own fresh session by default. To pick up the conversation another
387+client already has open, use the session manager (the session picker) and
388+select it. Sessions surface two signals there:
390+- `IsBusy` is set while an agent turn is in flight for that session.
391+- `AttachedClients` reports how many clients are currently viewing it.
393+A non-zero `AttachedClients` (often combined with `IsBusy`) is the cue that a
394+session is "in progress" on another client and joining it will mirror that
397+The first client to create a workspace fixes its process-wide flags. In
398+particular, `--yolo` and `--debug` follow a **first-wins** rule: later
399+clients that arrive at the same `--cwd` with different values for those
400+flags do not change the running workspace. A debug log line is emitted
401+recording the mismatch, and the workspace keeps the flags it was created
404+A workspace lives as long as at least one client has an SSE event stream
405+open against it. When the last stream disconnects, the workspace is torn
406+down. There is a short grace window right after `POST /v1/workspaces` so a
407+client that has created the workspace but not yet opened its event stream
408+does not get reaped before it can attach.
410+### Global context files
412+Crush automatically includes two files for cross-project instructions.
414+- `~/.config/crush/CRUSH.md`: Crush-specific rules that would confuse other
415+ agentic coding tools. If you only use Crush, this is the only one you need to
417+- `~/.config/AGENTS.md`: generic instructions that other coding tools might
418+ read. Avoid referring to Crush-specific features or workflows here. You
419+ probably only care about this if you use multiple agentic coding tools and
420+ want to share instructions between them.
422+You can customize these paths using the `global_context_paths` option in your
427+ "$schema": "https://charm.land/crush.json",
429+ "global_context_paths": [
430+ "~/path/to/custom/context/file.md",
431+ "/full/path/to/folder/of/files/" // recursively load all .md files in folder
439+Crush respects `.gitignore` files by default, but you can also create a
440+`.crushignore` file to specify additional files and directories that Crush
441+should ignore. This is useful for excluding files that you want in version
442+control but don't want Crush to consider when providing context.
444+The `.crushignore` file uses the same syntax as `.gitignore` and can be placed
445+in the root of your project or in subdirectories.
197By default, Crush will ask you for permission before running tool calls. If
449By default, Crush will ask you for permission before running tool calls. If
198−you'd like, you can whitelist tools to be executed without prompting you for
450+you'd like, you can allow tools to be executed without prompting you for
199permissions. Use this with care.
451permissions. Use this with care.
@@ -216,11 +468,204 @@ permissions. Use this with care.
216You can also skip all permission prompts entirely by running Crush with the
468You can also skip all permission prompts entirely by running Crush with the
217`--yolo` flag. Be very, very careful with this feature.
469`--yolo` flag. Be very, very careful with this feature.
471+### Disabling Built-In Tools
473+If you'd like to prevent Crush from using certain built-in tools entirely, you
474+can disable them via the `options.disabled_tools` list. Disabled tools are
475+completely hidden from the agent.
479+ "$schema": "https://charm.land/crush.json",
481+ "disabled_tools": ["bash", "sourcegraph"]
486+To disable tools from MCP servers, see the [MCP config section](#mcps).
490+If you'd like to prevent Crush from using certain skills entirely, you can
491+disable them via the `options.disabled_skills` list. Disabled skills are hidden
492+from the agent, including builtin skills and skills discovered from disk.
496+ "$schema": "https://charm.land/crush.json",
498+ "disabled_skills": ["crush-config"]
505+Crush supports the [Agent Skills](https://agentskills.io) open standard for
506+extending agent capabilities with reusable skill packages. Skills are folders
507+containing a `SKILL.md` file with instructions that Crush can discover and
510+The global paths we looks for skills are:
512+* `$CRUSH_SKILLS_DIR`
513+* `$XDG_CONFIG_HOME/agents/skills` or `~/.config/agents/skills/`
514+* `$XDG_CONFIG_HOME/crush/skills` or `~/.config/crush/skills/`
515+* `~/.agents/skills/`
516+* `~/.claude/skills/`
517+* On Windows, we _also_ look at
518+ * `%LOCALAPPDATA%\agents\skills\` or `%USERPROFILE%\AppData\Local\agents\skills\`
519+ * `%LOCALAPPDATA%\crush\skills\` or `%USERPROFILE%\AppData\Local\crush\skills\`
520+* Additional paths configured via `options.skills_paths`
522+On top of that, we _also_ load skills in your project from the following
532+ "$schema": "https://charm.land/crush.json",
535+ "~/.config/crush/skills", // Windows: "%LOCALAPPDATA%\\crush\\skills",
542+You can get started with example skills from [anthropics/skills](https://github.com/anthropics/skills):
546+mkdir -p ~/.config/crush/skills
547+cd ~/.config/crush/skills
548+git clone https://github.com/anthropics/skills.git _temp
549+mv _temp/skills/* . && rm -rf _temp
553+# Windows (PowerShell)
554+mkdir -Force "$env:LOCALAPPDATA\crush\skills"
555+cd "$env:LOCALAPPDATA\crush\skills"
556+git clone https://github.com/anthropics/skills.git _temp
557+mv _temp/skills/* . ; rm -r -force _temp
560+#### User-Invocable Skills
562+Skills can be made invocable as commands from the commands palette (Ctrl+P). Add `user-invocable: true` to the skill's YAML frontmatter:
567+description: A skill that can be invoked as a command.
572+User-invocable skills appear in the commands palette with a `user:` or `project:` prefix:
573+- Skills from global directories show as `user:skill-name`
574+- Skills from project directories show as `project:skill-name`
576+When invoked, the skill's instructions are loaded into the conversation context.
578+To prevent the model from auto-triggering a skill (while still allowing user invocation), add `disable-model-invocation: true`:
583+description: Only invocable by users, not the model.
585+disable-model-invocation: true
589+Skills with `disable-model-invocation` won't appear in the model's available skills list but can still be invoked manually by users.
591+### Desktop notifications
593+Crush sends desktop notifications when a tool call requires permission and when
594+the agent finishes its turn. They're only sent when the terminal window isn't
595+focused _and_ your terminal supports reporting the focus state.
599+ "$schema": "https://charm.land/crush.json",
601+ "disable_notifications": false, // default
606+To disable desktop notifications, set `disable_notifications` to `true` in your
607+configuration. On macOS, notifications currently lack icons due to platform
612+When you initialize a project, Crush analyzes your codebase and creates
613+a context file that helps it work more effectively in future sessions.
614+By default, this file is named `AGENTS.md`, but you can customize the
615+name and location with the `initialize_as` option:
619+ "$schema": "https://charm.land/crush.json",
621+ "initialize_as": "AGENTS.md"
626+This is useful if you prefer a different naming convention or want to
627+place the file in a specific directory (e.g., `CRUSH.md` or
628+`docs/LLMs.md`). Crush will fill the file with project-specific context
629+like build commands, code patterns, and conventions it discovered during
632+### Attribution Settings
634+By default, Crush adds attribution information to Git commits and pull requests
635+it creates. You can customize this behavior with the `attribution` option:
639+ "$schema": "https://charm.land/crush.json",
642+ "trailer_style": "co-authored-by",
643+ "generated_with": true
649+- `trailer_style`: Controls the attribution trailer added to commit messages
650+ (default: `assisted-by`)
651+ - `assisted-by`: Adds `Assisted-by: Crush:[ModelID]` as specified in [the convention](https://docs.kernel.org/process/coding-assistants.html#attribution)
652+ - `co-authored-by`: Adds `Co-Authored-By: Crush <crush@charm.land>`
653+ - `none`: No attribution trailer
654+- `generated_with`: When true (default), adds `💘 Generated with Crush` line to
655+ commit messages and PR descriptions
219### Custom Providers
657### Custom Providers
221Crush supports custom provider configurations for both OpenAI-compatible and
659Crush supports custom provider configurations for both OpenAI-compatible and
222Anthropic-compatible APIs.
660Anthropic-compatible APIs.
663+> Note that we support two "types" for OpenAI. Make sure to choose the right one
664+> to ensure the best experience!
666+> - `openai` should be used when proxying or routing requests through OpenAI.
667+> - `openai-compat` should be used when using non-OpenAI providers that have OpenAI-compatible APIs.
224#### OpenAI-Compatible APIs
669#### OpenAI-Compatible APIs
226Here’s an example configuration for Deepseek, which uses an OpenAI-compatible
671Here’s an example configuration for Deepseek, which uses an OpenAI-compatible
@@ -231,7 +676,7 @@ API. Don't forget to set `DEEPSEEK_API_KEY` in your environment.
231 "$schema": "https://charm.land/crush.json",
676 "$schema": "https://charm.land/crush.json",
232 "providers": {
677 "providers": {
233 "deepseek": {
678 "deepseek": {
234− "type": "openai",
679+ "type": "openai-compat",
235 "base_url": "https://api.deepseek.com/v1",
680 "base_url": "https://api.deepseek.com/v1",
236 "api_key": "$DEEPSEEK_API_KEY",
681 "api_key": "$DEEPSEEK_API_KEY",
237 "models": [
682 "models": [
@@ -285,6 +730,111 @@ Custom Anthropic-compatible providers follow this format:
735+Crush currently supports running Anthropic models through Bedrock, with caching disabled.
737+- A Bedrock provider will appear once you have AWS configured, i.e. `aws configure`
738+- Crush also expects the `AWS_REGION` or `AWS_DEFAULT_REGION` to be set
739+- To use a specific AWS profile set `AWS_PROFILE` in your environment, i.e. `AWS_PROFILE=myprofile crush`
740+- Alternatively to `aws configure`, you can also just set `AWS_BEARER_TOKEN_BEDROCK`
742+### Vertex AI Platform
744+Vertex AI will appear in the list of available providers when `VERTEXAI_PROJECT` and `VERTEXAI_LOCATION` are set. You will also need to be authenticated:
747+gcloud auth application-default login
750+To add specific models to the configuration, configure as such:
754+ "$schema": "https://charm.land/crush.json",
759+ "id": "claude-sonnet-4@20250514",
760+ "name": "VertexAI Sonnet 4",
761+ "cost_per_1m_in": 3,
762+ "cost_per_1m_out": 15,
763+ "cost_per_1m_in_cached": 3.75,
764+ "cost_per_1m_out_cached": 0.3,
765+ "context_window": 200000,
766+ "default_max_tokens": 50000,
768+ "supports_attachments": true
778+Crush can auto-discovers models from local providers. Add a custom provider
779+with `type` set to `llamacpp`, `omlx`, `lmstudio`, `litellm`, or `ollama`
780+and leave out the models list. Crush will populate the model list
788+ "base_url": "http://localhost:11434/v1/",
795+For llama.cpp (`llama-server`), point at the server's base URL:
801+ "name": "llama.cpp",
802+ "base_url": "http://localhost:2222",
809+#### Manual Model Configuration
811+You can still list models explicitly. User-defined models always take
812+precedence over discovered ones, and any fields you set won't be overwritten
813+by auto-discovery. Auto discovery will run if the model list is empty for any
814+`openai-compat` provider or if you pass `"discover_models": true` it will merge
815+ the found models with your hand configured ones.
822+ "base_url": "http://localhost:11434/v1/",
826+ "name": "Qwen 3 30B",
828+ "context_window": 256000,
829+ "default_max_tokens": 20000
832+ "discover_models": true
288## Logging
838## Logging
290Sometimes you need to look at logs. Luckily, Crush logs all sorts of
840Sometimes you need to look at logs. Luckily, Crush logs all sorts of
@@ -316,26 +866,129 @@ config:
869+## Provider Auto-Updates
871+By default, Crush automatically checks for the latest and greatest list of
872+providers and models from [Catwalk](https://github.com/charmbracelet/catwalk),
873+the open source Crush provider database. This means that when new providers and
874+models are available, or when model metadata changes, Crush automatically
875+updates your local configuration.
877+### Disabling automatic provider updates
879+For those with restricted internet access, or those who prefer to work in
880+air-gapped environments, this might not be want you want, and this feature can
883+To disable automatic provider updates, set `disable_provider_auto_update` into
884+your `crush.json` config:
888+ "$schema": "https://charm.land/crush.json",
890+ "disable_provider_auto_update": true
895+Or set the `CRUSH_DISABLE_PROVIDER_AUTO_UPDATE` environment variable:
898+export CRUSH_DISABLE_PROVIDER_AUTO_UPDATE=1
901+### Manually updating providers
903+Manually updating providers is possible with the `crush update-providers`
907+# Update providers remotely from Catwalk.
908+crush update-providers
910+# Update providers from a custom Catwalk base URL.
911+crush update-providers https://example.com/
913+# Update providers from a local file.
914+crush update-providers /path/to/local-providers.json
916+# Reset providers to the embedded version, embedded at crush at build time.
917+crush update-providers embedded
920+crush update-providers --help
925+Crush records pseudonymous usage metrics (tied to a device-specific hash),
926+which maintainers rely on to inform development and support priorities. The
927+metrics include solely usage metadata; prompts and responses are NEVER
930+Details on exactly what’s collected are in the source code ([here](https://github.com/charmbracelet/crush/tree/main/internal/event)
931+and [here](https://github.com/charmbracelet/crush/blob/main/internal/llm/agent/event.go)).
933+You can opt out of metrics collection at any time by setting the environment
934+variable by setting the following in your environment:
937+export CRUSH_DISABLE_METRICS=1
940+Or by setting the following in your config:
945+ "disable_metrics": true
950+Crush also respects the [`DO_NOT_TRACK`](https://donottrack.sh/) convention
951+which can be enabled via `export DO_NOT_TRACK=1`.
955+### Why is clipboard copy and paste not working?
957+Installing an extra tool might be needed on Unix-like environments.
959+| Environment | Tool |
960+| ------------------- | ------------------------ |
961+| Windows | Native support |
962+| macOS | Native support |
963+| Linux/BSD + Wayland | `wl-copy` and `wl-paste` |
964+| Linux/BSD + X11 | `xclip` or `xsel` |
968+See the [contributing guide](https://github.com/charmbracelet/crush?tab=contributing-ov-file#contributing).
319## Whatcha think?
970## Whatcha think?
321We’d love to hear your thoughts on this project. Need help? We gotchu. You can find us on:
972We’d love to hear your thoughts on this project. Need help? We gotchu. You can find us on:
323- [Twitter](https://twitter.com/charmcli)
974- [Twitter](https://twitter.com/charmcli)
324- [Discord][discord]
976- [Discord][discord]
325−- [Slack](https://charm.land/slack)
326- [The Fediverse](https://mastodon.social/@charmcli)
977- [The Fediverse](https://mastodon.social/@charmcli)
978+- [Bluesky](https://bsky.app/profile/charm.land)
980+[slack]: https://charm.land/slack
328[discord]: https://charm.land/discord
981[discord]: https://charm.land/discord
330## License
983## License
332−[FSL-1.1-MIT](https://github.com/charmbracelet/crush/raw/main/LICENSE)
985+[FSL-1.1-MIT](https://github.com/charmbracelet/crush/raw/main/LICENSE.md)
336Part of [Charm](https://charm.land).
989Part of [Charm](https://charm.land).
338−<a href="https://charm.land/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-next.jpg" /></a>
991+<a href="https://charm.land/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-softy.jpg" /></a>
340<!--prettier-ignore-->
993<!--prettier-ignore-->
341Charm热爱开源 • Charm loves open source
994Charm热爱开源 • Charm loves open source
@@ -2,27 +2,110 @@
3version: "3"
3version: "3"
7+ sh: git describe --long 2>/dev/null || echo ""
9+ sh: test -f race.log && echo "1" || echo ""
13+ GOEXPERIMENT: greenteagc
17+ desc: Install golangci-lint
19+ - go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
21+ GOTOOLCHAIN: go1.25.0
7 desc: Run base linters
24 desc: Run base linters
9 - golangci-lint run --path-mode=abs --config=".golangci.yml" --timeout=5m
27 - golangci-lint run --path-mode=abs --config=".golangci.yml" --timeout=5m
32+ desc: Check that log messages start with capital letters
34+ - ./scripts/check_log_capitalization.sh
11− lint-fix:
36+ lint:fix:
12 desc: Run base linters and fix issues
37 desc: Run base linters and fix issues
14 - golangci-lint run --path-mode=abs --config=".golangci.yml" --timeout=5m --fix
39 - golangci-lint run --path-mode=abs --config=".golangci.yml" --timeout=5m --fix
46+ LDFLAGS: '{{if .VERSION}}-ldflags="-X github.com/charmbracelet/crush/internal/version.Version={{.VERSION}}"{{end}}'
48+ - "go build -v {{if .RACE}}-race{{end}} {{.LDFLAGS}} ."
52+ - internal/agent/**/*.md
53+ - internal/agent/**/*.md.tpl
54+ - internal/agent/hyper/provider.json
62+ - "./crush{{exeExt}} {{.CLI_ARGS}} {{if .RACE}}2>race.log{{end}}"
65+ desc: Run build with local Catwalk
67+ CATWALK_URL: http://localhost:8080
70+ - ./crush{{exeExt}} {{.CLI_ARGS}}
73+ desc: Run build with custom config to test onboarding
75+ CRUSH_GLOBAL_DATA: tmp/onboarding/data
76+ CRUSH_GLOBAL_CONFIG: tmp/onboarding/config
79+ - rm -rf tmp/onboarding
80+ - ./crush{{exeExt}} {{.CLI_ARGS}}
17 desc: Run tests
83 desc: Run tests
19− - go test ./... {{.CLI_ARGS}}
85+ - go test -race -failfast ./... {{.CLI_ARGS}}
88+ desc: Run tests and record all VCR cassettes again
91+ - rm -r internal/agent/testdata
92+ - go test -v -count=1 -timeout=1h ./internal/agent
22 desc: Run gofumpt
95 desc: Run gofumpt
24 - gofumpt -w .
97 - gofumpt -w .
100+ desc: Run prettier on HTML/CSS/JS files
102+ - prettier --write internal/cmd/stats/index.html internal/cmd/stats/index.css internal/cmd/stats/index.js
107+ - go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix -test ./...
27 desc: Run with profiling enabled
110 desc: Run with profiling enabled
@@ -30,6 +113,20 @@ tasks:
31 - go run .
114 - go run .
117+ desc: Install the application
119+ LDFLAGS: '{{if .VERSION}}-ldflags="-X github.com/charmbracelet/crush/internal/version.Version={{.VERSION}}"{{end}}'
122+ - go install {{.LDFLAGS}} -v .
126+ - internal/agent/**/*.md
127+ - internal/agent/**/*.md.tpl
128+ - internal/agent/hyper/provider.json
33 profile:cpu:
130 profile:cpu:
34 desc: 10s CPU profile
131 desc: 10s CPU profile
@@ -50,3 +147,69 @@ tasks:
51 - go run main.go schema > schema.json
148 - go run main.go schema > schema.json
52 - echo "Generated schema.json"
149 - echo "Generated schema.json"
154+ desc: Update Hyper embedded provider.json
156+ - go generate ./internal/agent/hyper/...
158+ - ./internal/agent/hyper/provider.json
161+ desc: Create and push a new tag following semver
164+ sh: svu next --always || go run github.com/caarlos0/svu/v3@latest next --always
165+ prompt: "This will release {{.NEXT}}. Continue?"
167+ - sh: '[ $(git symbolic-ref --short HEAD) = "main" ]'
168+ msg: Not on main branch
169+ - sh: "[ $(git status --porcelain=2 | wc -l) = 0 ]"
171+ - sh: 'gh run list --workflow build.yml --commit $(git rev-parse HEAD) --status success --json conclusion -q ".[0].conclusion" | grep -q success'
172+ msg: "Test build for this commit failed or not present"
173+ - sh: 'gh run list --workflow snapshot.yml --commit $(git rev-parse HEAD) --status success --json conclusion -q ".[0].conclusion" | grep -q success'
174+ msg: "Snapshot build for this commit failed or not present"
177+ - git commit --allow-empty -m "{{.NEXT}}"
178+ - git tag --annotate --sign -m "{{.NEXT}}" {{.NEXT}} {{.CLI_ARGS}}
179+ - echo "Pushing {{.NEXT}}..."
180+ - git push origin main --follow-tags
184+ - git tag -d nightly || true
188+ desc: Update Fantasy and Catwalk
190+ # The Go proxy takes a bit of time to see the latest release. Setting
191+ # these bypass it to ensure we can update to a release from a minute ago.
193+ GONOSUMDB: charm.land/*
195+ - go get charm.land/fantasy@latest
196+ - go get charm.land/catwalk@latest
200+ desc: Generate OpenAPI spec from swag annotations
202+ - go run github.com/swaggo/swag/cmd/swag@v1.16.6 init --generalInfo main.go --dir . --output internal/swagger --packageName swagger --parseDependency --parseInternal --parseDepth 5
204+ - internal/server/*.go
205+ - internal/proto/*.go
208+ - internal/swagger/docs.go
209+ - internal/swagger/swagger.json
210+ - internal/swagger/swagger.yaml
213+ desc: Generate code using SQLC
@@ -1,8 +1,40 @@
2 "$schema": "https://charm.land/crush.json",
2 "$schema": "https://charm.land/crush.json",
5− "command": "gopls"
4+ "gopls": {
10+ "run_govulncheck": true,
13+ "upgrade_dependency": true
16+ "assignVariableTypes": true,
17+ "compositeLiteralFields": true,
18+ "compositeLiteralTypes": true,
19+ "constantValues": true,
20+ "functionTypeParameters": true,
21+ "parameterNames": true,
22+ "rangeVariableTypes": true
26+ "unusedparams": true,
27+ "unusedvariable": true,
32+ "directoryFilters": [
36+ "semanticTokens": true
@@ -1 +0,0 @@
1−{"flagWords":[],"version":"0.2","language":"en","words":["afero","agentic","alecthomas","anthropics","aymanbagabas","azidentity","bmatcuk","bubbletea","charlievieth","charmbracelet","charmtone","Charple","chkconfig","crush","curlie","cursorrules","diffview","doas","Dockerfiles","doublestar","dpkg","Emph","fastwalk","fdisk","filepicker","Focusable","fseventsd","fsext","genai","goquery","GROQ","Guac","imageorient","Inex","jetta","jsons","jsonschema","jspm","Kaufmann","killall","Lanczos","lipgloss","LOCALAPPDATA","lsps","lucasb","makepkg","mcps","MSYS","mvdan","natefinch","nfnt","noctx","nohup","nolint","nslookup","oksvg","Oneshot","openrouter","opkg","pacman","paru","pfctl","postamble","postambles","preconfigured","Preproc","Proactiveness","Puerkito","pycache","pytest","qjebbs","rasterx","rivo","sabhiram","sess","shortlog","sjson","Sourcegraph","srwiley","SSEMCP","Streamable","stretchr","Strikethrough","substrs","Suscriber","systeminfo","tasklist","termenv","textinput","tidwall","timedout","trashhalo","udiff","uniseg","Unticked","urllib","USERPROFILE","VERTEXAI","webp","whatis","whereis","sahilm","csync"]}
docs/hooks/FUTURE.mdnew file+260
@@ -0,0 +1,260 @@
3+This document tracks planned features and design notes for hooks that are not
4+yet implemented. Nothing here is part of the current contract. Treat it as a
5+scratchpad for what's next, not as documentation of current behavior.
8+> This document was largely LLM-generated.
12+**Status:** planned, not implemented.
16+Today, a hook that wants to inject reference material into the agent's context
17+has exactly one knob: `context` (string or array of strings). Whatever the hook
18+puts there is concatenated into what the model sees. That's fine for short notes
19+("current branch: main", "scrubbed secrets") but it scales badly:
21+- Dumping a whole `README.md` or `package.json` into `context` burns tokens on
22+ every tool call where the hook fires.
23+- The model sees the file contents even if it doesn't need them.
24+- Large files can push the turn past the context window.
26+`context_files` is the lazy alternative: the hook returns **paths**, not
27+contents. Crush tells the agent the files exist and are relevant, and the agent
28+decides whether to open them with its existing `view` tool.
32+Additive envelope field. Accepts a list of strings:
37+ "context": "Scrubbed one secret",
38+ "context_files": ["README.md", "docs/ARCHITECTURE.md"],
42+Paths are resolved relative to `CRUSH_CWD`. Non-existent paths are dropped with
43+a debug log (don't fail the hook over a missing file).
45+### How the agent sees it
47+Crush appends a short note to the turn's context along the lines of:
52+- docs/ARCHITECTURE.md
55+No file contents are inlined. The agent opens them with `view` if it decides
56+they're relevant. This keeps cost proportional to need.
60+Matches the existing rules for lists:
62+- Concatenates across matching hooks in config order.
63+- Deduplicates paths (same file referenced by two hooks → listed once).
64+- Dropped entirely if the final decision is `deny` or `halt`.
66+### Backwards compatibility
68+Purely additive. Hooks that don't emit `context_files` are unaffected. Existing
69+envelopes keep working unchanged. No version bump required.
73+- Should `context_files` paths be constrained to `CRUSH_PROJECT_DIR`? Probably
74+ yes, to avoid hooks smuggling in arbitrary filesystem reads.
75+- Do we want a per-file line range (`"README.md:1-40"`) or keep it dead simple
76+ (whole-file references only)? Start simple; add ranges only if asked for.
77+- Should we annotate "why this file is relevant" per entry? An object form
78+ (`{"path": "...", "reason": "..."}`) would allow that but complicates the
79+ schema. Defer until there's a real user need.
83+**Status:** not implemented.
87+Today hooks fire **only** on the top-level agent's tool calls. Sub-agents
88+(`agent` task tool, `agentic_fetch`, future delegated loops) run without hook
89+interception so a single delegated turn doesn't trigger the user's hook N times.
91+The outer sub-agent tool call itself is hooked, so blanket policy like "never
92+spawn sub-agents" or "rewrite prompts sent to the task agent" still works from
93+the coder's side. The sub-agent's inner loop is the part that's exempt.
95+### Why users might want the escape hatch
97+- Audit logging of every tool call, including delegated ones.
98+- Redaction hooks that want to apply uniformly regardless of who called the
100+- Policy that cares about the _tool_ not the _caller_: "never fetch from this
101+ domain, even in `agentic_fetch`."
103+Until someone actually asks, don't ship this. YAGNI.
107+Additive, per-hook. Zero-value matches current default (skip sub-agents):
114+ "matcher": "^bash$",
115+ "command": "./hooks/audit.sh",
116+ "include_sub_agents": true, // default false
123+Implementation changes where `wrapToolsWithHooks` decides to skip. Instead of a
124+single `isSubAgent` bailout, the runner filters per-hook matches by the hook's
125+`include_sub_agents` flag. Hooks that opt in get wrapped into sub-agent tool
126+slices too; everything else stays skipped.
128+### Backwards Compatibility
130+Purely additive. Hooks that don't set `include_sub_agents` get the default
131+(`false` = skip sub-agents). No wire format change, no version bump. The initial
132+transition from "hooks fire everywhere" to "hooks skip sub-agents by default"
133+was a one-time behavior change; adding the opt-in is pure addition.
135+### Side benefit: payload awareness
137+Extend the stdin payload with `"is_sub_agent": true|false` so hook scripts that
138+opt in can branch on caller type ("audit top-level and sub-agent calls
139+differently"). Also purely additive — hooks that don't read the field are
144+- Per-hook flag (above) vs a global `hooks.include_sub_agents` default? A global
145+ toggle is simpler but coarse-grained; per-hook is more flexible and
146+ composable. Start per-hook; a global default can be layered on later with
147+ explicit precedence ("per-hook overrides global").
148+- Does an opt-in hook see hooks from _nested_ sub-agents too (a sub-agent that
149+ itself calls a sub-agent)? Probably yes — once you've opted in you want the
150+ full tree. But call it out explicitly in docs so users aren't surprised by N²
151+ explosions on pathological configs.
153+## `UserPromptSubmit` event
155+**Status:** not implemented.
159+Today Crush supports exactly one hook event, `PreToolUse`. That's enough to gate
160+and rewrite tool calls but nothing else. The next-most-useful event is
161+`UserPromptSubmit`: fires after the user hits Enter but before the turn hits the
162+LLM. Lets hooks inject context, rewrite prompts, or gate on content without the
163+mutation complexity of `PostToolUse` (output scrubbing, error coercion, size
164+limits — all rabbit holes).
168+- Prepend project context the user didn't think to include ("current branch:
169+ `feat/x`; last commit: `<sha> <title>`").
170+- Point at reference files via `context_files` (when that lands) so the agent
171+ knows where to look without being force-fed contents.
172+- Redact secrets out of the prompt before it leaves the machine.
173+- Refuse prompts matching a policy ("don't send anything mentioning
174+ `production.env`") — with `deny` and a reason the user sees.
175+- Expand shorthand (`@TODO` → "please address the TODO in …").
179+Stdin payload extends the common envelope with the prompt:
183+ "event": "UserPromptSubmit",
185+ "cwd": "/home/user/project",
186+ "prompt": "fix the login flow",
187+ "attachments": ["screenshot.png"],
191+Output envelope reuses common fields plus one new per-event field,
196+ "decision": "allow", // optional; deny blocks the submission entirely
197+ "reason": "includes a production secret", // shown to the user when denying
198+ "context": "Current branch: feat/login",
199+ "updated_prompt": "fix the login flow\n\n(from @TODO on line 42)",
203+`updated_prompt` is a **full replacement** — not a merge patch — because a
204+prompt is a single string with no natural key structure. If multiple hooks emit
205+`updated_prompt`, later hooks in config order win.
209+Reuses the universal rules:
211+- `halt` is sticky. Halts the whole turn before the LLM is called.
212+- `context` concatenates in config order.
213+- `updated_prompt`: last writer wins.
214+- `decision: "deny"` blocks the submission. The user sees `reason`; the turn
215+ never reaches the LLM.
217+### Differences from `PreToolUse`
219+- No `updated_input`: there are no tool inputs at this point.
220+- No permission-prompt bypass: there's no permission prompt for a user prompt.
221+- `decision: "allow"` is functionally identical to silence. It exists only for
222+ symmetry with `PreToolUse` and to give hook authors a consistent vocabulary.
223+ (Could be argued both ways — consider dropping it here.)
224+- Fires on every user submission, including follow-ups in the same session.
225+ Hooks should be fast; no subprocess-per-keystroke scenarios but the per-turn
228+### Implementation sketch
230+- New event constant `EventUserPromptSubmit` in `internal/hooks/hooks.go`.
231+- `Runner.Run` already takes an event name; no interface change.
232+- A new call site in `sessionAgent.Run` (or the coordinator's Run path) that
233+ fires hooks after creating the user message but before the first LLM call. If
234+ the aggregate decision is `deny` or `halt`, abort the turn and surface
235+ `reason` to the user.
236+- If hooks return `context`, prepend it to the prompt seen by the LLM (or attach
237+ as a system-message-level note — decide based on how the prompt is threaded
239+- If hooks return `updated_prompt`, replace the prompt body before the first LLM
240+ call. The message row in the DB should still store the _original_ prompt so
241+ the user sees what they typed; only the outbound version is rewritten. (Or:
242+ store both, show the original, send the rewritten — mirror how `updated_input`
247+- Store original vs rewritten prompt? Probably both, with UI showing original
248+ and a subtle indicator that a hook modified it.
249+- Do hooks fire on queued prompts too, or only when actually dispatched? If the
250+ user queues three prompts and the hook blocks the second, what happens to the
251+ third? Simplest rule: fire when dispatched; denial skips to the next queued
252+ prompt with a visible note.
253+- What about the `/commands` prefix? Does `UserPromptSubmit` fire for slash
254+ commands, or are those intercepted earlier? Probably earlier — hooks see only
255+ freeform prompts that would actually reach the LLM.
257+## Cross-platform shell (Windows support)
259+**Status:** implemented. See the [Execution model](README.md#execution-model)
260+section in `README.md` for the current behavior and contract.
docs/hooks/README.mdnew file+759
@@ -0,0 +1,759 @@
4+> This document was designed for both humans and agents.
6+Hooks are user-defined shell scripts that run when various events happen during
7+the agent lifecycle, allowing you to both build on top of Crush, customize
8+its behavior, and exert deterministic control over an agent's wily behavior.
10+Hooks are just shell commands, and were designed to be both simple and future
15+- Hooks are just shell commands
16+- Hooks can be written in any language because they’re just executables: Bash, Python, Node, Rust, Haskell, whatever
17+- Hooks are Claude Code-compatible
18+- Crush ships with a builtin `crush-hook` skill write, edit, and configure
19+ hooks; just tell Crush how to configure Crush
20+- Crush currently supports just one hook, `PreToolUse`, with plans to support
21+ the full gamut; please let us know which hooks you'd like to see next
22+- Hooks run in parallel for speed, but their results compose in config order
25+### Some things you can do with hooks:
27+- Block "dangerous" commands: no more `git push -f` or `cabal init`
28+- Rewrite tool input: turn `node` calls info `deno`, scrub secrets from
29+ commands, rewrite all mentions of "Haskell" into "Haskell, The Best
31+- Inject context: add notes to the model's context whenever certain tools are
32+ called. For example: "remember to run gofumpt after editing Go files"
33+- Auto-approve tools: skip the permission prompt for bash commands that
35+- Log certain tool calls
37+…And lots more. Show us what you're building!
41+Let's just dive into it and make a simple hook. This particular hook will
42+disallow the use of Haskell (but we love you, Simon Peyton Jones).
46+The first thing we need to do is hook up our hook. Let's add the following to
47+our **project-level** `crush.json`. Relative paths like `./no-haskell.sh` work
48+here because the project root is your working directory. If you're configuring
49+a global hook (`~/.config/crush/crush.json`), use an absolute path instead.
53+ // As expected, hooks go in a "hooks" object.
55+ // PreToolUse is an event that fires before a tool is used.
58+ // What tool do we want to hook into? In this case, Bash, because it
59+ // runs the stuff we wanna block.
62+ // The path to our actual hook script.
63+ "command": "./no-haskell.sh",
70+Now, let's make our `no-haskell.sh` hook script.
75+# Disallow ghc, cabal, and stack. Pipe the bash command output
76+# ($CRUSH_TOOL_INPUT_COMMAND) to grep and match on a regexp.
77+if echo "$CRUSH_TOOL_INPUT_COMMAND" | grep -qE '(^| )((ghc|cabal|stack)(\.exe)?)( |$)'; then
79+ # Someone is trying to use Haskell. Let's send a message back to the model
80+ # and user explaining why we're blocking this. Note that we send all feedback
81+ # like this to stderr.
82+ echo "No Haskell allowed, kiddo." >&2
84+ # Now, block the tool call by exiting with code 2.
89+That's basically it. For the full guide on how hooks work, however, read on.
95+Hooks run through Crush's embedded POSIX shell (`mvdan.cc/sh`) — the same
96+interpreter the `bash` tool uses. Inline commands and shebang-less scripts
97+execute in-process; scripts with a `#!` shebang dispatch to the named
98+interpreter via `os/exec`. This contract is identical on macOS, Linux, and
101+What this means in practice:
103+- **Windows without Unix tooling**: inline shell (`echo`, pipelines, `jq`,
104+ `grep`), shebang-less `.sh` scripts, inline PowerShell
105+ (`powershell -Command …`), and `.exe` invocations all work out of the box
106+ with no WSL, Git Bash, Cygwin, or MSYS required.
107+- **PowerShell scripts** (`.ps1`) are not auto-dispatched by extension.
108+ Invoke them explicitly: `powershell -File ./audit.ps1` (or
109+ `pwsh -File ./audit.ps1`).
110+- **Shebang'd scripts** require the named interpreter on `PATH`. Git for
111+ Windows ships `bash.exe`, which makes `#!/bin/bash` and
112+ `#!/usr/bin/env bash` scripts work on Windows the same way they do on
113+ Unix. CRLF line endings in the shebang line are tolerated.
114+- **Permissive shebang fallback**: if the absolute path in a shebang
115+ doesn't exist (e.g. `#!/bin/bash` on Windows), Crush falls back to a
116+ `PATH` lookup of the base name (`bash`) before giving up. A debug-level
117+ log records the fallback. If the interpreter isn't on `PATH` either, the
118+ hook fails cleanly as a non-blocking warning and the agent proceeds as
120+- **Environment**: every hook sees `CRUSH=1`, `AGENT=crush`, and
121+ `AI_AGENT=crush` on top of the `CRUSH_*` hook-specific variables. These
122+ three markers are guaranteed and match what the `bash` tool sets, so
123+ scripts that detect "am I being run by an AI agent?" behave the same in
125+- **Timeout behavior**: when a hook exceeds its timeout, Crush cancels the
126+ context and waits a short grace period (~1s) for the interpreter to
127+ yield. If the hook still hasn't returned, Crush abandons it, logs a
128+ warning, and treats the result as "no opinion" so the agent can proceed.
129+ Long-running work should honor context cancellation or run in a
130+ subprocess via a shebang.
134+Hooks can be added to your `crush.json` (or `.crush.json`) at both the global
135+and project-level, with project level hooks taking precedence.
142+ "name": "no-rm-rf", // friendly name shown in the TUI
143+ "matcher": "bash", // regex tested against the tool name
144+ "command": "./hooks/my-hot-hook.sh", // the path to the hook
145+ "timeout": 10, // in seconds; default 30
153+> The `command` is resolved relative to your **current working directory** —
154+> not relative to the config file. Relative paths like `./hooks/whatever.sh`
155+> work fine in project-level `crush.json` because the project root is also
156+> your working directory. For **global** config (`~/.config/crush/`),
157+> however, you must use either an absolute path or an inline command:
160+> // Global ~/.config/crush/crush.json
165+> "command": "/home/you/.config/crush/hooks/no-haskell.sh"
166+> // or use an inline command:
167+> // "command": "echo '{\"decision\":\"allow\"}'"
174+Remember, hooks will run in parallel but resolve in config order. Last hook
175+wins when rewriting input, but first deny wins when blocking.
179+Here are the events you can hook into (spoiler: there's currently just one):
183+This hook fires before every tool call. Use it to block dangerous commands,
184+enforce policies, rewrite tool input, inject context the model should see, log
187+**Matched against**: the tool name (e.g. `bash`, `edit`, `write`,
188+`mcp_github_create_pull_request`).
191+> Event names are case insensitive and snake-caseable, so `PreToolUse`,
192+> `pretooluse`, `PRETOOLUSE`, `pre_tool_use`, and `PRE_TOOL_USE` all work.
194+**Scope**: `PreToolUse` only fires on the **top-level agent's** tool calls.
195+Sub-agents (the `agent` task tool, `agentic_fetch`, etc.) run without hook
196+interception so a single delegated turn doesn't trigger your hook N times. The
197+outer sub-agent tool call itself _is_ hooked, so policy like "never let the
198+agent spawn sub-agents" still works.
200+Hooks are keyed by event name. Only `command` is required, and you can omit
201+`matcher` to match all tools.
205+When a hook fires, Crush:
207+1. Filters hooks whose `matcher` regex matches the tool name (no matcher = match
209+2. Deduplicates by `command` (identical commands run once).
210+3. Runs all matching hooks **in parallel** through Crush's embedded POSIX
211+ shell (see [Execution model](#execution-model)).
212+4. Waits for all to finish (or time out), then aggregates results **in config
213+ order**: deny wins over allow, allow wins over none; `updated_input` patches
214+ shallow-merge in order.
215+5. Applies the result **before** permission checks. If the aggregated decision
216+ is `deny`, the tool call is blocked and you never see a permission prompt
217+ for it. If it's `allow`, Crush treats that as affirmative pre-approval and
218+ also skips the prompt. Silence (no decision) falls through to the normal
221+Note that you can omit `matcher` and match in your shell script instead,
222+however you'll incur some additional overhead as Crush will still parse and
227+Each hook receives data two ways: environment variables and stdin (as JSON).
228+Environment variables are typically easier to work with, with JSON being
229+available when input is more complex.
231+#### Environment Variables
233+The available environment variables are:
235+| Variable | Description |
236+| ---------------------------- | ---------------------------------------------- |
237+| `CRUSH` | Always `1` when running under Crush. |
238+| `AGENT` | Always `crush`. |
239+| `AI_AGENT` | Always `crush`. |
240+| `CRUSH_EVENT` | The hook event name (e.g. `PreToolUse`). |
241+| `CRUSH_TOOL_NAME` | The tool being called (e.g. `bash`). |
242+| `CRUSH_SESSION_ID` | Current session ID. |
243+| `CRUSH_CWD` | Working directory. |
244+| `CRUSH_PROJECT_DIR` | Project root directory. |
245+| `CRUSH_TOOL_INPUT_COMMAND` | For `bash` calls: the shell command being run. |
246+| `CRUSH_TOOL_INPUT_FILE_PATH` | For file tools: the target file path. |
248+The `CRUSH`, `AGENT`, and `AI_AGENT` markers are also set by the `bash`
249+tool, so a script can detect "am I running under Crush?" the same way in
254+Standard input provides the full context as JSON:
258+ "event": "PreToolUse", // Hook event name
259+ "session_id": "313909e", // Current session ID
260+ "cwd": "/home/user/project", // Working directory
261+ "tool_name": "bash", // The tool being called
262+ "tool_input": { "command": "rm -rf /" }, // The tool's input
266+Note that `tool_input` field contains the raw JSON the model sent to the tool.
268+To parse the stdin JSON in your hook script, read from stdin and use a tool like
274+tool_name=$(echo "$input" | jq -r '.tool_name')
275+command=$(echo "$input" | jq -r '.tool_input.command // empty')
278+You can also use tools like Python:
281+#!/usr/bin/env python3
284+data = json.load(sys.stdin)
285+tool_name = data.get("tool_name", "")
286+command = data.get("tool_input", {}).get("command", "")
291+Hooks communicate back to Crush via **exit code** and `stdout`/`stderr`. The
292+simplest way to do this is to return an error code and print additional context
293+to stderr. For example:
296+# Here, error code 2 blocks the tool, using stderr as the reason:
297+if some_bad_condition; then
298+ echo "Blocked: reason here" >&2
303+| Exit Code | Meaning |
304+| --------- | ---------------------------------------------------------------- |
305+| 0 | Success. Stdout is parsed as JSON (see fields below). |
306+| 2 | **Block the tool.** Stderr is used as the deny reason (no JSON). |
307+| 49 | **Halt the turn.** Stderr is used as the halt reason (no JSON). |
308+| Other | Non-blocking error. Logged and ignored — the tool call proceeds. |
310+The difference between exit 2 and exit 49:
312+- **Exit 2** blocks the current tool call. The agent sees the error and can try
314+- **Exit 49** halts the whole turn. The agent doesn't get to respond further;
315+ the user takes over. Use this when something is wrong enough that the agent
316+ shouldn't keep trying. 49 sits in an empty slice of the exit-code space —
317+ between the generic-error range (1-30), the BSD `sysexits.h` range (64-78),
318+ and the killed-by-signal range (128+) — so it can't be hit by accident.
320+That said, if you need more control, or if you need to rewrite input, you can
321+use JSON on stdout. Exit 0 and print a JSON object to provide context, update
322+the input, or still deny/halt with a reason:
326+ "version": 1, // Output envelope version. Optional; defaults to 1.
327+ "decision": "allow", // "allow", "deny", or null. Omit for no opinion.
328+ "halt": false, // If true, halts the turn entirely.
329+ "reason": "LGTM", // Shown when denying or halting.
330+ "context": "Scrubbed secrets", // String or array of strings. Appended to what the model sees.
331+ "updated_input": { "command": "…" }, // Shallow-merged into the tool's input before execution.
335+`version` is an optional integer at the top of the envelope. It defaults to `1`
336+if omitted. Unknown higher versions are still parsed; the field exists so the
337+envelope can evolve without a compatibility shim.
339+`decision: "allow"` is **affirmative**: it pre-approves the tool call and
340+bypasses the permission prompt entirely. Silence (no `decision`, or
341+`decision: null`) means "no opinion" — the tool still goes through the
342+normal permission flow. Use `"allow"` when you want to auto-approve; omit it
343+when you only want to inject context or rewrite input without also vouching
346+`updated_input` is a shallow-merge patch. Keys you include overwrite matching
347+keys in `tool_input`; keys you don't include are preserved. If the model called
348+`bash` with `{"command": "npm test", "timeout": 60000}` and your hook returns
349+`{"updated_input": {"command": "bun test"}}`, the tool runs with
350+`{"command": "bun test", "timeout": 60000}` — the timeout isn't dropped. The
351+merge is shallow: nested objects are replaced wholesale, not deep-merged.
353+`halt: true` stops the turn entirely. The agent doesn't get to respond further;
354+the user takes over. The exit-code shorthand is `exit 49` with stderr as the
357+`context` accepts either a string or an array of strings. Use the string form
358+for a single observation; use the array form when a hook produces multiple
359+distinct notes and you'd rather not concatenate them by hand. Empty strings and
360+empty array entries are dropped.
362+Here's a full shell script that produces this JSON:
366+# Example: rewrite a bash command using RTK
369+original_cmd=$(echo "$input" | jq -r '.tool_input.command')
370+rewritten=$(secret-scrubber rewrite "$original_cmd")
374+ "decision": "allow",
375+ "context": "Scrubbed secrets",
376+ "updated_input": {"command": "$rewritten"}
383+Hooks run in parallel, but their results compose in config order. Whichever hook
384+finishes first doesn't get to "win" by virtue of timing; composition is
385+deterministic based on the order hooks appear in `crush.json`.
387+When multiple hooks match the same tool call:
389+- If **any** hook denies, the tool call is blocked. `reason` values are
390+ concatenated in config order (newline-separated).
391+- If **any** hook halts, the turn ends after the tool call is blocked.
392+- If no hook denies or halts but at least one allows, the tool call proceeds
393+ **and the permission prompt is skipped**.
394+- `context` values are concatenated in config order. Strings and arrays compose
395+ uniformly — each string becomes one entry, and array entries are flattened in.
396+- `updated_input` patches shallow-merge in config order against the original
397+ tool input. Later hooks override earlier ones on colliding keys. If denied or
398+ halted, `updated_input` patches are ignored.
402+If a hook exceeds its timeout, Crush cancels its context and treats the
403+result as a non-blocking error so the tool call proceeds. The default
404+timeout is 30 seconds. Shebang-dispatched subprocesses are killed through
405+`exec.CommandContext`; in-process hooks get a short grace period to yield
406+and are then abandoned (the agent moves on regardless). Long-running work
407+should honor context cancellation or run out-of-process via a shebang.
411+### Block destructive commands
413+Prevent the agent from running `rm -rf` in bash:
420+ "matcher": "^bash$",
421+ "command": "./hooks/no-rm-rf.sh"
432+# Block rm -rf commands in the bash tool. Otherwise stay silent so the
433+# normal permission flow runs.
435+if echo "$CRUSH_TOOL_INPUT_COMMAND" | grep -qE 'rm\s+-(rf|fr)\s+/'; then
436+ echo "Refusing to run rm -rf against root" >&2
443+### Auto-approve read-only tools
445+Skip the permission prompt for tools that can't change anything. The hook
446+returns `decision: "allow"`, which tells Crush to pre-approve the call:
453+ "matcher": "^(view|ls|grep|glob)$",
454+ "command": "echo '{\"decision\":\"allow\"}'",
461+No script file needed — the command is inline. Every `view`/`ls`/`grep`/`glob`
462+call now runs without prompting. Add the `bash` tool to this list at your own
463+risk; consider a more targeted allowlist instead:
467+# hooks/safe-bash.sh — auto-approve read-only bash commands.
469+case "$CRUSH_TOOL_INPUT_COMMAND" in
470+ ls*|cat*|grep*|rg*|echo*|pwd*)
471+ echo '{"decision":"allow"}'
474+ # Silent — fall through to the normal permission prompt.
480+### Inject context into file writes
482+Add a reminder to the model whenever it writes a Go file:
489+ "matcher": "^(edit|write|multiedit)$",
490+ "command": "./hooks/go-context.sh"
497+`hooks/go-context.sh`:
501+# Remind the model about Go formatting when editing .go files.
502+# Emit context only; stay silent on `decision` so the normal permission
503+# prompt still runs for edits/writes.
505+if [[ "$CRUSH_TOOL_INPUT_FILE_PATH" == *.go ]]; then
506+ echo '{"context": "Remember: run gofumpt after editing Go files."}'
512+### Block all MCP tools
514+The `command` can be inline. This one-liner matches all MCP tools and blocks
518+{ "matcher": "^mcp_", "command": "echo 'MCP tools are disabled' >&2; exit 2" }
521+### Log every tool call
523+With no `matcher` this fires for every tool. It exits 0 with no stdout so the
524+tool call always proceeds.
527+{ "command": "echo \"$(date -Iseconds) $CRUSH_TOOL_NAME\" >> ./tools.log" }
530+### A real-world Example:
532+For a more practical example, see [`rtk-rewrite.sh`](./examples/rtk-rewrite.sh),
533+which demonstrates how to rewrite tool input using
534+[RTK](https://github.com/rtk-ai/rtk) to save tokens.
536+### Using other languages
538+Hooks aren't limited to shell scripts: any executable works. Here's the same
539+"block rm -rf" example in some other languages.
543+`{"matcher": "^bash$", "command": "lua ./hooks/no-rm-rf.lua"}`
546+local input = io.read("*a")
547+local tool_input = input:match('"command":"(.-)"') or ""
549+if tool_input:match("rm%s+%-[rf][rf]%s+/") then
550+ io.stderr:write("Refusing to run rm -rf against root\n")
557+`{"matcher": "^bash$", "command": "node ./hooks/no-rm-rf.js"}`
561+process.stdin.on("data", (chunk) => (input += chunk));
562+process.stdin.on("end", () => {
563+ const { tool_input: toolInput } = JSON.parse(input);
565+ if (/rm\s+-[rf]{2}\s+\//.test(toolInput.command)) {
566+ process.stderr.write("Refusing to run rm -rf against root\n");
574+## Claude Code compatibility
576+Crush hooks are broadly compatible with [Claude Code
577+hooks](https://docs.claude.com/en/docs/claude-code/hooks): the config shape,
578+stdin payload, output envelope, and exit codes line up so most Claude Code
579+hooks run under Crush unchanged. This document covers the Crush-specific API
580+only — anything not documented here isn't guaranteed to work.
582+One intentional divergence: Crush treats `updated_input` as a shallow-merge
583+patch against the original `tool_input` rather than a full replacement. Keys
584+you omit are preserved. See [Output](#output) for details.
590+This is the official reference of the narrative above. If prose and this section
591+disagree, the prose should be presumed canonical for intent, while this section
592+is canonical for shape.
594+Both the stdin payload and the output envelope have **common fields** that apply
595+to every event and **per-event fields** that only some events recognize. When an
596+event doesn't understand a field, it's ignored.
600+Each entry under a `hooks.<EventName>` array:
604+ // string. Optional. Friendly display name shown in the TUI. Falls back to
605+ // command when omitted.
608+ // string. Optional. Regex tested against the tool name. Omit to match all.
609+ "matcher": "^bash$",
611+ // string. Required. Shell command to run.
612+ "command": "./hooks/my-hook.sh",
614+ // number. Optional. Seconds before the hook is killed. Defaults to 30.
619+### Stdin payload (common)
621+Present in every hook event:
625+ // string. Hook event name.
626+ "event": "PreToolUse",
628+ // string. Current session ID.
629+ "session_id": "313909e",
631+ // string. Working directory when invoked.
632+ "cwd": "/home/user/project",
636+### Stdin payload — PreToolUse
638+Extends the common payload:
642+ // ...common fields...
644+ // string. The tool being called.
645+ "tool_name": "bash",
647+ // object. Raw JSON input the model sent to the tool. Shape is per-tool.
649+ "command": "npm test",
654+### Output envelope (common)
656+Fields a hook may print to stdout on exit 0. All are optional and apply to every
661+ // number. Defaults to 1. Unknown higher values still parse; exists for
665+ // boolean. If true, ends the turn entirely. User takes over.
668+ // string. Shown when denying (to the model) or halting (to the model and
670+ "reason": "not allowed",
672+ // string | string[]. Appended to what the model sees. Empty entries are
674+ "context": "Rewrote with RTK",
678+### Output envelope — PreToolUse
680+Extends the common envelope:
684+ // ...common fields...
686+ // "allow" | "deny" | null. null/omitted = no opinion, the tool still goes
687+ // through the normal permission prompt. "allow" is affirmative: pre-approves
688+ // the tool call and bypasses the prompt. "deny" blocks the call; the model
689+ // sees the error and may try something else.
690+ "decision": "allow",
692+ // object. Shallow-merge patch against tool_input. Nested objects are
693+ // replaced wholesale, not deep-merged.
695+ "command": "bun test",
703+| ----- | ------------------------------------------------------------------------ |
704+| `0` | Success. Stdout is parsed as the output envelope. |
705+| `2` | Block this tool call. Stderr becomes the deny reason. Stdout is ignored. |
706+| `49` | Halt the whole turn. Stderr becomes the halt reason. Stdout is ignored. |
707+| other | Non-blocking error. Logged and ignored; the tool call proceeds. |
709+Exit `2` only applies to events that can block something. On events where
710+there's nothing to block, it's treated as a non-blocking error.
714+When multiple hooks match the same event, results compose in **config order**.
718+1. `halt` is sticky: if any hook halts, the turn ends.
719+2. `reason` values concatenate with `\n` in config order. Halt-only hooks
720+ without a deny still contribute their reason.
721+3. `context` values concatenate with `\n` in config order. String entries and
722+ array entries flatten uniformly.
724+PreToolUse-specific rules:
726+4. `decision` precedence: `deny` > `allow` > `null`. First deny determines the
727+ outcome; subsequent allows don't override. If the final aggregated decision
728+ is `allow`, Crush pre-approves the tool call and skips the permission
729+ prompt. If it's `null` (no hook allowed), the tool goes through the normal
731+5. `updated_input` patches shallow-merge sequentially against the original
732+ `tool_input`. Later patches override earlier ones on colliding keys. Patches
733+ are **ignored** if the final decision is deny or halt.
735+### Environment variables
737+See [Environment Variables](#environment-variables) above for the full list.
743+We'd love to hear your thoughts on this project. Need help? We gotchu. You can
746+- [Twitter](https://twitter.com/charmcli)
747+- [Slack](https://charm.land/slack)
748+- [Discord](https://charm.land/discord)
749+- [The Fediverse](https://mastodon.social/@charmcli)
750+- [Bluesky](https://bsky.app/profile/charm.land)
754+Part of [Charm](https://charm.land).
756+<a href="https://charm.land/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-softy.jpg" /></a>
758+<!--prettier-ignore-->
759+Charm热爱开源 • Charm loves open source
docs/hooks/examples/rtk-rewrite.shnew file+60
@@ -0,0 +1,60 @@
4+# This hook rewrites bash commands to use rtk for token savings.
6+# https://github.com/rtk-ai/rtk
8+# Requires: rtk >= 0.23.0, jq
10+# All rewrite logic lives in `rtk rewrite`, which is the single source of
11+# truth. To add or change rewrite rules, edit the Rust registry, not this
14+# Exit code protocol for `rtk rewrite`:
15+# 0 + stdout Rewrite found → allow with updated input
16+# 1 No RTK equivalent → pass through unchanged
17+# 2 Deny rule matched → pass through
21+if ! command -v jq &>/dev/null; then
22+ echo "[rtk] WARNING: jq is not installed. Install: https://jqlang.github.io/jq/download/" >&2
26+if ! command -v rtk &>/dev/null; then
27+ echo "[rtk] WARNING: rtk is not installed. Install: https://github.com/rtk-ai/rtk#installation" >&2
31+# Version guard: rtk rewrite requires >= 0.23.0.
32+RTK_VERSION=$(rtk --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
33+if [ -n "$RTK_VERSION" ]; then
34+ MAJOR=$(echo "$RTK_VERSION" | cut -d. -f1)
35+ MINOR=$(echo "$RTK_VERSION" | cut -d. -f2)
36+ if [ "$MAJOR" -eq 0 ] && [ "$MINOR" -lt 23 ]; then
37+ echo "[rtk] WARNING: rtk $RTK_VERSION is too old (need >= 0.23.0). Upgrade: cargo install rtk" >&2
42+CMD="${CRUSH_TOOL_INPUT_COMMAND:-}"
43+if [ -z "$CMD" ]; then
47+REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null) && EXIT_CODE=0 || EXIT_CODE=$?
51+ # Rewrite found. If identical, the command already uses rtk.
52+ [ "$CMD" = "$REWRITTEN" ] && exit 0
53+ jq -n --arg cmd "$REWRITTEN" \
54+ '{decision: "allow", updated_input: ({command: $cmd} | tostring)}'
57+ # No rewrite (1), deny (2), or unexpected — pass through.
@@ -0,0 +1,60 @@
8+ "lastModified": 1731533236,
9+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
11+ "repo": "flake-utils",
12+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
17+ "repo": "flake-utils",
23+ "lastModified": 1782964654,
24+ "narHash": "sha256-oqyac50OyRdni5ZK9H7ZuAJoR3LzgsOdUcbBlUsk9lg=",
27+ "rev": "3130a1cf8f7c794ea5a4760c3fa4c745d64ec269",
38+ "flake-utils": "flake-utils",
44+ "lastModified": 1681028828,
45+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
46+ "owner": "nix-systems",
48+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
52+ "owner": "nix-systems",
@@ -0,0 +1,75 @@
2+ description = "Crush development environment";
5+ nixpkgs.url = "github:NixOS/nixpkgs";
6+ flake-utils.url = "github:numtide/flake-utils";
14+ flake-utils.lib.eachDefaultSystem (
16+ pkgs = nixpkgs.legacyPackages.${system};
19+ packages.default = pkgs.buildGoModule {
27+ # Match the Go toolchain used in the dev shell.
35+ "-X github.com/charmbracelet/crush/internal/version.Version=${version}"
38+ # The test suite requires network access and external tools.
42+ description = "Terminal-based AI coding assistant";
43+ homepage = "https://github.com/charmbracelet/crush";
44+ license = pkgs.lib.licenses.mit;
45+ mainProgram = "crush";
49+ devShells.default = pkgs.mkShell {
50+ buildInputs = with pkgs; [
55+ gopls # Go language server
56+ golangci-lint # Linter
57+ gofumpt # Formatter (stricter than gofmt)
58+ go-task # Task runner
62+ git # Version control
64+ svu # Semantic version utility
65+ sqlc # SQL code generator
69+ # Set Go environment variables
@@ -1,149 +1,221 @@
1module github.com/charmbracelet/crush
1module github.com/charmbracelet/crush
6+ charm.land/bubbles/v2 v2.1.1
7+ charm.land/bubbletea/v2 v2.0.8
8+ charm.land/catwalk v0.49.0
9+ charm.land/fang/v2 v2.0.1
10+ charm.land/fantasy v0.35.0
11+ charm.land/glamour/v2 v2.0.1
12+ charm.land/lipgloss/v2 v2.0.5
13+ charm.land/log/v2 v2.0.0
14+ charm.land/x/vcr v0.1.1
6 github.com/JohannesKaufmann/html-to-markdown v1.6.0
15 github.com/JohannesKaufmann/html-to-markdown v1.6.0
7 github.com/MakeNowJust/heredoc v1.0.0
16 github.com/MakeNowJust/heredoc v1.0.0
17+ github.com/Microsoft/go-winio v0.6.2
8− github.com/PuerkitoBio/goquery v1.9.2
18+ github.com/PuerkitoBio/goquery v1.12.0
9− github.com/alecthomas/chroma/v2 v2.15.0
19+ github.com/alecthomas/chroma/v2 v2.27.0
10− github.com/anthropics/anthropic-sdk-go v1.6.2
11− github.com/atotto/clipboard v0.1.4
12− github.com/aymanbagabas/go-udiff v0.3.1
20+ github.com/aymanbagabas/go-udiff v0.4.1
13− github.com/bmatcuk/doublestar/v4 v4.9.0
21+ github.com/bmatcuk/doublestar/v4 v4.10.0
14− github.com/charlievieth/fastwalk v1.0.11
22+ github.com/charlievieth/fastwalk v1.0.14
15− github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250716191546-1e2ffbbcf5c5
23+ github.com/charmbracelet/colorprofile v0.4.3
16− github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.4.0.20250724172607-5ba56e2bec69
17− github.com/charmbracelet/catwalk v0.3.5
18− github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674
24+ github.com/charmbracelet/openai-go v0.0.0-20260617131321-5e4b9c18c4be
19− github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe
25+ github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7
20− github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3.0.20250721205738-ea66aa652ee0
21− github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706
22− github.com/charmbracelet/x/ansi v0.9.3
26+ github.com/charmbracelet/x/ansi v0.11.7
27+ github.com/charmbracelet/x/editor v0.2.0
28+ github.com/charmbracelet/x/etag v0.2.0
23− github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3
29+ github.com/charmbracelet/x/exp/charmtone v0.0.0-20260527151214-009e6338d40d
24− github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a
30+ github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
31+ github.com/charmbracelet/x/exp/ordered v0.1.0
32+ github.com/charmbracelet/x/exp/slice v0.0.0-20260622092256-25656177ba8e
33+ github.com/charmbracelet/x/exp/strings v0.1.0
34+ github.com/charmbracelet/x/powernap v0.1.6
35+ github.com/charmbracelet/x/term v0.2.2
36+ github.com/clipperhouse/displaywidth v0.11.0
37+ github.com/clipperhouse/uax29/v2 v2.7.0
38+ github.com/denisbrodbeck/machineid v1.0.1
25− github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec
39+ github.com/disintegration/imaging v1.6.2
26− github.com/fsnotify/fsnotify v1.9.0
40+ github.com/dustin/go-humanize v1.0.1
41+ github.com/gen2brain/beeep v0.11.2
42+ github.com/go-git/go-git/v5 v5.19.1
27 github.com/google/uuid v1.6.0
43 github.com/google/uuid v1.6.0
28− github.com/invopop/jsonschema v0.13.0
44+ github.com/invopop/jsonschema v0.14.0
45+ github.com/itchyny/gojq v0.12.19
29 github.com/joho/godotenv v1.5.1
46 github.com/joho/godotenv v1.5.1
30− github.com/mark3labs/mcp-go v0.34.0
47+ github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d
48+ github.com/lucasb-eyer/go-colorful v1.4.0
31− github.com/muesli/termenv v0.16.0
49+ github.com/mattn/go-isatty v0.0.22
50+ github.com/modelcontextprotocol/go-sdk v1.6.1
32− github.com/ncruces/go-sqlite3 v0.25.0
51+ github.com/ncruces/go-sqlite3 v0.35.1
33− github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
34 github.com/nxadm/tail v1.4.11
52 github.com/nxadm/tail v1.4.11
35− github.com/openai/openai-go v1.11.1
53+ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
54+ github.com/posthog/posthog-go v1.17.5
36− github.com/pressly/goose/v3 v3.24.2
55+ github.com/pressly/goose/v3 v3.27.2
37− github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c
56+ github.com/qjebbs/go-jsons v1.0.0-alpha.6
38− github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
57+ github.com/rivo/uniseg v0.4.7
39− github.com/sahilm/fuzzy v0.1.1
58+ github.com/sahilm/fuzzy v0.1.3
59+ github.com/sourcegraph/jsonrpc2 v0.2.1
40− github.com/spf13/cobra v1.9.1
60+ github.com/spf13/cobra v1.10.2
41− github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
42− github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
43− github.com/stretchr/testify v1.10.0
61+ github.com/stretchr/testify v1.11.1
62+ github.com/swaggo/http-swagger/v2 v2.0.2
63+ github.com/swaggo/swag v1.16.6
64+ github.com/tidwall/gjson v1.19.0
44 github.com/tidwall/sjson v1.2.5
65 github.com/tidwall/sjson v1.2.5
45− github.com/u-root/u-root v0.14.1-0.20250724181933-b01901710169
46− github.com/zeebo/xxh3 v1.0.2
66+ github.com/zeebo/xxh3 v1.1.0
67+ go.uber.org/goleak v1.3.0
68+ golang.design/x/clipboard v0.8.0
69+ golang.org/x/net v0.56.0
70+ golang.org/x/sync v0.21.0
71+ golang.org/x/sys v0.46.0
72+ golang.org/x/text v0.38.0
47 gopkg.in/natefinch/lumberjack.v2 v2.2.1
73 gopkg.in/natefinch/lumberjack.v2 v2.2.1
48− mvdan.cc/sh/v3 v3.12.1-0.20250726150758-e256f53bade8
74+ gopkg.in/yaml.v3 v3.0.1
75+ modernc.org/sqlite v1.53.0
76+ mvdan.cc/sh/moreinterp v0.0.0-20250902163504-3cf4fd5717a5
77+ mvdan.cc/sh/v3 v3.13.1
52− github.com/bahlo/generic-list-go v0.2.0 // indirect
81+ cloud.google.com/go v0.123.0 // indirect
53− github.com/buger/jsonparser v1.1.1 // indirect
82+ cloud.google.com/go/auth v0.20.0 // indirect
54− github.com/mailru/easyjson v0.7.7 // indirect
83+ cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
55− github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
56− golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
60− cloud.google.com/go v0.116.0 // indirect
61− cloud.google.com/go/auth v0.13.0 // indirect
62− cloud.google.com/go/compute/metadata v0.6.0 // indirect
84+ cloud.google.com/go/compute/metadata v0.9.0 // indirect
85+ git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
63 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
86 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
64 github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
87 github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
88+ github.com/KyleBanks/depth v1.2.1 // indirect
89+ github.com/andybalholm/brotli v1.2.1 // indirect
65− github.com/andybalholm/cascadia v1.3.2 // indirect
90+ github.com/andybalholm/cascadia v1.3.3 // indirect
91+ github.com/atotto/clipboard v0.1.4 // indirect
66− github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
92+ github.com/aws/aws-sdk-go-v2 v1.42.0 // indirect
67− github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
93+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13 // indirect
68− github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
94+ github.com/aws/aws-sdk-go-v2/config v1.32.25 // indirect
69− github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
95+ github.com/aws/aws-sdk-go-v2/credentials v1.19.24 // indirect
70− github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
96+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 // indirect
71− github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
97+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 // indirect
72− github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
98+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 // indirect
73− github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
99+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 // indirect
74− github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
100+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 // indirect
75− github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
101+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 // indirect
102+ github.com/aws/aws-sdk-go-v2/service/signin v1.2.0 // indirect
76− github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
103+ github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 // indirect
77− github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
104+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 // indirect
78− github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
105+ github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 // indirect
79− github.com/aws/smithy-go v1.20.3 // indirect
106+ github.com/aws/smithy-go v1.27.3 // indirect
80− github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
81 github.com/aymerick/douceur v0.2.0 // indirect
107 github.com/aymerick/douceur v0.2.0 // indirect
82− github.com/charmbracelet/colorprofile v0.3.1 // indirect
108+ github.com/bahlo/generic-list-go v0.2.0 // indirect
83− github.com/charmbracelet/ultraviolet v0.0.0-20250729133950-5d2ddf68d813 // indirect
109+ github.com/buger/jsonparser v1.1.2 // indirect
84− github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa // indirect
110+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
85− github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef
111+ github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab // indirect
86− github.com/charmbracelet/x/term v0.2.1
87 github.com/charmbracelet/x/termios v0.1.1 // indirect
112 github.com/charmbracelet/x/termios v0.1.1 // indirect
88− github.com/charmbracelet/x/windows v0.2.1 // indirect
113+ github.com/charmbracelet/x/windows v0.2.2 // indirect
114+ github.com/cyphar/filepath-securejoin v0.6.1 // indirect
89− github.com/davecgh/go-spew v1.1.1 // indirect
115+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
90− github.com/disintegration/gift v1.1.2 // indirect
91− github.com/dlclark/regexp2 v1.11.4 // indirect
116+ github.com/dlclark/regexp2/v2 v2.2.1 // indirect
92− github.com/dustin/go-humanize v1.0.1 // indirect
117+ github.com/ebitengine/purego v0.10.1 // indirect
118+ github.com/esiqveland/notify v0.13.3 // indirect
93− github.com/felixge/httpsnoop v1.0.4 // indirect
119+ github.com/felixge/httpsnoop v1.1.0 // indirect
120+ github.com/fsnotify/fsnotify v1.9.0 // indirect
121+ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
122+ github.com/go-git/go-billy/v5 v5.9.0 // indirect
123+ github.com/go-json-experiment/json v0.0.0-20260623181947-01eb4420fa68 // indirect
94 github.com/go-logfmt/logfmt v0.6.0 // indirect
124 github.com/go-logfmt/logfmt v0.6.0 // indirect
95− github.com/go-logr/logr v1.4.2 // indirect
125+ github.com/go-logr/logr v1.4.3 // indirect
96 github.com/go-logr/stdr v1.2.2 // indirect
126 github.com/go-logr/stdr v1.2.2 // indirect
127+ github.com/go-ole/go-ole v1.3.0 // indirect
128+ github.com/go-openapi/jsonpointer v0.19.5 // indirect
129+ github.com/go-openapi/jsonreference v0.20.0 // indirect
130+ github.com/go-openapi/spec v0.20.6 // indirect
131+ github.com/go-openapi/swag v0.19.15 // indirect
132+ github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
133+ github.com/goccy/go-json v0.10.5 // indirect
134+ github.com/goccy/go-yaml v1.19.2 // indirect
135+ github.com/godbus/dbus/v5 v5.2.2 // indirect
136+ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
97 github.com/google/go-cmp v0.7.0 // indirect
137 github.com/google/go-cmp v0.7.0 // indirect
138+ github.com/google/jsonschema-go v0.4.3 // indirect
98− github.com/google/s2a-go v0.1.8 // indirect
139+ github.com/google/s2a-go v0.1.9 // indirect
99− github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
140+ github.com/googleapis/enterprise-certificate-proxy v0.3.17 // indirect
100− github.com/googleapis/gax-go/v2 v2.14.1 // indirect
141+ github.com/googleapis/gax-go/v2 v2.22.0 // indirect
101 github.com/gorilla/css v1.0.1 // indirect
142 github.com/gorilla/css v1.0.1 // indirect
102 github.com/gorilla/websocket v1.5.3 // indirect
143 github.com/gorilla/websocket v1.5.3 // indirect
144+ github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
103 github.com/inconshreveable/mousetrap v1.1.0 // indirect
145 github.com/inconshreveable/mousetrap v1.1.0 // indirect
146+ github.com/itchyny/timefmt-go v0.1.8 // indirect
147+ github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
148+ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
149+ github.com/josharian/intern v1.0.0 // indirect
150+ github.com/kaptinlin/jsonpointer v0.4.26 // indirect
151+ github.com/kaptinlin/jsonschema v0.9.2 // indirect
152+ github.com/klauspost/compress v1.18.6 // indirect
104− github.com/klauspost/cpuid/v2 v2.0.9 // indirect
153+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
105− github.com/lucasb-eyer/go-colorful v1.2.0
154+ github.com/klauspost/pgzip v1.2.6 // indirect
106− github.com/mattn/go-isatty v0.0.20 // indirect
155+ github.com/mailru/easyjson v0.7.7 // indirect
107− github.com/mattn/go-runewidth v0.0.16 // indirect
156+ github.com/mattn/go-runewidth v0.0.24 // indirect
108 github.com/mfridman/interpolate v0.0.2 // indirect
157 github.com/mfridman/interpolate v0.0.2 // indirect
109 github.com/microcosm-cc/bluemonday v1.0.27 // indirect
158 github.com/microcosm-cc/bluemonday v1.0.27 // indirect
159+ github.com/mitchellh/mapstructure v1.5.0 // indirect
110 github.com/muesli/cancelreader v0.2.2 // indirect
160 github.com/muesli/cancelreader v0.2.2 // indirect
111 github.com/muesli/mango v0.1.0 // indirect
161 github.com/muesli/mango v0.1.0 // indirect
112 github.com/muesli/mango-cobra v1.2.0 // indirect
162 github.com/muesli/mango-cobra v1.2.0 // indirect
113 github.com/muesli/mango-pflag v0.1.0 // indirect
163 github.com/muesli/mango-pflag v0.1.0 // indirect
114 github.com/muesli/roff v0.1.0 // indirect
164 github.com/muesli/roff v0.1.0 // indirect
165+ github.com/ncruces/go-sqlite3-wasm/v3 v3.1.35302 // indirect
166+ github.com/ncruces/go-strftime v1.0.0 // indirect
115 github.com/ncruces/julianday v1.0.0 // indirect
167 github.com/ncruces/julianday v1.0.0 // indirect
168+ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
169+ github.com/pb33f/ordered-map/v2 v2.3.1 // indirect
170+ github.com/pierrec/lz4/v4 v4.1.26 // indirect
171+ github.com/pjbgf/sha1cd v0.6.0 // indirect
116− github.com/pmezard/go-difflib v1.0.0 // indirect
172+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
117− github.com/rivo/uniseg v0.4.7
173+ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
118− github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
174+ github.com/segmentio/asm v1.2.1 // indirect
175+ github.com/segmentio/encoding v0.5.4 // indirect
176+ github.com/sergeymakinen/go-bmp v1.0.0 // indirect
177+ github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
119 github.com/sethvargo/go-retry v0.3.0 // indirect
178 github.com/sethvargo/go-retry v0.3.0 // indirect
120− github.com/spf13/cast v1.7.1 // indirect
179+ github.com/spf13/pflag v1.0.9 // indirect
121− github.com/spf13/pflag v1.0.7 // indirect
180+ github.com/swaggo/files/v2 v2.0.0 // indirect
122− github.com/tetratelabs/wazero v1.9.0 // indirect
181+ github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
123− github.com/tidwall/gjson v1.18.0 // indirect
124 github.com/tidwall/match v1.1.1 // indirect
182 github.com/tidwall/match v1.1.1 // indirect
125 github.com/tidwall/pretty v1.2.1 // indirect
183 github.com/tidwall/pretty v1.2.1 // indirect
184+ github.com/u-root/u-root v0.14.1-0.20250807200646-5e7721023dc7 // indirect
185+ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
126 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
186 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
127 github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
187 github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
128 github.com/yuin/goldmark v1.7.8 // indirect
188 github.com/yuin/goldmark v1.7.8 // indirect
129 github.com/yuin/goldmark-emoji v1.0.5 // indirect
189 github.com/yuin/goldmark-emoji v1.0.5 // indirect
130− go.opentelemetry.io/auto/sdk v1.1.0 // indirect
190+ go.opentelemetry.io/auto/sdk v1.2.1 // indirect
191+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 // indirect
131− go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
192+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
132− go.opentelemetry.io/otel v1.35.0 // indirect
193+ go.opentelemetry.io/otel v1.44.0 // indirect
133− go.opentelemetry.io/otel/metric v1.35.0 // indirect
194+ go.opentelemetry.io/otel/metric v1.44.0 // indirect
134− go.opentelemetry.io/otel/trace v1.35.0 // indirect
195+ go.opentelemetry.io/otel/trace v1.44.0 // indirect
135 go.uber.org/multierr v1.11.0 // indirect
196 go.uber.org/multierr v1.11.0 // indirect
197+ go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
198+ golang.design/x/x11 v0.2.0 // indirect
136− golang.org/x/crypto v0.38.0 // indirect
199+ golang.org/x/crypto v0.53.0 // indirect
200+ golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
201+ golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 // indirect
137− golang.org/x/image v0.26.0 // indirect
202+ golang.org/x/image v0.43.0 // indirect
138− golang.org/x/net v0.40.0 // indirect
203+ golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f // indirect
139− golang.org/x/sync v0.16.0 // indirect
204+ golang.org/x/mod v0.36.0 // indirect
140− golang.org/x/sys v0.34.0
205+ golang.org/x/oauth2 v0.36.0 // indirect
141− golang.org/x/term v0.32.0 // indirect
206+ golang.org/x/term v0.44.0 // indirect
207+ golang.org/x/time v0.15.0 // indirect
142− golang.org/x/text v0.25.0
208+ golang.org/x/tools v0.45.0 // indirect
209+ google.golang.org/api v0.286.0 // indirect
143− google.golang.org/genai v1.3.0
210+ google.golang.org/genai v1.62.0 // indirect
144− google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
211+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260622175928-b703f567277d // indirect
145− google.golang.org/grpc v1.71.0 // indirect
212+ google.golang.org/grpc v1.81.1 // indirect
146− google.golang.org/protobuf v1.36.6 // indirect
213+ google.golang.org/protobuf v1.36.11 // indirect
214+ gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290 // indirect
147 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
215 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
148− gopkg.in/yaml.v3 v3.0.1 // indirect
216+ gopkg.in/warnings.v0 v0.1.2 // indirect
217+ gopkg.in/yaml.v2 v2.4.0 // indirect
218+ modernc.org/libc v1.73.4 // indirect
219+ modernc.org/mathutil v1.7.1 // indirect
220+ modernc.org/memory v1.11.0 // indirect
@@ -1,9 +1,31 @@
1−cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
1+charm.land/bubbles/v2 v2.1.1 h1:7r55WzBxpo/R3z98hGmY7KKPd3ET6vsf0Fb9sDHOV60=
2−cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
2+charm.land/bubbles/v2 v2.1.1/go.mod h1:GE6M31gaWZVXzGw73OeuTTgy4lX+OtkH0E5ymnNsHxo=
3−cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs=
3+charm.land/bubbletea/v2 v2.0.8 h1:SxTJMhCAI3lbPmy4SgX5LWZ24AdINr4I6UEqzZvYJuY=
4+charm.land/bubbletea/v2 v2.0.8/go.mod h1:2SkdgoTXluXJHOUwAoRlRXF/28vklb1rFl6GcgV1/ss=
5+charm.land/catwalk v0.49.0 h1:pXcHh9H76VvwGqPYMZhJe5vRqMLpzGsv0anJArKw70g=
6+charm.land/catwalk v0.49.0/go.mod h1:bw6/oiChsa9Fkr8LgYn84KrbbJY2z1+m7Jmlmmv3B2A=
7+charm.land/fang/v2 v2.0.1 h1:zQCM8JQJ1JnQX/66B5jlCYBUxL2as5JXQZ2KJ6EL0mY=
8+charm.land/fang/v2 v2.0.1/go.mod h1:S1GmkpcvK+OB5w9caywUnJcsMew45Ot8FXqoz8ALrII=
9+charm.land/fantasy v0.35.0 h1:iFES7cnt3/o20T01+y2PDkHj5dHEWRFQH0vSXYzV8xo=
10+charm.land/fantasy v0.35.0/go.mod h1:rUqUhunz+c6k66L0hHd51CrXB3SSzPNKkwBrzIe6XnY=
11+charm.land/glamour/v2 v2.0.1 h1:xl+r00A4aJWU0z8fgwKd9fQQ4rsphqGUzuEiXZP5n+c=
12+charm.land/glamour/v2 v2.0.1/go.mod h1:jo9z8XqVKPeEFMVdvCRLGk++RyJ3CdUwgNr7EvXLw3k=
13+charm.land/lipgloss/v2 v2.0.5 h1:kbNxgeeUOYv5J0YdpxFjfvf3dFvqH8Aci4zB6xqFtrY=
14+charm.land/lipgloss/v2 v2.0.5/go.mod h1:9oqhxt4yxIMe6q5A4kHr44DremZk7J9UNh74GlWa5nc=
15+charm.land/log/v2 v2.0.0 h1:SY3Cey7ipx86/MBXQHwsguOT6X1exT94mmJRdzTNs+s=
16+charm.land/log/v2 v2.0.0/go.mod h1:c3cZSRqm20qUVVAR1WmS/7ab8bgha3C6G7DjPcaVZz0=
17+charm.land/x/vcr v0.1.1 h1:PXCFMUG0rPtyk35rhfzYCJEduOzWXCIbrXTFq4OF/9Q=
18+charm.land/x/vcr v0.1.1/go.mod h1:eByq2gqzWvcct/8XE2XO5KznoWEBiXH56+y2gphbltM=
19+cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
20+cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
21+cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
4−cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
22+cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
23+cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
24+cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
5−cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
25+cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
6−cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
26+cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
27+git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm5euVuE=
28+git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo=
7github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
29github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
8github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
30github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
9github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
31github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
@@ -14,159 +36,242 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mx
14github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
36github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
15github.com/JohannesKaufmann/html-to-markdown v1.6.0 h1:04VXMiE50YYfCfLboJCLcgqF5x+rHJnb1ssNmqpLH/k=
37github.com/JohannesKaufmann/html-to-markdown v1.6.0 h1:04VXMiE50YYfCfLboJCLcgqF5x+rHJnb1ssNmqpLH/k=
16github.com/JohannesKaufmann/html-to-markdown v1.6.0/go.mod h1:NUI78lGg/a7vpEJTz/0uOcYMaibytE4BUOQS8k78yPQ=
38github.com/JohannesKaufmann/html-to-markdown v1.6.0/go.mod h1:NUI78lGg/a7vpEJTz/0uOcYMaibytE4BUOQS8k78yPQ=
39+github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
40+github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
17github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
41github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
18github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
42github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
19−github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
43+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
44+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
20github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
45github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
46+github.com/PuerkitoBio/goquery v1.12.0 h1:pAcL4g3WRXekcB9AU/y1mbKez2dbY2AajVhtkO8RIBo=
47+github.com/PuerkitoBio/goquery v1.12.0/go.mod h1:802ej+gV2y7bbIhOIoPY5sT183ZW0YFofScC4q/hIpQ=
21github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
48github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
22github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
49github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
23−github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
50+github.com/alecthomas/chroma/v2 v2.27.0 h1:FodwmyOBgJULFYmDqibcp9pvfDLWdtPRh9v/r5BXYZs=
24−github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
51+github.com/alecthomas/chroma/v2 v2.27.0/go.mod h1:NjJ3ciIgrqBNeIkWZ4e46nseoLDslxU1LmfCoL+wcY8=
25−github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
52+github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
26−github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
53+github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
27−github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
54+github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
55+github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
28github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
56github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
29−github.com/anthropics/anthropic-sdk-go v1.6.2 h1:oORA212y0/zAxe7OPvdgIbflnn/x5PGk5uwjF60GqXM=
57+github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
30−github.com/anthropics/anthropic-sdk-go v1.6.2/go.mod h1:3qSNQ5NrAmjC8A2ykuruSQttfqfdEYNZY5o8c0XSHB8=
58+github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
31github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
59github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
32github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
60github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
33−github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
61+github.com/aws/aws-sdk-go-v2 v1.42.0 h1:XvXMJTkFQtpBKIWZnmr9ZEOc2InWM2yldjXEJ/bymhA=
34−github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
62+github.com/aws/aws-sdk-go-v2 v1.42.0/go.mod h1:27+ACypSLljLAEKsCYOmrjKh83vuTRkuAe9Uv/3A4bg=
35−github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
63+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13 h1:p1BBrg/Hhp6uK7zpejeI8QFXHJeC/mynzi04Sl03k9g=
36−github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
64+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.13/go.mod h1:8cIfkE9MDhkRZGpQ22aV6/lkYeYSozpz16Smrs5x4Ls=
37−github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
65+github.com/aws/aws-sdk-go-v2/config v1.32.25 h1:ACCejvStYoilgwrfegSt5ZntCbPrk52qfwyNcnl3omM=
38−github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
66+github.com/aws/aws-sdk-go-v2/config v1.32.25/go.mod h1:LJyU8sDRbXUxFn8xMJIGP+v9QYYwveNLI8a/giAOiAs=
39−github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
67+github.com/aws/aws-sdk-go-v2/credentials v1.19.24 h1:2hQqYCV9yqyePQ9o6dCrZc/zO8U3TwPr9mIKlZnPu/I=
40−github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
68+github.com/aws/aws-sdk-go-v2/credentials v1.19.24/go.mod h1:IDwpACtwqHLISdzfwUUNq4P9DsB/h5BLg4FwJPNfqFY=
41−github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
69+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 h1:r6qZHbT+wxgWO/e9vYNUEtg7lv5+UN3pRqKhLXvnArg=
42−github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
70+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29/go.mod h1:QRnaRcTVGKPGRy8w78HMQtKUGRYcnMZAANATkeVA6Mo=
43−github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
71+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 h1:f3vKqSo13fhTYb+JEcXwXefZQE26I1FB5eTSniU67ko=
44−github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
72+github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29/go.mod h1:MzoLFUArKGpGD+ukmPiTPG1X5x4o6M2kq4v2dr1FiEc=
45−github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
73+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 h1:RdwIf/CuUsvJX3RgJagbOyotl/cxoLY4xviKuE7p2GY=
46−github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
74+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29/go.mod h1:71wt8W2EgswdZy9Mf9KNnzxZ3TiZlv4caKghPktDOkA=
47−github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
75+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 h1:VTGy885W5DKBxWRUJbym9hytNaYzsyaPkCHGRRMAOhU=
48−github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
76+github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30/go.mod h1:AS0HycUvJRFvTt613AYDOgO2jzw+00cVSMny8XB3yMY=
49−github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
77+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 h1:ZD2+BSw9vFsNlKYIasSNt3uDbjqqXIBcM13UJv/Lx2k=
50−github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
78+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12/go.mod h1:Ms4zlcVBbXbiP7EVLhl+lgjvA/a7YphqQ3Ih3174EmI=
51−github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
79+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 h1:DRebniUGZ2MqiiIVmQJ04vIXr918hubdHMnarSLEWyU=
52−github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
80+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29/go.mod h1:LfRkPCD8YHDM2E5eTkos2UpwYeZnBcVarTa8L59bJHA=
53−github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
81+github.com/aws/aws-sdk-go-v2/service/signin v1.2.0 h1:3nXpRcFwRCW8n7HgO2QGy0Dc20eQNfBuUemGQhpF8m8=
54−github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
82+github.com/aws/aws-sdk-go-v2/service/signin v1.2.0/go.mod h1:LxYujSTLPRlp2vTtcUO/+1ilrew8ytt6SvQyOgejzFQ=
55−github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
83+github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 h1:ey1XLTYXb9PcLt4535632o5kCGXNXEhNb620Dqwuylo=
56−github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
84+github.com/aws/aws-sdk-go-v2/service/sso v1.31.3/go.mod h1:Lk7PlmoTYryQmyBG0EXqj5BcUbj3whXdU2s3yGI3EAc=
57−github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
85+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 h1:yLr03zQE/5Eu5l3QU0Si+xMbLMbSDF2YXsigqXngs6g=
58−github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
86+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6/go.mod h1:Q5N6icH+KJZDLh+ESNwzdv6cZ6vLFF/egy3IOxWhmz4=
59−github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
87+github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 h1:VrIhKRCSK1umelSgB9RghvA9RTUYeQffyAS5ApXehNI=
60−github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
88+github.com/aws/aws-sdk-go-v2/service/sts v1.43.3/go.mod h1:r8wkDOuLaaMFqFiYAb8dGY2A3gJCOujMc6CFOVC4Zhc=
61−github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
89+github.com/aws/smithy-go v1.27.3 h1:F3Zb497UhhskkfpJmfkXswyo+t0sh9OTBnIHjogWbVY=
62−github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
90+github.com/aws/smithy-go v1.27.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
63−github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
91+github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o=
64−github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
92+github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=
65github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
93github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
66github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
94github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
67github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
95github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
68github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
96github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
69−github.com/bmatcuk/doublestar/v4 v4.9.0 h1:DBvuZxjdKkRP/dr4GVV4w2fnmrk5Hxc90T51LZjv0JA=
97+github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
70−github.com/bmatcuk/doublestar/v4 v4.9.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
98+github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
71−github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
99+github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
72−github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
100+github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
73−github.com/charlievieth/fastwalk v1.0.11 h1:5sLT/q9+d9xMdpKExawLppqvXFZCVKf6JHnr2u/ufj8=
101+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
74−github.com/charlievieth/fastwalk v1.0.11/go.mod h1:yGy1zbxog41ZVMcKA/i8ojXLFsuayX5VvwhQVoj9PBI=
102+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
75−github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250716191546-1e2ffbbcf5c5 h1:GTcMIfDQJKyNKS+xVt7GkNIwz+tBuQtIuiP50WpzNgs=
103+github.com/charlievieth/fastwalk v1.0.14 h1:3Eh5uaFGwHZd8EGwTjJnSpBkfwfsak9h6ICgnWlhAyg=
76−github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1.0.20250716191546-1e2ffbbcf5c5/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw=
104+github.com/charlievieth/fastwalk v1.0.14/go.mod h1:diVcUreiU1aQ4/Wu3NbxxH4/KYdKpLDojrQ1Bb2KgNY=
77−github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.4.0.20250724172607-5ba56e2bec69 h1:nXLMl4ows2qogDXhuEtDNgFNXQiU+PJer+UEBsQZuns=
105+github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab h1:J7XQLgl9sefgTnTGrmX3xqvp5o6MCiBzEjGv5igAlc4=
78−github.com/charmbracelet/bubbletea/v2 v2.0.0-beta.4.0.20250724172607-5ba56e2bec69/go.mod h1:XIQ1qQfRph6Z5o2EikCydjumo0oDInQySRHuPATzbZc=
106+github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab/go.mod h1:hqlYqR7uPKOKfnNeicUbZp0Ps0GeYFlKYtwh5HGDCx8=
79−github.com/charmbracelet/catwalk v0.3.5 h1:ChMvA5ooTNZhDKFagmGNQgIZvZp8XjpdaJ+cDmhgCgA=
107+github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
80−github.com/charmbracelet/catwalk v0.3.5/go.mod h1:gUUCqqZ8bk4D7ZzGTu3I77k7cC2x4exRuJBN1H2u2pc=
81−github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40=
108+github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
82−github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0=
109+github.com/charmbracelet/openai-go v0.0.0-20260617131321-5e4b9c18c4be h1:pg+OWlIkk9HOe/8P5J95aKe2wGDzFUiiyFOUpwR30B4=
83−github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674 h1:+Cz+VfxD5DO+JT1LlswXWhre0HYLj6l2HW8HVGfMuC0=
110+github.com/charmbracelet/openai-go v0.0.0-20260617131321-5e4b9c18c4be/go.mod h1:1DahUaExbUZx/jD+FNT2PKP4L9rLE5+ZBRuI8mZjd/E=
84−github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674/go.mod h1:9gCUAHmVx5BwSafeyNr3GI0GgvlB1WYjL21SkPp1jyU=
111+github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7 h1:3FmWoGNWK4STvqg0O0Aeav2T7rodWJAPeF0QpH+8gFw=
85−github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe h1:i6ce4CcAlPpTj2ER69m1DBeLZ3RRcHnKExuwhKa3GfY=
112+github.com/charmbracelet/ultraviolet v0.0.0-20260703014108-f5a850f9c2b7/go.mod h1:f/jRa757WUmaOZrbPspXymbg/GnbF+rwe4OLsG7aXYo=
86−github.com/charmbracelet/glamour/v2 v2.0.0-20250516160903-6f1e2c8f9ebe/go.mod h1:p3Q+aN4eQKeM5jhrmXPMgPrlKbmc59rWSnMsSA3udhk=
113+github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI=
87−github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3.0.20250721205738-ea66aa652ee0 h1:sWRGoSw/JsO2S4t2+fmmEkRbkOxphI0AxZkQPQVKWbs=
114+github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ=
88−github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3.0.20250721205738-ea66aa652ee0/go.mod h1:XIuqKpZTUXtVyeyiN1k9Tc/U7EzfaDnVc34feFHfBws=
115+github.com/charmbracelet/x/editor v0.2.0 h1:7XLUKtaRaB8jN7bWU2p2UChiySyaAuIfYiIRg8gGWwk=
89−github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706 h1:WkwO6Ks3mSIGnGuSdKl9qDSyfbYK50z2wc2gGMggegE=
116+github.com/charmbracelet/x/editor v0.2.0/go.mod h1:p3oQ28TSL3YPd+GKJ1fHWcp+7bVGpedHpXmo0D6t1dY=
90−github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706/go.mod h1:mjJGp00cxcfvD5xdCa+bso251Jt4owrQvuimJtVmEmM=
117+github.com/charmbracelet/x/etag v0.2.0 h1:Euj1VkheoHfTYA9y+TCwkeXF/hN8Fb9l4LqZl79pt04=
91−github.com/charmbracelet/ultraviolet v0.0.0-20250728213340-d73950b67624 h1:D6cSAhkOFnx8TG8pyUiVWTbQ058xM4FXcOdaZXtBz+A=
118+github.com/charmbracelet/x/etag v0.2.0/go.mod h1:C1B7/bsgvzzxpfu0Rabbd+rTHJa5TmC/qgTseCf6DF0=
92−github.com/charmbracelet/ultraviolet v0.0.0-20250728213340-d73950b67624/go.mod h1:XrrgNFfXLrFAyd9DUmrqVc3yQFVv8Uk+okj4PsNNzpc=
119+github.com/charmbracelet/x/exp/charmtone v0.0.0-20260527151214-009e6338d40d h1:sMilwx1YIYTrQva6jsB522AoRYAerNaDIKP4ZPtUq0A=
93−github.com/charmbracelet/ultraviolet v0.0.0-20250729133950-5d2ddf68d813 h1:A3omGay8ZBDBmmGZ4Hcffpo7Ywz92rb2GUbFb9YABkM=
120+github.com/charmbracelet/x/exp/charmtone v0.0.0-20260527151214-009e6338d40d/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY=
94−github.com/charmbracelet/ultraviolet v0.0.0-20250729133950-5d2ddf68d813/go.mod h1:XrrgNFfXLrFAyd9DUmrqVc3yQFVv8Uk+okj4PsNNzpc=
121+github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
95−github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
122+github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
96−github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
123+github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
97−github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa h1:lphz0Z3rsiOtMYiz8axkT24i9yFiueDhJbzyNUADmME=
124+github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
98−github.com/charmbracelet/x/cellbuf v0.0.14-0.20250516160309-24eee56f89fa/go.mod h1:xBlh2Yi3DL3zy/2n15kITpg0YZardf/aa/hgUaIM6Rk=
125+github.com/charmbracelet/x/exp/slice v0.0.0-20260622092256-25656177ba8e h1:TerxTCW/3BrnpqKxeouW0cWSjZb7PsVAmtNftRAAFRE=
99−github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3 h1:1xwHZg6eMZ9Wv5TE1UGub6ARubyOd1Lo5kPUI/6VL50=
126+github.com/charmbracelet/x/exp/slice v0.0.0-20260622092256-25656177ba8e/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
100−github.com/charmbracelet/x/exp/charmtone v0.0.0-20250708181618-a60a724ba6c3/go.mod h1:T9jr8CzFpjhFVHjNjKwbAD7KwBNyFnj2pntAO7F2zw0=
127+github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
101−github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a h1:FsHEJ52OC4VuTzU8t+n5frMjLvpYWEznSr/u8tnkCYw=
128+github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
102−github.com/charmbracelet/x/exp/golden v0.0.0-20250207160936-21c02780d27a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
129+github.com/charmbracelet/x/powernap v0.1.6 h1:tsnQWQVl9arYm5S/tQVXuMJcvnkUNNkXhBWlEBDRNqM=
103−github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef h1:v7qwsZ2OxzlwvpKwz8dtZXp7fIJlcDEUOyFBNE4fz4Q=
130+github.com/charmbracelet/x/powernap v0.1.6/go.mod h1:cmdl5zlP5mR8TF2Y68UKc7hdGUDiSJ2+4hk0h04Hsx4=
104−github.com/charmbracelet/x/exp/slice v0.0.0-20250611152503-f53cdd7e01ef/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
105−github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
131+github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
106−github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
132+github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
107github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
133github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
108github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
134github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
109−github.com/charmbracelet/x/windows v0.2.1 h1:3x7vnbpQrjpuq/4L+I4gNsG5htYoCiA5oe9hLjAij5I=
135+github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=
110−github.com/charmbracelet/x/windows v0.2.1/go.mod h1:ptZp16h40gDYqs5TSawSVW+yiLB13j4kSMA0lSCHL0M=
136+github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
137+github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
138+github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
139+github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
140+github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
141+github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
142+github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
111github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
143github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
144+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
112github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
145github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
113github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
146github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
147+github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
148+github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
114github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
149github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
115−github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
116github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
150github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
117−github.com/disintegration/gift v1.1.2 h1:9ZyHJr+kPamiH10FX3Pynt1AxFUob812bU9Wt4GMzhs=
151+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
118−github.com/disintegration/gift v1.1.2/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
152+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
119−github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec h1:YrB6aVr9touOt75I9O1SiancmR2GMg45U9UYf0gtgWg=
153+github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
120−github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec/go.mod h1:K0KBFIr1gWu/C1Gp10nFAcAE4hsB7JxE6OgLijrJ8Sk=
154+github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
121−github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
155+github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
122−github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
156+github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
157+github.com/dlclark/regexp2/v2 v2.2.1 h1:mf4KkFUj0gJuarK8P+LgiS+Lit7m9N1yAwEfPbee7R0=
158+github.com/dlclark/regexp2/v2 v2.2.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU=
159+github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
160+github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
123github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
161github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
124github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
162github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
125−github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
163+github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY=
126−github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
164+github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
127−github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
165+github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
128−github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
166+github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ=
167+github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=
168+github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
169+github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
170+github.com/esiqveland/notify v0.13.3 h1:QCMw6o1n+6rl+oLUfg8P1IIDSFsDEb2WlXvVvIJbI/o=
171+github.com/esiqveland/notify v0.13.3/go.mod h1:hesw/IRYTO0x99u1JPweAl4+5mwXJibQVUcP0Iu5ORE=
172+github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
173+github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
129github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
174github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
130github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
175github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
131github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
176github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
177+github.com/gen2brain/beeep v0.11.2 h1:+KfiKQBbQCuhfJFPANZuJ+oxsSKAYNe88hIpJuyKWDA=
178+github.com/gen2brain/beeep v0.11.2/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
179+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
180+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
181+github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA=
182+github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
183+github.com/go-git/go-git/v5 v5.19.1 h1:nX27AnaU43/K5bKktKwgBmR9lawoYVe1Ckg0rgzzN00=
184+github.com/go-git/go-git/v5 v5.19.1/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ=
185+github.com/go-json-experiment/json v0.0.0-20260623181947-01eb4420fa68 h1:KZaTBSyshWX3MP5jukJcNSuXDQTO+rNpt0J564dX/eg=
186+github.com/go-json-experiment/json v0.0.0-20260623181947-01eb4420fa68/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
132github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
187github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
133github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
188github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
134github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
189github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
135−github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
190+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
136−github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
191+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
137github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
192github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
138github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
193github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
194+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
195+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
196+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
197+github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
198+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
199+github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
200+github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
201+github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
202+github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
203+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
204+github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
205+github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
139github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
206github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
140github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
207github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
141−github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
208+github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
142−github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
209+github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
210+github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
211+github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
212+github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
213+github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
214+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
215+github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
216+github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
217+github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
218+github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
219+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
220+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
143github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
221github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
144github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
222github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
223+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
145github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
224github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
146github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
225github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
147−github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
226+github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
227+github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
228+github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
229+github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
230+github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
148−github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
231+github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
149github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
232github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
150github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
233github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
151−github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
234+github.com/googleapis/enterprise-certificate-proxy v0.3.17 h1:73NfMHdiqo9JFU9+7a5ExpVa10/R29pXfZIaW559nrg=
152−github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
235+github.com/googleapis/enterprise-certificate-proxy v0.3.17/go.mod h1:rSEsBUemEBZEexP2y6jPp16LUmUbjmSbcPMQizR0o4k=
153−github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
236+github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4=
154−github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
237+github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
155github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
238github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
156github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
239github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
240+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
157github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
241github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
158github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
242github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
243+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
244+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
159github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
245github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
160github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
246github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
161github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
247github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
162github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
248github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
163−github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
249+github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg=
164−github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
250+github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I=
251+github.com/itchyny/gojq v0.12.19 h1:ttXA0XCLEMoaLOz5lSeFOZ6u6Q3QxmG46vfgI4O0DEs=
252+github.com/itchyny/gojq v0.12.19/go.mod h1:5galtVPDywX8SPSOrqjGxkBeDhSxEW1gSxoy7tn1iZY=
253+github.com/itchyny/timefmt-go v0.1.8 h1:1YEo1JvfXeAHKdjelbYr/uCuhkybaHCeTkH8Bo791OI=
254+github.com/itchyny/timefmt-go v0.1.8/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
255+github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
256+github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
257+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
258+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
165github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
259github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
166github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
260github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
261+github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d h1:on25kP+Sx7sxUMRQiA8gdcToAGet4DK/EIA30mXre+4=
262+github.com/jordanella/go-ansi-paintbrush v0.0.0-20240728195301-b7ad996ecf3d/go.mod h1:SV0W0APWP9MZ1/gfDQ/NzzTlWdIgYZ/ZbpN4d/UXRYw=
263+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
167github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
264github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
168−github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
265+github.com/kaptinlin/jsonpointer v0.4.26 h1:tw616yszHek+B3/GtDSia+uzBa3sLXGpmo4tYeMhBZw=
266+github.com/kaptinlin/jsonpointer v0.4.26/go.mod h1:wVOBaXGGnP42YsMb6zev/3W5POTvspdNfh8DXzf8XS8=
267+github.com/kaptinlin/jsonschema v0.9.2 h1:zqowDnBkpg80OeIt4Bl1bOyfKY1/KVVzst1m3MCsxd4=
268+github.com/kaptinlin/jsonschema v0.9.2/go.mod h1:mCH2W5lXd29tdDjvoFfY32nedPORnlk7pCVrrcs/NkQ=
269+github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
270+github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
271+github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
169−github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
272+github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
273+github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
274+github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
170github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
275github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
171github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
276github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
172github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
277github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -176,20 +281,25 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
176github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
281github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
177github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
282github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
178github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
283github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
179−github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
284+github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
180−github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
285+github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
286+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
287+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
288+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
181github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
289github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
182github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
290github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
183−github.com/mark3labs/mcp-go v0.34.0 h1:eWy7WBGvhk6EyAAyVzivTCprE52iXJwNtvHV6Cv3bR0=
291+github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
184−github.com/mark3labs/mcp-go v0.34.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
185−github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
186−github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
292+github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
187−github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
293+github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
188−github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
294+github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
189github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
295github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
190github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
296github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
191github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
297github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
192github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
298github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
299+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
300+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
301+github.com/modelcontextprotocol/go-sdk v1.6.1 h1:0zOSupjKUxPKSocPT1Wtago+mUHU2/uZ4xSOY0FGReU=
302+github.com/modelcontextprotocol/go-sdk v1.6.1/go.mod h1:kzm3kzFL1/+AziGOE0nUs3gvPoNxMCvkxokMkuFapXQ=
193github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
303github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
194github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
304github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
195github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI=
305github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI=
@@ -200,71 +310,96 @@ github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe
200github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0=
310github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0=
201github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
311github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
202github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
312github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
203−github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
313+github.com/ncruces/go-sqlite3 v0.35.1 h1:h/LaVyQwIvBBT0+2JmVe2tbYyWjUQ093/pYhpBqdxJo=
204−github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
314+github.com/ncruces/go-sqlite3 v0.35.1/go.mod h1:fXOSIkWwN5NXgbJk+7Zls8QIW4xOflmgh11OFvcY+J0=
205−github.com/ncruces/go-sqlite3 v0.25.0 h1:trugKUs98Zwy9KwRr/EUxZHL92LYt7UqcKqAfpGpK+I=
315+github.com/ncruces/go-sqlite3-wasm/v3 v3.1.35302 h1:Cew7/eNAMd1zhpXYBjofBua/63pFvbvB2h4PM/p6gKU=
206−github.com/ncruces/go-sqlite3 v0.25.0/go.mod h1:n6Z7036yFilJx04yV0mi5JWaF66rUmXn1It9Ux8dx68=
316+github.com/ncruces/go-sqlite3-wasm/v3 v3.1.35302/go.mod h1:xe0CfafDUxfh+fSVKjHHMiAxoG9KALt5nFtbGNb/jRs=
207−github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
317+github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
208−github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
318+github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
209github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
319github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
210github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
320github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
211github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
321github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
212github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
322github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
323+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
213github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
324github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
214github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
325github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
215−github.com/openai/openai-go v1.11.1 h1:fTQ4Sr9eoRiWFAoHzXiZZpVi6KtLeoTMyGrcOCudjNU=
326+github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
216−github.com/openai/openai-go v1.11.1/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
327+github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
328+github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY=
329+github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ=
330+github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY=
331+github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
332+github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU=
333+github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
217github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
334github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
218github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
335github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
219github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
336github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
220−github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
337+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
338+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
339+github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
340+github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
221github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
341github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
222−github.com/pressly/goose/v3 v3.24.2 h1:c/ie0Gm8rnIVKvnDQ/scHErv46jrDv9b4I0WRcFJzYU=
342+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
343+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
344+github.com/posthog/posthog-go v1.17.5 h1:mrLiAdyiQpl8Yeyg23iShyAztJMaUrYzsBjKeH52Aak=
345+github.com/posthog/posthog-go v1.17.5/go.mod h1://M430hNH3e8CDv4i8SJesb26816Mpa6GIZaiP4pNQU=
346+github.com/pressly/goose/v3 v3.27.2 h1:FjKNzcmMdGrQlSIu5alMSmakQtJFBgtw+A0bb1p/LC8=
223−github.com/pressly/goose/v3 v3.24.2/go.mod h1:kjefwFB0eR4w30Td2Gj2Mznyw94vSP+2jJYkOVNbD1k=
347+github.com/pressly/goose/v3 v3.27.2/go.mod h1:qWW+/8dkVtJYjJrbIpwD5xxnEJTUKvxkQ9JKQp9LaIM=
224−github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c h1:kmzxiX+OB0knCo1V0dkEkdPelzCdAzCURCfmFArn2/A=
348+github.com/qjebbs/go-jsons v1.0.0-alpha.6 h1:9pMjdrCT7rj9CDIM0FXf9Ilie8PEy9g1b4qMkCnedjQ=
225−github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c/go.mod h1:wNJrtinHyC3YSf6giEh4FJN8+yZV7nXBjvmfjhBIcw4=
349+github.com/qjebbs/go-jsons v1.0.0-alpha.6/go.mod h1:wNJrtinHyC3YSf6giEh4FJN8+yZV7nXBjvmfjhBIcw4=
226github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
350github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
227github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
351github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
228−github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
229github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
352github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
230github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
353github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
231github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
354github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
232github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
355github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
233github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
356github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
234−github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
357+github.com/sahilm/fuzzy v0.1.3 h1:juByESSS32nVD81vr6tHmKmA/8zde7gE+x5CLxrzXPU=
235−github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
236−github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
237−github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
358+github.com/sahilm/fuzzy v0.1.3/go.mod h1:au6//VbVSqu6DFrkL2CfjlJ5iURpNCPeE+1GwY3XsT8=
238github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
359github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
239github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
360github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
361+github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
362+github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
363+github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
364+github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
365+github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
366+github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
367+github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3K6MFJw4GfZvQ=
368+github.com/sergeymakinen/go-ico v1.0.0-beta.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=
240github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
369github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
241github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
370github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
242github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
371github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
243github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
372github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
244github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
373github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
245github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
374github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
246−github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
375+github.com/sourcegraph/jsonrpc2 v0.2.1 h1:2GtljixMQYUYCmIg7W9aF2dFmniq/mOr2T9tFRh6zSQ=
247−github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
376+github.com/sourcegraph/jsonrpc2 v0.2.1/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo=
248−github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
377+github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
249−github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
378+github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
250−github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
379+github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
251−github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
252−github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
380+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
253−github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
254−github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
255−github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
256−github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
257github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
381github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
382+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
383+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
258github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
384github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
259github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
385github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
260github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
386github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
261−github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
387+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
262−github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
388+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
263−github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
389+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
264−github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
390+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
391+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
392+github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
393+github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
394+github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg=
395+github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ=
396+github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
397+github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
398+github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
399+github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
265github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
400github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
266−github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
401+github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU=
267−github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
402+github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc=
268github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
403github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
269github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
404github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
270github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
405github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@@ -272,12 +407,14 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
272github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
407github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
273github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
408github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
274github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
409github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
275−github.com/u-root/u-root v0.14.1-0.20250724181933-b01901710169 h1:f4cp2yGKkMuGpCwAyNEjzcw8szgVXmemK/wfOu4l5gc=
410+github.com/u-root/u-root v0.14.1-0.20250807200646-5e7721023dc7 h1:ax+jBy7xFhh+Ka0IGLmH5mft+YDuqvzEjSgWuAP0nsM=
276−github.com/u-root/u-root v0.14.1-0.20250724181933-b01901710169/go.mod h1:/0Qr7qJeDwWxoKku2xKQ4Szc+SwBE3g9VE8jNiamsmc=
411+github.com/u-root/u-root v0.14.1-0.20250807200646-5e7721023dc7/go.mod h1:/0Qr7qJeDwWxoKku2xKQ4Szc+SwBE3g9VE8jNiamsmc=
277−github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
412+github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
278−github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
413+github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
279github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
414github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
280github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
415github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
416+github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
417+github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
281github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
418github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
282github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
419github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
283github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
420github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -288,121 +425,202 @@ github.com/yuin/goldmark-emoji v1.0.5 h1:EMVWyCGPlXJfUXBXpuMu+ii3TIaxbVBnEX9uaDC
288github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
425github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
289github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
426github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
290github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
427github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
291−github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
428+github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
292−github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
429+github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
293−go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
430+go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
294−go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
431+go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
432+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0=
433+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
295−go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
434+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
296−go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
435+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
297−go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
436+go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
298−go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
437+go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
299−go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
438+go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
300−go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
439+go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
301−go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
440+go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
302−go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
441+go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
303−go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
442+go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
304−go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
443+go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
305−go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
444+go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
306−go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
445+go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
446+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
447+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
307go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
448go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
308go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
449go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
450+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
451+go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
452+go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
453+golang.design/x/clipboard v0.8.0 h1:6VEcH28wwcSgKc+vnxHHDWiRjrakTQIAJnPUrt3aOgg=
454+golang.design/x/clipboard v0.8.0/go.mod h1:s0pwrtA3Q9fgnVtGDmP5ZK/pp55cQKB23esKsjwWhWM=
455+golang.design/x/x11 v0.2.0 h1:Uiwu2guGihsJX/ZCzpoDPFz5gR/Qntm08mvoBCmRydo=
456+golang.design/x/x11 v0.2.0/go.mod h1:/5q1mFkdc1rL8mvB7DsQFi6as4tIkBv4FXjcP07mrkE=
309golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
457golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
310golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
458golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
459+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
311golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
460golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
312golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
461golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
313golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
462golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
314−golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
463+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
315−golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
464+golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
316−golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
465+golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
317−golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
466+golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
318−golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
467+golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
319−golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
468+golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 h1:Wdx0vgH5Wgsw+lF//LJKmWOJBLWX6nprsMqnf99rYDE=
469+golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
470+golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
471+golang.org/x/image v0.43.0 h1:FLxcP4ec2350nTfOC8ysKtqYSIFbk/QGjw1ZHNP4tsY=
472+golang.org/x/image v0.43.0/go.mod h1:rrpelvGFt+kLPAjPM4HeWPgrl0FtafueU//e5N0qk/Q=
473+golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f h1:/n+PL2HlfqeSiDCuhdBbRNlGS/g2fM4OHufalHaTVG8=
474+golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f/go.mod h1:ESkJ836Z6LpG6mTVAhA48LpfW/8fNR0ifStlH2axyfg=
320golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
475golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
321golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
476golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
477+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
478+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
479+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
480+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
481+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
322golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
482golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
323golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
483golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
324golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
484golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
325golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
485golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
326golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
486golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
327golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
487golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
488+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
328golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
489golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
329golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
490golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
330golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
491golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
331−golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
492+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
332−golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
493+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
494+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
495+golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
496+golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
333golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
497golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
334golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
498golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
335golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
499golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
336−golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
500+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
337−golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
501+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
502+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
503+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
504+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
505+golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
338golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
506golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
339golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
507golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
340golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
508golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
341golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
509golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
342golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
510golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
343golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
511golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
512+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
344golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
513golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
345−golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
346golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
514golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
347golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
515golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
516+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
348golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
517golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
349golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
518golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
350golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
519golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
351−golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
520+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
352−golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
521+golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
522+golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
523+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
353golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
524golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
354golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
525golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
355golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
526golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
356golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
527golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
357golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
528golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
529+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
358golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
530golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
359golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
531golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
360golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
532golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
361−golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
533+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
362−golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
534+golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
535+golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
363golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
536golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
364golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
537golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
365golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
538golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
366golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
539golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
367golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
540golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
541+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
368golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
542golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
369golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
543golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
370−golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
544+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
371−golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
545+golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
546+golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
547+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
548+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
372golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
549golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
373golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
550golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
374golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
551golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
375golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
552golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
553+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
554+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
555+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
556+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
376golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
557golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
377−google.golang.org/genai v1.3.0 h1:tXhPJF30skOjnnDY7ZnjK3q7IKy4PuAlEA0fk7uEaEI=
558+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
378−google.golang.org/genai v1.3.0/go.mod h1:TyfOKRz/QyCaj6f/ZDt505x+YreXnY40l2I6k8TvgqY=
559+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
379−google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g=
560+google.golang.org/api v0.286.0 h1:TdTXMvzYKnWV1/lPbCdbXRqBrkDqjPto22H2xeZZ8LI=
561+google.golang.org/api v0.286.0/go.mod h1:NlOlUIr8MPoIhT9Bb/oUnRuHbJOLwxb6JSYJM8Yz+jQ=
562+google.golang.org/genai v1.62.0 h1:PaBju84orf4Vbcc6OfHe4vxhxhjwulKTgOpEc3iIc00=
563+google.golang.org/genai v1.62.0/go.mod h1:mDdPDFXo1Ats7f1WXVyZgWb/CkMzFWTWJruIMy7hGIU=
564+google.golang.org/genproto v0.0.0-20260622175928-b703f567277d h1:CP5omUq8AJTiWMrPKM1WRLJ7zZeXd9OPcQD3TbBNAyY=
565+google.golang.org/genproto v0.0.0-20260622175928-b703f567277d/go.mod h1:DrwuGJgFSEVNpv3S5Q5VxhRTvdnjauw9GtvwVOEARfA=
566+google.golang.org/genproto/googleapis/api v0.0.0-20260622175928-b703f567277d h1:xr2lwHI91bn3UiXcnyzRMQjp2LRiM8wEHzwUaE0YhTs=
567+google.golang.org/genproto/googleapis/api v0.0.0-20260622175928-b703f567277d/go.mod h1:O0ZOWSrfWfJ+Z5HbwZ+wNtHsg/vk1k2C/w67eww8PfQ=
568+google.golang.org/genproto/googleapis/rpc v0.0.0-20260622175928-b703f567277d h1:mpAgMyM9vQHxycBlDq50y1VHpfSfVwzXvrQKtYbXuUY=
380−google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
569+google.golang.org/genproto/googleapis/rpc v0.0.0-20260622175928-b703f567277d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
381−google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
570+google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
382−google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
571+google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
383−google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
572+google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
384−google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
573+google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
385gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
574gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
575+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
386gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
576gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
577+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
387gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
578gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
388gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
579gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
580+gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290 h1:g3ah7zaWmw41EtOgBNXpx8zk4HYuH3OMwB+qh1Dt834=
581+gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290/go.mod h1:sbq5oMEcM4PXngbcNbHhzfCP9OdZodLhrbRYoyg09HY=
389gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
582gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
390gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
583gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
391gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
584gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
392gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
585gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
586+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
587+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
393gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
588gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
394gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
589gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
395gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
590gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
396gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
591gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
592+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
397gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
593gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
398gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
594gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
399−modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
595+modernc.org/cc/v4 v4.28.4 h1:Hd/4Es+MBj+/7hSdZaisNyu6bv3V0Dp2MdllyfqaH+c=
400−modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
596+modernc.org/cc/v4 v4.28.4/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
597+modernc.org/ccgo/v4 v4.34.4 h1:OVnSOWQjVKOYkFxoHYB+qQmSHK5gqMqARM+K9DpR/Ws=
598+modernc.org/ccgo/v4 v4.34.4/go.mod h1:qdKqE8FNIYyysougB1RX9MxCzp5oJOcQXSobANJ4TuE=
599+modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
600+modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
601+modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
602+modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
603+modernc.org/gc/v3 v3.1.3 h1:6QAplYyVO+KdPW3pGnqmJDUxtkec8ooEWvks/hhU3lc=
604+modernc.org/gc/v3 v3.1.3/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
605+modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
606+modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
607+modernc.org/libc v1.73.4 h1:+ra4Ui8ngyt8HDcO1FTDPWlkAh6yOdaO2yAoh8MddQA=
608+modernc.org/libc v1.73.4/go.mod h1:DXZ3eO8qMCNn2SnmTNCiC71nJ9Rcq3PsnpU6Vc4rWK8=
401modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
609modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
402modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
610modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
403−modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
611+modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
404−modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
612+modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
405−modernc.org/sqlite v1.36.2 h1:vjcSazuoFve9Wm0IVNHgmJECoOXLZM1KfMXbcX2axHA=
613+modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
406−modernc.org/sqlite v1.36.2/go.mod h1:ADySlx7K4FdY5MaJcEv86hTJ0PjedAloTUuif0YS3ws=
614+modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
407−mvdan.cc/sh/v3 v3.12.1-0.20250726150758-e256f53bade8 h1:yOKqXg3uKDx7VxqnrKRUzB+InP3whTBi7jeggyFkfX0=
615+modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
408−mvdan.cc/sh/v3 v3.12.1-0.20250726150758-e256f53bade8/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg=
616+modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
617+modernc.org/sqlite v1.53.0 h1:20WG8N9q4ji/dEqGk4uiI0c6OPjSeLTNYGFCc3+7c1M=
618+modernc.org/sqlite v1.53.0/go.mod h1:xoEpOIpGrgT48H5iiyt/YXPCZPEzlfmfFwtk8Lklw8s=
619+modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
620+modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
621+modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
622+modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
623+mvdan.cc/sh/moreinterp v0.0.0-20250902163504-3cf4fd5717a5 h1:mO2lyKtGwu4mGQ+Qqjx0+fd5UU5BXhX/rslFmxd5aco=
624+mvdan.cc/sh/moreinterp v0.0.0-20250902163504-3cf4fd5717a5/go.mod h1:Of9PCedbLDYT8b3EyiYG64rNnx5nOp27OLCVdDrjJyo=
625+mvdan.cc/sh/v3 v3.13.1 h1:DP3TfgZhDkT7lerUdnp6PTGKyxxzz6T+cOlY/xEvfWk=
626+mvdan.cc/sh/v3 v3.13.1/go.mod h1:lXJ8SexMvEVcHCoDvAGLZgFJ9Wsm2sulmoNEXGhYZD0=
internal/agent/.env.samplenew file+5
@@ -0,0 +1,5 @@
1+CRUSH_ANTHROPIC_API_KEY=
4+CRUSH_OPENROUTER_API_KEY=
internal/agent/accepted_run_test.gonew file+231
@@ -0,0 +1,231 @@
7+ "github.com/charmbracelet/crush/internal/message"
8+ "github.com/stretchr/testify/assert"
9+ "github.com/stretchr/testify/require"
12+// newCancelTestAgent builds a DB-backed sessionAgent with no model. The
13+// tests here exercise the dispatch/cancel/persist paths, none of which
14+// reach agent.Stream, so a model is unnecessary.
15+func newCancelTestAgent(t *testing.T) (*sessionAgent, fakeEnv) {
18+ sa := NewSessionAgent(SessionAgentOptions{
19+ Sessions: env.sessions,
20+ Messages: env.messages,
25+func (a *sessionAgent) acceptedCount(sessionID string) int {
26+ c, _ := a.acceptedRuns.Get(sessionID)
30+func (a *sessionAgent) hasPendingCancel(sessionID string) bool {
31+ mark, ok := a.cancelMark.Get(sessionID)
32+ return ok && mark > 0
35+func (a *sessionAgent) pendingCancelMark(sessionID string) uint64 {
36+ mark, _ := a.cancelMark.Get(sessionID)
40+func TestAcceptedRun_CloseIsIdempotent(t *testing.T) {
42+ sa, _ := newCancelTestAgent(t)
44+ accept := sa.BeginAccepted("sid")
45+ require.Equal(t, "sid", accept.SessionID())
46+ require.Equal(t, 1, sa.acceptedCount("sid"))
49+ require.Equal(t, 0, sa.acceptedCount("sid"))
51+ // Repeated Close must not underflow the counter.
54+ require.Equal(t, 0, sa.acceptedCount("sid"))
57+func TestAcceptedRun_MultipleReservations(t *testing.T) {
59+ sa, _ := newCancelTestAgent(t)
61+ a1 := sa.BeginAccepted("sid")
62+ a2 := sa.BeginAccepted("sid")
63+ require.Equal(t, 2, sa.acceptedCount("sid"))
66+ require.Equal(t, 1, sa.acceptedCount("sid"))
69+ require.Equal(t, 0, sa.acceptedCount("sid"))
72+func TestAcceptedRun_NilSafe(t *testing.T) {
74+ var accept *AcceptedRun
75+ require.Equal(t, "", accept.SessionID())
80+func TestCancel_IdleDoesNotRecordPendingCancel(t *testing.T) {
82+ sa, _ := newCancelTestAgent(t)
84+ // No accepted run, no active request: a true no-op.
86+ require.False(t, sa.hasPendingCancel("sid"))
89+func TestCancel_AcceptedRecordsPendingCancel(t *testing.T) {
91+ sa, _ := newCancelTestAgent(t)
93+ accept := sa.BeginAccepted("sid")
97+ require.True(t, sa.hasPendingCancel("sid"))
100+func TestCancel_SecondCancelWhilePendingIsNoOp(t *testing.T) {
102+ sa, _ := newCancelTestAgent(t)
104+ accept := sa.BeginAccepted("sid")
105+ defer accept.Close()
108+ require.True(t, sa.hasPendingCancel("sid"))
110+ // A second cancel while a pending cancel is already recorded must
111+ // remain a single pending cancel; one Run consumes exactly one.
113+ require.True(t, sa.hasPendingCancel("sid"))
116+func TestRun_CancelOnEntryPersistsCanceledTurn(t *testing.T) {
118+ sa, env := newCancelTestAgent(t)
120+ sess, err := env.sessions.Create(t.Context(), "session")
121+ require.NoError(t, err)
123+ accept := sa.BeginAccepted(sess.ID)
124+ // A cancel arrives in the accepted-but-not-yet-active window.
126+ require.True(t, sa.hasPendingCancel(sess.ID))
128+ result, err := sa.Run(t.Context(), SessionAgentCall{
133+ require.NoError(t, err)
134+ require.Nil(t, result)
136+ // The pending cancel was consumed and the accept released.
137+ require.False(t, sa.hasPendingCancel(sess.ID))
138+ require.Equal(t, 0, sa.acceptedCount(sess.ID))
140+ msgs, err := env.messages.List(t.Context(), sess.ID)
141+ require.NoError(t, err)
142+ require.Len(t, msgs, 2)
143+ assert.Equal(t, message.User, msgs[0].Role)
144+ assert.Equal(t, message.Assistant, msgs[1].Role)
145+ assert.Equal(t, message.FinishReasonCanceled, msgs[1].FinishReason())
148+func TestPersistCanceledTurn_WritesBothWhenUserMissing(t *testing.T) {
150+ sa, env := newCancelTestAgent(t)
152+ sess, err := env.sessions.Create(t.Context(), "session")
153+ require.NoError(t, err)
155+ err = sa.persistCanceledTurn(t.Context(), SessionAgentCall{
159+ require.NoError(t, err)
161+ msgs, err := env.messages.List(t.Context(), sess.ID)
162+ require.NoError(t, err)
163+ require.Len(t, msgs, 2)
164+ assert.Equal(t, message.User, msgs[0].Role)
165+ assert.Equal(t, message.Assistant, msgs[1].Role)
166+ assert.Equal(t, message.FinishReasonCanceled, msgs[1].FinishReason())
169+func TestPersistCanceledTurn_WritesAssistantOnlyWhenUserCreated(t *testing.T) {
171+ sa, env := newCancelTestAgent(t)
173+ sess, err := env.sessions.Create(t.Context(), "session")
174+ require.NoError(t, err)
176+ // Simulate PrepareStep having already created the user message.
177+ _, err = sa.createUserMessage(t.Context(), SessionAgentCall{
181+ require.NoError(t, err)
183+ err = sa.persistCanceledTurn(t.Context(), SessionAgentCall{
187+ require.NoError(t, err)
189+ msgs, err := env.messages.List(t.Context(), sess.ID)
190+ require.NoError(t, err)
191+ require.Len(t, msgs, 2)
192+ assert.Equal(t, message.User, msgs[0].Role)
193+ assert.Equal(t, message.Assistant, msgs[1].Role)
194+ assert.Equal(t, message.FinishReasonCanceled, msgs[1].FinishReason())
197+func TestPersistCanceledTurn_SucceedsWithCanceledContext(t *testing.T) {
199+ sa, env := newCancelTestAgent(t)
201+ sess, err := env.sessions.Create(t.Context(), "session")
202+ require.NoError(t, err)
204+ // Simulate workspace shutdown having already canceled the run
205+ // context. WithoutCancel must let the writes through.
206+ ctx, cancel := context.WithCancel(t.Context())
209+ err = sa.persistCanceledTurn(ctx, SessionAgentCall{
213+ require.NoError(t, err)
215+ msgs, err := env.messages.List(t.Context(), sess.ID)
216+ require.NoError(t, err)
217+ require.Len(t, msgs, 2)
220+func TestClearPendingCancel(t *testing.T) {
222+ sa, _ := newCancelTestAgent(t)
224+ accept := sa.BeginAccepted("sid")
225+ defer accept.Close()
227+ require.True(t, sa.hasPendingCancel("sid"))
229+ sa.clearPendingCancel("sid")
230+ require.False(t, sa.hasPendingCancel("sid"))
internal/agent/agent.gonew file+2248
@@ -0,0 +1,2248 @@
1+// Package agent is the core orchestration layer for Crush AI agents.
3+// It provides session-based AI agent functionality for managing
4+// conversations, tool execution, and message handling. It coordinates
5+// interactions between language models, messages, sessions, and tools while
6+// handling features like automatic summarization, queuing, and token
29+ "charm.land/catwalk/pkg/catwalk"
31+ "charm.land/fantasy/providers/anthropic"
32+ "charm.land/fantasy/providers/bedrock"
33+ "charm.land/fantasy/providers/google"
34+ "charm.land/fantasy/providers/openai"
35+ "charm.land/fantasy/providers/openrouter"
36+ "charm.land/fantasy/providers/vercel"
37+ "charm.land/lipgloss/v2"
38+ "github.com/charmbracelet/crush/internal/agent/hyper"
39+ "github.com/charmbracelet/crush/internal/agent/notify"
40+ "github.com/charmbracelet/crush/internal/agent/tools"
41+ "github.com/charmbracelet/crush/internal/agent/tools/mcp"
42+ "github.com/charmbracelet/crush/internal/config"
43+ "github.com/charmbracelet/crush/internal/csync"
44+ "github.com/charmbracelet/crush/internal/message"
45+ "github.com/charmbracelet/crush/internal/pubsub"
46+ "github.com/charmbracelet/crush/internal/session"
47+ "github.com/charmbracelet/crush/internal/stringext"
48+ "github.com/charmbracelet/crush/internal/version"
49+ "github.com/charmbracelet/x/ansi"
50+ "github.com/charmbracelet/x/exp/charmtone"
54+ DefaultSessionName = "Untitled Session"
56+ // Constants for auto-summarization thresholds
57+ largeContextWindowThreshold = 200_000
58+ largeContextWindowBuffer = 20_000
59+ smallContextWindowRatio = 0.2
62+var userAgent = fmt.Sprintf("Charm-Crush/%s (https://charm.land/crush)", version.Version)
64+//go:embed templates/title.md
65+var titlePrompt []byte
67+//go:embed templates/summary.md
68+var summaryPrompt []byte
70+// Used to remove <think> tags from generated titles.
72+ thinkTagRegex = regexp.MustCompile(`(?s)<think>.*?</think>`)
73+ orphanThinkTagRegex = regexp.MustCompile(`</?think>`)
76+type SessionAgentCall struct {
78+ // RunID, when non-empty, is the caller-supplied correlator that
79+ // gets echoed back on the notify.RunComplete event emitted for
80+ // this turn. It is preserved when the call is enqueued behind a
81+ // busy session so the queued turn's terminal event is still
82+ // recognisable to the original caller. Callers that need a
83+ // reliable completion contract (e.g. `crush run` against a
84+ // session that may be busy) MUST set it; SessionID alone is
85+ // ambiguous when concurrent turns share the same session.
88+ ProviderOptions fantasy.ProviderOptions
89+ Attachments []message.Attachment
90+ MaxOutputTokens int64
94+ FrequencyPenalty *float64
95+ PresencePenalty *float64
97+ // OnComplete, when non-nil, replaces the default RunComplete
98+ // publish path: the inner Run hands the terminal payload to this
99+ // callback instead of emitting it on the RunComplete broker. The
100+ // coordinator uses this hook to coalesce the unauthorized →
101+ // re-auth → retry chain into a single user-visible terminal
102+ // event, so non-interactive clients (e.g. `crush run`) don't
103+ // exit on a stale failed-attempt RunComplete before the
104+ // successful retry. It is intentionally stripped when queueing
105+ // a busy-session call (see Run): the originating
106+ // coordinator.Run has long returned by the time the queued
107+ // recursion drains, so falling back to the default broker
108+ // publish keeps the event visible to subscribers.
109+ OnComplete func(notify.RunComplete)
110+ // Accepted, when non-nil, is the accept reservation taken by
111+ // BeginAccepted before the call was dispatched onto a goroutine
112+ // (the client/server fire-and-forget path). Run consumes it under
113+ // dispatchMu[SessionID] once the accepted -> (cancel-on-entry |
114+ // queued | active) transition has been chosen. When nil
115+ // (in-process / local callers like AppWorkspace), behavior is
116+ // unchanged and no accept tracking applies.
117+ Accepted *AcceptedRun
118+ // acceptSeq carries the accept sequence of the handle that produced
119+ // this call after it has been enqueued and its Accepted handle
120+ // stripped. The queue-drain paths compare it against a session's
121+ // cancel mark so a follow-up queued before a cancel is dropped while
122+ // one queued after the cancel survives. 0 means untracked (an
123+ // in-process enqueue with no accept reservation), which the drain
124+ // paths treat as covered by any present mark, preserving the
125+ // pre-sequence behavior.
129+type SessionAgent interface {
130+ Run(context.Context, SessionAgentCall) (*fantasy.AgentResult, error)
131+ BeginAccepted(sessionID string) *AcceptedRun
132+ SetModels(large Model, small Model)
133+ SetTools(tools []fantasy.AgentTool)
134+ SetSystemPrompt(systemPrompt string)
135+ Cancel(sessionID string)
137+ IsSessionBusy(sessionID string) bool
139+ QueuedPrompts(sessionID string) int
140+ QueuedPromptsList(sessionID string) []string
141+ ClearQueue(sessionID string)
142+ Summarize(context.Context, string, fantasy.ProviderOptions) error
144+ GenerateTitle(ctx context.Context, sessionID, userPrompt string)
148+ Model fantasy.LanguageModel
149+ CatwalkCfg catwalk.Model
150+ ModelCfg config.SelectedModel
154+type sessionAgent struct {
155+ largeModel *csync.Value[Model]
156+ smallModel *csync.Value[Model]
157+ systemPromptPrefix *csync.Value[string]
158+ systemPrompt *csync.Value[string]
159+ tools *csync.Slice[fantasy.AgentTool]
160+ toolsGen atomic.Uint64 // bumped by SetTools; lets PrepareStep skip re-copying unchanged tools
163+ sessions session.Service
164+ messages message.Service
165+ disableAutoSummarize bool
167+ notify pubsub.Publisher[notify.Notification]
168+ runComplete pubsub.Publisher[notify.RunComplete]
170+ messageQueue *csync.Map[string, []SessionAgentCall]
171+ activeRequests *csync.Map[string, context.CancelFunc]
173+ // dispatchMu holds a per-session mutex that serializes the
174+ // accepted -> (cancel-on-entry | queued | active) transition in
175+ // Run against a concurrent Cancel. The lock is held only during
176+ // the brief handoff (no DB or LLM I/O under the lock).
177+ dispatchMu *csync.Map[string, *sync.Mutex]
178+ // acceptedRuns counts dispatched-but-not-yet-active runs per
179+ // session. A counter > 0 means a dispatched prompt is in flight
180+ // and has not yet completed the dispatch handoff in Run. Only
181+ // BeginAccepted increments it; only AcceptedRun.Close decrements
183+ acceptedRuns *csync.Map[string, int]
184+ // cancelMark records, per session, a high-water accept sequence: an
185+ // accepted handle is canceled by it iff the handle's sequence is at
186+ // or below the mark. Cancel raises the mark to the latest sequence
187+ // assigned at cancel time, so a single Cancel covers every prompt
188+ // accepted-but-not-yet-active then, while a prompt accepted later
189+ // (higher sequence) is never poisoned. Absent or 0 means no pending
190+ // cancel. It is only raised by Cancel when acceptedRuns > 0, so an
191+ // idle Escape never records a mark.
192+ cancelMark *csync.Map[string, uint64]
193+ // dispatchMuCreate guards lazy creation of per-session entries in
194+ // dispatchMu so two goroutines can't race to lock different mutex
195+ // instances for the same session.
196+ dispatchMuCreate sync.Mutex
197+ // acceptedMu serializes increments/decrements of acceptedRuns and
198+ // the assignment of accept sequence numbers from acceptSeqGen. It
199+ // is separate from dispatchMu so AcceptedRun.Close (which may run
200+ // while Run holds dispatchMu for the same session) does not
201+ // deadlock by re-entering the dispatch lock.
202+ acceptedMu sync.Mutex
203+ // acceptSeqGen is the monotonic source of accept sequence numbers.
204+ // Each BeginAccepted increments it under acceptedMu and stamps the
205+ // returned handle, so sequences strictly increase in accept order
206+ // across the agent. Cancel uses its current value as the per-session
211+type SessionAgentOptions struct {
214+ SystemPromptPrefix string
217+ DisableAutoSummarize bool
219+ Sessions session.Service
220+ Messages message.Service
221+ Tools []fantasy.AgentTool
222+ Notify pubsub.Publisher[notify.Notification]
223+ RunComplete pubsub.Publisher[notify.RunComplete]
226+func NewSessionAgent(
227+ opts SessionAgentOptions,
229+ return &sessionAgent{
230+ largeModel: csync.NewValue(opts.LargeModel),
231+ smallModel: csync.NewValue(opts.SmallModel),
232+ systemPromptPrefix: csync.NewValue(opts.SystemPromptPrefix),
233+ systemPrompt: csync.NewValue(opts.SystemPrompt),
234+ isSubAgent: opts.IsSubAgent,
235+ sessions: opts.Sessions,
236+ messages: opts.Messages,
237+ disableAutoSummarize: opts.DisableAutoSummarize,
238+ tools: csync.NewSliceFrom(opts.Tools),
239+ isYolo: opts.IsYolo,
240+ notify: opts.Notify,
241+ runComplete: opts.RunComplete,
242+ messageQueue: csync.NewMap[string, []SessionAgentCall](),
243+ activeRequests: csync.NewMap[string, context.CancelFunc](),
244+ dispatchMu: csync.NewMap[string, *sync.Mutex](),
245+ acceptedRuns: csync.NewMap[string, int](),
246+ cancelMark: csync.NewMap[string, uint64](),
250+// AcceptedRun owns exactly one accept reservation taken by
251+// BeginAccepted. It is the only carrier of accept-state across the
252+// backend.runAgent / Coordinator.Run / sessionAgent.Run layers: a
253+// counter > 0 means a dispatched prompt is in flight and has not yet
254+// completed the dispatch handoff in Run. Close is the only way to
255+// release the reservation and is idempotent.
256+type AcceptedRun struct {
259+ // seq is the monotonic accept sequence stamped by BeginAccepted. A
260+ // cancel covers this handle iff seq is at or below the session's
261+ // cancel mark, so a handle accepted after a cancel (higher seq) is
262+ // never poisoned by it.
267+// Close decrements the accept counter for this reservation. It is safe
268+// to call multiple times; only the first call has effect.
269+func (r *AcceptedRun) Close() {
273+ if !r.done.CompareAndSwap(false, true) {
276+ r.agent.endAccepted(r.sessionID)
279+// SessionID exposes the session this reservation is for so the run path
280+// can use it without an extra parameter.
281+func (r *AcceptedRun) SessionID() string {
288+// BeginAccepted increments the accept counter for sessionID and returns
289+// a handle whose Close is the only way to decrement it. It is the only
290+// entry point that mutates acceptedRuns.
291+func (a *sessionAgent) BeginAccepted(sessionID string) *AcceptedRun {
293+ defer a.acceptedMu.Unlock()
294+ count, _ := a.acceptedRuns.Get(sessionID)
295+ a.acceptedRuns.Set(sessionID, count+1)
297+ return &AcceptedRun{agent: a, sessionID: sessionID, seq: a.acceptSeqGen}
300+// endAccepted decrements the accept counter for sessionID. It is only
301+// called via AcceptedRun.Close. It uses a dedicated lock (not the
302+// per-session dispatch mutex) so it can run while Run holds dispatchMu
303+// for the same session without deadlocking.
305+// When the count reaches zero the session's cancel mark is dropped: no
306+// accepted handle remains for it to cover, and any handle accepted later
307+// gets a strictly higher sequence that the mark would not match anyway.
308+// Handles canceled on entry never reach RunComplete, so this is the only
309+// place that clears the mark for an all-canceled batch. Sibling handles
310+// covered by the same mark are serialized on the per-session dispatch
311+// mutex and read the mark before they Close, so this never clears it out
312+// from under a covered handle still waiting to enter Run.
313+func (a *sessionAgent) endAccepted(sessionID string) {
315+ defer a.acceptedMu.Unlock()
316+ count, ok := a.acceptedRuns.Get(sessionID)
317+ if !ok || count <= 1 {
318+ a.acceptedRuns.Del(sessionID)
319+ a.cancelMark.Del(sessionID)
322+ a.acceptedRuns.Set(sessionID, count-1)
325+// sessionMu returns the per-session dispatch mutex, creating it on first
326+// use. Creation is guarded so concurrent callers always observe the same
327+// mutex instance for a given session.
328+func (a *sessionAgent) sessionMu(sessionID string) *sync.Mutex {
329+ if mu, ok := a.dispatchMu.Get(sessionID); ok {
332+ a.dispatchMuCreate.Lock()
333+ defer a.dispatchMuCreate.Unlock()
334+ if mu, ok := a.dispatchMu.Get(sessionID); ok {
338+ a.dispatchMu.Set(sessionID, mu)
342+// enqueueCall appends call to the session's message queue. The
343+// OnComplete hook is stripped: the caller that supplied it (typically
344+// coordinator.Run) has its own retry/coalesce scope that ends when it
345+// returns, so by the time the queue drains nobody is left to consume the
346+// buffered terminal event. The recursive Run falls back to the default
347+// broker publish, which is what existing subscribers expect for queued
349+func (a *sessionAgent) enqueueCall(call SessionAgentCall) {
350+ existing, ok := a.messageQueue.Get(call.SessionID)
352+ existing = make([]SessionAgentCall, 0, 4)
355+ if call.Accepted != nil {
356+ // Preserve the accept sequence after the handle is stripped so
357+ // the queue-drain paths can tell a follow-up queued before a
358+ // cancel (covered by the mark) from one queued after it.
359+ queued.acceptSeq = call.Accepted.seq
361+ queued.OnComplete = nil
362+ queued.Accepted = nil
363+ existing = append(existing, queued)
364+ a.messageQueue.Set(call.SessionID, existing)
367+// drainQueueForStep partitions the session's queued calls for the current
368+// streaming step under the per-session dispatch mutex so the filtering is
369+// atomic against a concurrent Cancel: canceledBySeq requires the caller to
370+// hold that mutex, and evaluating it here (rather than after unlocking)
371+// prevents a cancel recorded between the drain and the check from being
372+// observed inconsistently.
374+// Calls covered by a pending cancel are dropped; the dropped ones that
375+// carry a RunID are returned in canceledWithRunID so the caller can
376+// publish their terminal cancelled RunComplete (a caller waiting on that
377+// RunID, e.g. `crush run`, would otherwise hang). Uncanceled calls without
378+// a RunID are returned in fold to be folded into the active turn,
379+// preserving the existing follow-up behavior. Uncanceled calls that carry
380+// a RunID are left in the queue so each runs as its own turn via the
381+// recursive run path and publishes its own RunComplete, giving every
382+// RunID-bearing prompt an explicit lifecycle instead of being silently
383+// absorbed into another turn. fold is processed by the caller without the
385+func (a *sessionAgent) drainQueueForStep(sessionID string) (fold, canceledWithRunID []SessionAgentCall) {
386+ dispatchLock := a.sessionMu(sessionID)
388+ defer dispatchLock.Unlock()
389+ queuedCalls, _ := a.messageQueue.Get(sessionID)
390+ var keep []SessionAgentCall
391+ for _, queued := range queuedCalls {
392+ if a.canceledBySeq(sessionID, queued.acceptSeq) {
393+ if queued.RunID != "" {
394+ canceledWithRunID = append(canceledWithRunID, queued)
398+ if queued.RunID != "" {
399+ keep = append(keep, queued)
402+ fold = append(fold, queued)
405+ a.messageQueue.Del(sessionID)
407+ a.messageQueue.Set(sessionID, keep)
409+ return fold, canceledWithRunID
412+// publishCanceledQueueDrops emits a terminal cancelled RunComplete for
413+// every dropped queued call that carries a RunID. A queued prompt removed
414+// from the queue without ever running — covered by a pending cancel, or
415+// cleared by Cancel/ClearQueue — would otherwise leave a caller blocked on
416+// that RunID: `crush run` ignores live message events and exits only on a
417+// RunComplete whose RunID matches. Calls without a RunID had no such waiter
418+// and are dropped silently as before. A detached, bounded context keeps the
419+// must-deliver publish alive even when the run context that triggered the
420+// drop is already canceled.
421+func (a *sessionAgent) publishCanceledQueueDrops(drops []SessionAgentCall) {
423+ for _, d := range drops {
432+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
434+ for _, d := range drops {
438+ a.publishRunComplete(ctx, d, notify.RunComplete{
439+ SessionID: d.SessionID,
446+// clearQueueAndNotify removes all queued prompts for the session and
447+// publishes a terminal cancelled RunComplete for any that carried a RunID,
448+// so callers waiting on those RunIDs (e.g. `crush run`) are not left
449+// hanging when their queued prompt is discarded without running.
450+func (a *sessionAgent) clearQueueAndNotify(sessionID string) {
451+ queued, ok := a.messageQueue.Get(sessionID)
452+ a.messageQueue.Del(sessionID)
456+ a.publishCanceledQueueDrops(queued)
459+// clearPendingCancel removes any pending-cancel mark for sessionID. It
460+// takes the per-session dispatch lock so it is ordered against Cancel
461+// and the dispatch handoff.
462+func (a *sessionAgent) clearPendingCancel(sessionID string) {
463+ mu := a.sessionMu(sessionID)
466+ a.cancelMark.Del(sessionID)
469+// canceledBySeq reports whether an accepted handle or queued call with
470+// the given accept sequence is covered by a pending cancel for the
471+// session. Callers must hold the session's dispatch mutex. A tracked
472+// sequence (seq > 0) is covered only when it is at or below the cancel
473+// high-water mark, so a prompt accepted after the cancel (higher seq) is
474+// never poisoned. An untracked sequence (seq == 0, an in-process enqueue
475+// with no accept reservation) is covered whenever any mark is present,
476+// preserving the pre-sequence behavior. The mark is not consumed: it
477+// stays so every sibling handle it covers observes the same cancel, and
478+// a later handle (higher seq) ignores it regardless.
479+func (a *sessionAgent) canceledBySeq(sessionID string, seq uint64) bool {
480+ mark, ok := a.cancelMark.Get(sessionID)
481+ if !ok || mark == 0 {
484+ return seq == 0 || seq <= mark
487+// persistCanceledTurn writes the user/assistant records for a turn that
488+// was canceled before (or just as) streaming would have produced them.
489+// It creates the user message only when it was not already created by an
490+// earlier createUserMessage call (userMsgCreated), then writes an
491+// assistant message with FinishReasonCanceled. Both writes use
492+// context.WithoutCancel(ctx) so workspace shutdown (which cancels the run
493+// context) can't drop them.
494+func (a *sessionAgent) persistCanceledTurn(ctx context.Context, call SessionAgentCall, userMsgCreated bool) error {
495+ writeCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
497+ if !userMsgCreated {
498+ if _, err := a.createUserMessage(writeCtx, call); err != nil {
502+ largeModel := a.largeModel.Get()
503+ assistant, err := a.messages.Create(writeCtx, call.SessionID, message.CreateMessageParams{
504+ Role: message.Assistant,
505+ Parts: []message.ContentPart{},
506+ Model: largeModel.ModelCfg.Model,
507+ Provider: largeModel.ModelCfg.Provider,
512+ assistant.AddFinish(message.FinishReasonCanceled, "User canceled request", "")
513+ return a.messages.Update(writeCtx, assistant)
516+// publishRunComplete emits the authoritative terminal event for a turn.
517+// It honors the per-call OnComplete hook when set (so the coordinator can
518+// coalesce retries) and otherwise falls back to the RunComplete broker.
519+// ctx is used only for the bounded-blocking must-deliver publish; the
520+// terminal payload is supplied by the caller. This is the single emit path
521+// shared by the streaming defer and the cancel-on-entry early return so a
522+// caller waiting on RunComplete (e.g. `crush run` with a RunID) always
523+// observes exactly one terminal event regardless of which Run branch ends
525+func (a *sessionAgent) publishRunComplete(ctx context.Context, call SessionAgentCall, complete notify.RunComplete) {
526+ if call.OnComplete != nil {
527+ call.OnComplete(complete)
530+ if a.runComplete == nil {
533+ a.runComplete.PublishMustDeliver(ctx, pubsub.UpdatedEvent, complete)
536+// ValidateCall performs the cheap structural validation that
537+// sessionAgent.Run requires before a call can be dispatched: a call must
538+// carry either a non-empty prompt or a text attachment, and it must name a
539+// session. It is exported so callers that accept a run before dispatching it
540+// (e.g. backend.SendMessage) can apply the same checks and keep the error
541+// contract consistent.
542+func ValidateCall(call SessionAgentCall) error {
543+ if call.Prompt == "" && !message.ContainsTextAttachment(call.Attachments) {
544+ return ErrEmptyPrompt
546+ if call.SessionID == "" {
547+ return ErrSessionMissing
552+func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (result *fantasy.AgentResult, retErr error) {
553+ if err := ValidateCall(call); err != nil {
557+ // genCtx/cancel are the run context and its cancel func. For the
558+ // accepted (fire-and-forget) dispatch path they are created under
559+ // dispatchMu below so a concurrent Cancel can observe the
560+ // activeRequests entry before the assistant message exists. For
561+ // the in-process path they stay nil here and are created later,
562+ // preserving the original ordering.
564+ genCtx context.Context
565+ cancel context.CancelFunc
566+ activeRegistered bool
570+ if call.Accepted != nil {
571+ // Serialize the accepted -> (cancel-on-entry | queued |
572+ // active) transition against a concurrent Cancel. Cancel takes
573+ // the same per-session lock, so every cancel observes at least
574+ // one of: a cancel mark, an activeRequests entry, or a
575+ // messageQueue entry it then clears.
576+ mu := a.sessionMu(call.SessionID)
579+ if a.canceledBySeq(call.SessionID, call.Accepted.seq) {
580+ // Cancel-on-entry: a cancel arrived while this run was
581+ // dispatched but not yet active, and this handle's accept
582+ // sequence is at or below the session's cancel mark. The
583+ // mark is left in place so sibling handles it also covers
584+ // observe the same cancel; release the accept reservation,
585+ // drop the lock, and persist a canceled turn without
588+ // This path returns before the streaming defer that
589+ // publishes RunComplete is installed, so emit the terminal
590+ // event explicitly. Without it, a caller waiting on
591+ // RunComplete for this RunID (e.g. `crush run`, which
592+ // ignores message events and blocks on RunComplete) would
593+ // hang on an immediately-canceled accepted run.
594+ call.Accepted.Close()
596+ complete := notify.RunComplete{
597+ SessionID: call.SessionID,
601+ if err := a.persistCanceledTurn(ctx, call, false); err != nil {
602+ complete.Error = err.Error()
603+ a.publishRunComplete(ctx, call, complete)
606+ a.publishRunComplete(ctx, call, complete)
610+ if a.IsSessionBusy(call.SessionID) {
611+ // Busy: an earlier prompt is active. Queue this call and
612+ // release the accept reservation. A Cancel arriving after
613+ // this point sees the active entry and clears the queue.
615+ call.Accepted.Close()
620+ // Idle: become the active run. Register the cancel func before
621+ // dropping the lock so a Cancel that arrives between here and
622+ // assistant creation is not lost.
623+ runCtx := context.WithValue(ctx, tools.SessionIDContextKey, call.SessionID)
624+ genCtx, cancel = context.WithCancel(runCtx)
625+ a.activeRequests.Set(call.SessionID, cancel)
626+ activeRegistered = true
627+ call.Accepted.Close()
631+ defer a.activeRequests.Del(call.SessionID)
632+ } else if a.IsSessionBusy(call.SessionID) {
633+ // Queue the message if busy. Strip OnComplete: the caller that
634+ // supplied the hook (typically coordinator.Run) has its own
635+ // retry/coalesce scope that ends when it returns, so by the time
636+ // the queue drains nobody is left to consume the buffered
637+ // terminal event. The recursive Run will fall back to the
638+ // default broker publish, which is what existing subscribers
639+ // expect for queued turns.
644+ // Copy mutable fields under lock to avoid races with SetTools/SetModels.
645+ agentTools := a.tools.Copy()
646+ // Per-step tool snapshot reused across PrepareStep calls; only
647+ // re-copied when SetTools bumps toolsGen (see PrepareStep below).
649+ stepTools []fantasy.AgentTool
653+ largeModel := a.largeModel.Get()
654+ systemPrompt := a.systemPrompt.Get()
655+ promptPrefix := a.systemPromptPrefix.Get()
656+ var instructions strings.Builder
658+ for _, server := range mcp.GetStates() {
659+ if server.State != mcp.StateConnected {
662+ if s := server.Client.InitializeResult().Instructions; s != "" {
663+ instructions.WriteString(s)
664+ instructions.WriteString("\n\n")
668+ if s := instructions.String(); s != "" {
669+ systemPrompt += "\n\n<mcp-instructions>\n" + s + "\n</mcp-instructions>"
672+ if len(agentTools) > 0 {
673+ // Add Anthropic caching to the last tool.
674+ agentTools[len(agentTools)-1].SetProviderOptions(a.getCacheControlOptions())
677+ agent := fantasy.NewAgent(
679+ fantasy.WithSystemPrompt(systemPrompt),
680+ fantasy.WithTools(agentTools...),
681+ fantasy.WithUserAgent(userAgent),
684+ sessionLock := sync.Mutex{}
685+ currentSession, err := a.sessions.Get(ctx, call.SessionID)
687+ return nil, fmt.Errorf("failed to get session: %w", err)
690+ msgs, err := a.getSessionMessages(ctx, currentSession)
692+ return nil, fmt.Errorf("failed to get session messages: %w", err)
695+ var wg sync.WaitGroup
696+ // Generate title from the first real (non-shell) user prompt.
697+ if !hasUserTextMessage(msgs) {
698+ titleCtx := ctx // Copy to avoid race with ctx reassignment below.
700+ a.GenerateTitle(titleCtx, call.SessionID, call.Prompt)
705+ // Add the user message to the session.
706+ _, err = a.createUserMessage(ctx, call)
710+ userMsgCreated = true
712+ // Add the session to the context.
713+ ctx = context.WithValue(ctx, tools.SessionIDContextKey, call.SessionID)
715+ // For the accepted dispatch path the run context and cancel func
716+ // were already created and registered under dispatchMu above; reuse
717+ // them. For the in-process path create them here, preserving the
718+ // original ordering.
719+ if !activeRegistered {
720+ genCtx, cancel = context.WithCancel(ctx)
721+ a.activeRequests.Set(call.SessionID, cancel)
724+ defer a.activeRequests.Del(call.SessionID)
726+ // skipRunComplete is set just before the queued-recursion path so
727+ // the outer Run doesn't publish a RunComplete that would race
728+ // with — and be superseded by — the recursive call's own
729+ // RunComplete (each queued user prompt is its own turn and
730+ // publishes exactly one terminal event).
731+ var skipRunComplete bool
732+ // currentAssistant is declared here so the deferred RunComplete
733+ // publish below can capture the pointer that PrepareStep will
734+ // later (re)assign for each streaming step. The final assistant
735+ // message of the turn is the value reachable through this
736+ // pointer when the defer runs.
737+ var currentAssistant *message.Message
738+ // Drain any debounced message updates before returning. message.Service
739+ // already flushes synchronously on terminal updates, but a defer here
740+ // guarantees the contract at every Run exit (success, error, panic
741+ // recovery upstream) without callers needing to know.
743+ // After the flush completes — meaning all per-message
744+ // Publish(UpdatedEvent) calls have fired and been buffered into
745+ // every subscriber's channel — publish the authoritative
746+ // RunComplete event for this turn. The flush-then-publish order
747+ // gives well-behaved clients the best chance of seeing the final
748+ // message event before RunComplete; the embedded Text field
749+ // reconciles for clients that observe the events out of order
750+ // (the pubsub broker fan-in does not serialize publishes from
751+ // different upstream brokers).
753+ // Use a context detached from the run context: workspace
754+ // shutdown cancels ctx before this goroutine returns, but the
755+ // buffered streaming deltas must still land before the DB is
756+ // closed. A short timeout bounds the flush.
757+ flushCtx, flushCancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
759+ if flushErr := a.messages.FlushAll(flushCtx); flushErr != nil {
760+ slog.Error("Failed to flush pending message updates after run", "error", flushErr)
762+ if skipRunComplete {
765+ complete := notify.RunComplete{SessionID: call.SessionID, RunID: call.RunID}
766+ if currentAssistant != nil {
767+ complete.MessageID = currentAssistant.ID
768+ complete.Text = currentAssistant.Content().String()
771+ complete.Error = retErr.Error()
772+ complete.Cancelled = errors.Is(retErr, context.Canceled)
773+ } else if ctx.Err() != nil {
774+ complete.Cancelled = true
776+ // Prefer the per-call hook when supplied so the coordinator
777+ // can coalesce retries (e.g. unauthorized → re-auth → retry)
778+ // into a single user-visible terminal event. The fallback
779+ // must-deliver publish applies bounded-blocking semantics to
780+ // the authoritative terminal event so a momentarily-full
781+ // subscriber channel can't silently drop it and hang
782+ // non-interactive clients waiting on RunComplete.
783+ a.publishRunComplete(ctx, call, complete)
786+ history, files := a.preparePrompt(msgs, largeModel.CatwalkCfg.SupportsImages, call.Attachments...)
788+ startTime := time.Now()
789+ a.eventPromptSent(call.SessionID)
791+ var stepMessages []fantasy.Message
792+ var shouldSummarize bool
793+ sanitizedToolCalls := make(map[string]bool)
794+ // Don't send MaxOutputTokens if 0 — some providers (e.g. LM Studio) reject it
795+ var maxOutputTokens *int64
796+ if call.MaxOutputTokens > 0 {
797+ maxOutputTokens = &call.MaxOutputTokens
799+ result, err = agent.Stream(genCtx, fantasy.AgentStreamCall{
800+ Prompt: message.PromptWithTextAttachments(call.Prompt, call.Attachments),
803+ ProviderOptions: call.ProviderOptions,
804+ MaxOutputTokens: maxOutputTokens,
806+ Temperature: call.Temperature,
807+ PresencePenalty: call.PresencePenalty,
809+ FrequencyPenalty: call.FrequencyPenalty,
810+ PrepareStep: func(callContext context.Context, options fantasy.PrepareStepFunctionOptions) (_ context.Context, prepared fantasy.PrepareStepResult, err error) {
811+ prepared.Messages = options.Messages
812+ for i := range prepared.Messages {
813+ prepared.Messages[i].ProviderOptions = nil
816+ // Use latest tools (updated by SetTools when MCP tools change).
817+ // Reuse the previous step's copy unless SetTools has bumped the
818+ // generation, so an unchanged tool set isn't re-copied every step.
819+ if gen := a.toolsGen.Load(); !stepToolsInit || gen != stepToolsGen {
820+ stepTools = a.tools.Copy()
822+ stepToolsInit = true
824+ prepared.Tools = stepTools
826+ // Drain queued follow-up prompts for this step. Calls covered
827+ // by a cancel recorded while they sat in the queue are dropped:
828+ // a cancel that arrived after a prompt was queued must not let
829+ // it run as part of this step. Coverage is per-call by accept
830+ // sequence so a follow-up queued after the cancel (higher seq)
831+ // is not dropped. A dropped prompt carrying a RunID still gets
832+ // its terminal cancelled RunComplete so a caller waiting on it
833+ // does not hang. Uncanceled prompts without a RunID are folded
834+ // into this turn; uncanceled prompts with a RunID are left
835+ // queued so each runs as its own turn (with its own
836+ // RunComplete) via the recursive run path below.
837+ fold, canceledRunIDs := a.drainQueueForStep(call.SessionID)
838+ a.publishCanceledQueueDrops(canceledRunIDs)
839+ for _, queued := range fold {
840+ userMessage, createErr := a.createUserMessage(callContext, queued)
841+ if createErr != nil {
842+ return callContext, prepared, createErr
844+ prepared.Messages = append(prepared.Messages, userMessage.ToAIMessage()...)
847+ prepared.Messages = a.workaroundProviderMediaLimitations(prepared.Messages, largeModel)
849+ lastSystemRoleInx := 0
850+ systemMessageUpdated := false
851+ for i, msg := range prepared.Messages {
852+ // Only add cache control to the last message.
853+ if msg.Role == fantasy.MessageRoleSystem {
854+ lastSystemRoleInx = i
855+ } else if !systemMessageUpdated {
856+ prepared.Messages[lastSystemRoleInx].ProviderOptions = a.getCacheControlOptions()
857+ systemMessageUpdated = true
859+ // Than add cache control to the last 2 messages.
860+ if i > len(prepared.Messages)-3 {
861+ prepared.Messages[i].ProviderOptions = a.getCacheControlOptions()
865+ if promptPrefix != "" {
866+ prepared.Messages = append([]fantasy.Message{fantasy.NewSystemMessage(promptPrefix)}, prepared.Messages...)
869+ // Save a reference to the prepared messages for token
870+ // estimation in OnStepFinish. No clone needed here — the
871+ // messages are not modified between PrepareStep and
872+ // OnStepFinish (which run sequentially), and the clone is
873+ // only needed when the provider returns zero usage.
874+ stepMessages = prepared.Messages
876+ var assistantMsg message.Message
877+ assistantMsg, err = a.messages.Create(callContext, call.SessionID, message.CreateMessageParams{
878+ Role: message.Assistant,
879+ Parts: []message.ContentPart{},
880+ Model: largeModel.ModelCfg.Model,
881+ Provider: largeModel.ModelCfg.Provider,
884+ return callContext, prepared, err
886+ callContext = context.WithValue(callContext, tools.MessageIDContextKey, assistantMsg.ID)
887+ callContext = context.WithValue(callContext, tools.SupportsImagesContextKey, largeModel.CatwalkCfg.SupportsImages)
888+ callContext = context.WithValue(callContext, tools.ModelNameContextKey, largeModel.CatwalkCfg.Name)
889+ currentAssistant = &assistantMsg
890+ return callContext, prepared, err
892+ OnReasoningStart: func(id string, reasoning fantasy.ReasoningContent) error {
893+ currentAssistant.AppendReasoningContent(reasoning.Text)
894+ return a.messages.Update(genCtx, *currentAssistant)
896+ OnReasoningDelta: func(id string, text string) error {
897+ currentAssistant.AppendReasoningContent(text)
898+ return a.messages.Update(genCtx, *currentAssistant)
900+ OnReasoningEnd: func(id string, reasoning fantasy.ReasoningContent) error {
901+ // handle anthropic signature
902+ if anthropicData, ok := reasoning.ProviderMetadata[anthropic.Name]; ok {
903+ if reasoning, ok := anthropicData.(*anthropic.ReasoningOptionMetadata); ok {
904+ currentAssistant.AppendReasoningSignature(reasoning.Signature)
907+ if googleData, ok := reasoning.ProviderMetadata[google.Name]; ok {
908+ if reasoning, ok := googleData.(*google.ReasoningMetadata); ok {
909+ currentAssistant.AppendThoughtSignature(reasoning.Signature, reasoning.ToolID)
912+ if openaiData, ok := reasoning.ProviderMetadata[openai.Name]; ok {
913+ if reasoning, ok := openaiData.(*openai.ResponsesReasoningMetadata); ok {
914+ currentAssistant.SetReasoningResponsesData(reasoning)
917+ currentAssistant.FinishThinking()
918+ return a.messages.Update(genCtx, *currentAssistant)
920+ OnTextDelta: func(id string, text string) error {
921+ // Strip leading newline from initial text content. This is is
922+ // particularly important in non-interactive mode where leading
923+ // newlines are very visible.
924+ if len(currentAssistant.Parts) == 0 {
925+ text = strings.TrimPrefix(text, "\n")
928+ currentAssistant.AppendContent(text)
929+ return a.messages.Update(genCtx, *currentAssistant)
931+ OnToolInputStart: func(id string, toolName string) error {
932+ toolCall := message.ToolCall{
935+ ProviderExecuted: false,
938+ currentAssistant.AddToolCall(toolCall)
939+ // Use parent ctx instead of genCtx to ensure the update succeeds
940+ // even if the request is canceled mid-stream
941+ return a.messages.Update(ctx, *currentAssistant)
943+ OnRetry: func(err *fantasy.ProviderError, delay time.Duration) {
944+ slog.Warn("Provider request failed, retrying", providerRetryLogFields(err, delay)...)
946+ OnToolCall: func(tc fantasy.ToolCallContent) error {
947+ input, wasSanitized := sanitizeToolInput(tc.ToolName, tc.ToolCallID, tc.Input)
949+ sanitizedToolCalls[tc.ToolCallID] = true
951+ toolCall := message.ToolCall{
955+ ProviderExecuted: false,
958+ currentAssistant.AddToolCall(toolCall)
959+ // Use parent ctx instead of genCtx to ensure the update succeeds
960+ // even if the request is canceled mid-stream
961+ return a.messages.Update(ctx, *currentAssistant)
963+ OnToolResult: func(result fantasy.ToolResultContent) error {
964+ toolResult := a.convertToToolResult(result)
965+ if sanitizedToolCalls[result.ToolCallID] {
966+ toolResult.Content = "Tool call failed: arguments were not valid JSON. Please check your tool call format and try again."
967+ toolResult.IsError = true
969+ // Use parent ctx instead of genCtx to ensure the message is created
970+ // even if the request is canceled mid-stream
971+ _, createMsgErr := a.messages.Create(ctx, currentAssistant.SessionID, message.CreateMessageParams{
973+ Parts: []message.ContentPart{
979+ OnStepFinish: func(stepResult fantasy.StepResult) error {
980+ for _, w := range stepResult.Warnings {
981+ slog.Warn("Provider warning", "type", w.Type, "message", w.Message)
983+ finishReason := message.FinishReasonUnknown
984+ switch stepResult.FinishReason {
985+ case fantasy.FinishReasonLength:
986+ finishReason = message.FinishReasonMaxTokens
987+ case fantasy.FinishReasonStop:
988+ finishReason = message.FinishReasonEndTurn
989+ case fantasy.FinishReasonToolCalls:
990+ finishReason = message.FinishReasonToolUse
992+ // If a tool result halted the turn (e.g. a hook halt or a
993+ // permission denial), the step ends on FinishReasonToolCalls but
994+ // the model will not be called again. Treat it as the end of the
995+ // turn so the UI can render the assistant footer.
996+ if finishReason == message.FinishReasonToolUse {
997+ for _, tr := range stepResult.Content.ToolResults() {
999+ finishReason = message.FinishReasonEndTurn
1004+ currentAssistant.AddFinish(finishReason, "", "")
1006+ defer sessionLock.Unlock()
1008+ updatedSession, getSessionErr := a.sessions.Get(ctx, call.SessionID)
1009+ if getSessionErr != nil {
1010+ return getSessionErr
1012+ usage, estimated := fallbackStepUsage(stepMessages, stepResult)
1013+ a.updateSessionUsage(largeModel, &updatedSession, usage, a.openrouterCost(stepResult.ProviderMetadata), estimated)
1014+ extractHyperCredits(stepResult.ProviderMetadata)
1015+ _, sessionErr := a.sessions.Save(ctx, updatedSession)
1016+ if sessionErr != nil {
1019+ currentSession = updatedSession
1020+ return a.messages.Update(genCtx, *currentAssistant)
1022+ StopWhen: []fantasy.StopCondition{
1023+ func(_ []fantasy.StepResult) bool {
1024+ cw := int64(largeModel.CatwalkCfg.ContextWindow)
1025+ // If context window is unknown (0), skip auto-summarize
1026+ // to avoid immediately truncating custom/local models.
1030+ tokens := currentSession.CompletionTokens + currentSession.PromptTokens
1031+ remaining := cw - tokens
1032+ var threshold int64
1033+ if cw > largeContextWindowThreshold {
1034+ threshold = largeContextWindowBuffer
1036+ threshold = int64(float64(cw) * smallContextWindowRatio)
1038+ if (remaining <= threshold) && !a.disableAutoSummarize {
1039+ shouldSummarize = true
1044+ func(steps []fantasy.StepResult) bool {
1045+ return hasRepeatedToolCalls(steps, loopDetectionWindowSize, loopDetectionMaxRepeats)
1050+ a.eventPromptResponded(call.SessionID, time.Since(startTime).Truncate(time.Second))
1053+ isHyper := largeModel.ModelCfg.Provider == hyper.Name
1054+ isCancelErr := errors.Is(err, context.Canceled)
1055+ if currentAssistant == nil {
1056+ // Cancel-before-assistant-creation window: the run was
1057+ // canceled after activeRequests.Set but before PrepareStep
1058+ // created the assistant message. Without this, the turn
1059+ // would return with no FinishReasonCanceled marker and no
1060+ // user-visible record. The user message was already created
1061+ // above, so persistCanceledTurn only writes the assistant
1064+ if persistErr := a.persistCanceledTurn(ctx, call, userMsgCreated); persistErr != nil {
1065+ return nil, persistErr
1070+ // Persist final state with a context detached from the run
1071+ // context. The run context (ctx) is derived from the
1072+ // workspace context, which workspace shutdown cancels before
1073+ // agent goroutines finish; using ctx here would drop the
1074+ // final assistant state. WithoutCancel keeps the values
1075+ // (e.g. session ID) while ignoring cancellation, and a short
1076+ // timeout bounds the cleanup writes.
1077+ cleanupCtx, cleanupCancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
1078+ defer cleanupCancel()
1079+ // Ensure we finish thinking on error to close the reasoning state.
1080+ currentAssistant.FinishThinking()
1081+ toolCalls := currentAssistant.ToolCalls()
1082+ // INFO: we use the cleanup context here because the genCtx has been cancelled.
1083+ // Only load messages from the current assistant message onward — tool
1084+ // results for this turn's tool calls can only exist after it.
1085+ msgs, createErr := a.messages.ListAfter(cleanupCtx, currentAssistant.SessionID, currentAssistant.ID)
1086+ if createErr != nil {
1087+ return nil, createErr
1089+ for _, tc := range toolCalls {
1093+ currentAssistant.AddToolCall(tc)
1094+ updateErr := a.messages.Update(cleanupCtx, *currentAssistant)
1095+ if updateErr != nil {
1096+ return nil, updateErr
1101+ for _, msg := range msgs {
1102+ if msg.Role == message.Tool {
1103+ for _, tr := range msg.ToolResults() {
1104+ if tr.ToolCallID == tc.ID {
1117+ content := "There was an error while executing the tool"
1119+ content = "Error: user cancelled assistant tool calling"
1121+ toolResult := message.ToolResult{
1127+ _, createErr = a.messages.Create(cleanupCtx, currentAssistant.SessionID, message.CreateMessageParams{
1128+ Role: message.Tool,
1129+ Parts: []message.ContentPart{
1133+ if createErr != nil {
1134+ return nil, createErr
1137+ var fantasyErr *fantasy.Error
1138+ var providerErr *fantasy.ProviderError
1139+ const defaultTitle = "Provider Error"
1140+ linkStyle := lipgloss.NewStyle().Foreground(charmtone.Guac).Underline(true)
1142+ currentAssistant.AddFinish(message.FinishReasonCanceled, "User canceled request", "")
1143+ } else if isHyper && errors.As(err, &providerErr) && providerErr.StatusCode == http.StatusUnauthorized {
1144+ currentAssistant.AddFinish(message.FinishReasonError, "Unauthorized", `Please re-authenticate with Hyper. You can also run "crush auth" to re-authenticate.`)
1145+ } else if isHyper && errors.As(err, &providerErr) && providerErr.StatusCode == http.StatusPaymentRequired {
1146+ url := hyper.BaseURL()
1147+ link := linkStyle.Hyperlink(url, "id=hyper").Render(url)
1148+ currentAssistant.AddFinish(message.FinishReasonError, "No credits", "You're out of credits. Add more at "+link)
1149+ } else if errors.As(err, &providerErr) {
1150+ if providerErr.Message == "The requested model is not supported." {
1151+ url := "https://github.com/settings/copilot/features"
1152+ link := linkStyle.Hyperlink(url, "id=copilot").Render(url)
1153+ currentAssistant.AddFinish(
1154+ message.FinishReasonError,
1155+ "Copilot model not enabled",
1156+ fmt.Sprintf("%q is not enabled in Copilot. Go to the following page to enable it. Then, wait 5 minutes before trying again. %s", largeModel.CatwalkCfg.Name, link),
1159+ currentAssistant.AddFinish(message.FinishReasonError, cmp.Or(stringext.Capitalize(providerErr.Title), defaultTitle), providerErr.Message)
1161+ } else if errors.As(err, &fantasyErr) {
1162+ currentAssistant.AddFinish(message.FinishReasonError, cmp.Or(stringext.Capitalize(fantasyErr.Title), defaultTitle), fantasyErr.Message)
1164+ currentAssistant.AddFinish(message.FinishReasonError, defaultTitle, err.Error())
1166+ // Note: we use the cleanup context here because the genCtx has been
1168+ updateErr := a.messages.Update(cleanupCtx, *currentAssistant)
1169+ if updateErr != nil {
1170+ return nil, updateErr
1175+ if shouldSummarize {
1176+ a.activeRequests.Del(call.SessionID)
1177+ if summarizeErr := a.Summarize(genCtx, call.SessionID, call.ProviderOptions); summarizeErr != nil {
1178+ return nil, summarizeErr
1180+ // If the agent wasn't done...
1181+ if len(currentAssistant.ToolCalls()) > 0 {
1182+ existing, ok := a.messageQueue.Get(call.SessionID)
1184+ existing = []SessionAgentCall{}
1186+ call.Prompt = fmt.Sprintf("The previous session was interrupted because it got too long, the initial user request was: `%s`", call.Prompt)
1187+ existing = append(existing, call)
1188+ a.messageQueue.Set(call.SessionID, existing)
1192+ // Release active request before publishing the notification.
1193+ // TUI handlers poll IsSessionBusy() and only re-evaluate when a
1194+ // tea.Msg arrives, so the cleanup must precede the notify or
1195+ // subscribers see stale busy state at the moment of receipt.
1196+ a.activeRequests.Del(call.SessionID)
1199+ // Send notification that agent has finished its turn (skip for
1200+ // nested/non-interactive sessions).
1201+ if !call.NonInteractive && a.notify != nil {
1202+ a.notify.Publish(pubsub.CreatedEvent, notify.Notification{
1203+ SessionID: call.SessionID,
1204+ SessionTitle: currentSession.Title,
1205+ Type: notify.TypeAgentFinished,
1209+ // Hand off to the next queued prompt (if any) under dispatchMu so
1210+ // the transition from this finished run to the queued run is atomic
1211+ // against a concurrent Cancel. activeRequests for this session was
1212+ // just deleted above, so without the lock there is a window in
1213+ // which the session looks idle and a cancel becomes a no-op that
1214+ // fails to stop the queued prompt. Holding the lock lets us observe
1215+ // a pending cancel recorded against the session and drop the queue
1216+ // instead of running it, and (for the recursion) hand a fresh
1217+ // accept reservation to the dequeued call so acceptedRuns stays > 0
1218+ // across the recursive Run's own dispatch handoff — keeping the
1219+ // session observable to Cancel for the entire transition and
1220+ // closing the dequeue -> re-register window.
1221+ mu := a.sessionMu(call.SessionID)
1223+ queuedMessages, _ := a.messageQueue.Get(call.SessionID)
1224+ if mark, ok := a.cancelMark.Get(call.SessionID); ok && mark > 0 && len(queuedMessages) > 0 {
1225+ // A cancel was recorded for this session (e.g. it arrived while
1226+ // this run was active and follow-ups had been queued). Drop the
1227+ // queued prompts it covers (accept sequence at or below the
1228+ // mark, or untracked); keep any queued after the cancel (higher
1229+ // sequence) so they still run.
1230+ var kept []SessionAgentCall
1231+ var canceledRunIDDrops []SessionAgentCall
1232+ for _, q := range queuedMessages {
1233+ if q.acceptSeq == 0 || q.acceptSeq <= mark {
1235+ canceledRunIDDrops = append(canceledRunIDDrops, q)
1239+ kept = append(kept, q)
1241+ queuedMessages = kept
1242+ a.messageQueue.Set(call.SessionID, kept)
1243+ // A dropped prompt carrying a RunID must still publish its
1244+ // terminal cancelled RunComplete so a caller waiting on that
1245+ // RunID does not hang.
1246+ a.publishCanceledQueueDrops(canceledRunIDDrops)
1248+ if len(queuedMessages) == 0 {
1249+ // No queued work. Clear the cancel mark only when no accepted
1250+ // run remains in flight that it might still cover; otherwise a
1251+ // sibling prompt (sequence at or below the mark) waiting to
1252+ // enter Run would lose its cancellation. When accepted runs are
1253+ // gone, this also clears a stale mark so it can't catch a
1255+ a.messageQueue.Del(call.SessionID)
1256+ a.acceptedMu.Lock()
1257+ inFlight, _ := a.acceptedRuns.Get(call.SessionID)
1258+ a.acceptedMu.Unlock()
1260+ a.cancelMark.Del(call.SessionID)
1265+ // There are queued messages, restart the loop. Suppress the outer
1266+ // defer's emit: it would otherwise observe the recursive Run's retErr
1267+ // (named-return clobbering through the return below) against this
1268+ // turn's MessageID/Text and publish a mixed, racing event.
1269+ skipRunComplete = true
1270+ // Decide whether this turn still owes its own terminal RunComplete.
1271+ // Each submitted prompt with a RunID has its own lifecycle, so a turn
1272+ // that is finished and handing off to a *different* queued prompt must
1273+ // publish its own RunComplete here — leaving it to the recursive turn
1274+ // (which carries a different RunID) would hang a caller waiting on
1275+ // this turn's RunID. The exception is the summarize-continuation path,
1276+ // which re-queues this same call (same RunID) to resume after a
1277+ // summary; in that case the eventual terminal turn for this RunID
1278+ // publishes, so publishing now would double-emit.
1279+ outerOwesRunComplete := call.RunID != ""
1280+ if outerOwesRunComplete {
1281+ for _, q := range queuedMessages {
1282+ if q.RunID == call.RunID {
1283+ outerOwesRunComplete = false
1288+ firstQueuedMessage := queuedMessages[0]
1289+ a.messageQueue.Set(call.SessionID, queuedMessages[1:])
1290+ // Reserve a fresh accept for the dequeued prompt before dropping the
1291+ // lock so acceptedRuns > 0 across the handoff into the recursive
1292+ // Run. This closes the window between this dequeue and the recursive
1293+ // Run registering its activeRequests entry: a cancel arriving in
1294+ // that window now records a pending cancel (acceptedRuns > 0) that
1295+ // the recursive Run's accepted path observes as cancel-on-entry.
1296+ firstQueuedMessage.Accepted = a.BeginAccepted(call.SessionID)
1298+ if outerOwesRunComplete {
1299+ complete := notify.RunComplete{SessionID: call.SessionID, RunID: call.RunID}
1300+ if currentAssistant != nil {
1301+ complete.MessageID = currentAssistant.ID
1302+ complete.Text = currentAssistant.Content().String()
1304+ if ctx.Err() != nil {
1305+ complete.Cancelled = true
1307+ a.publishRunComplete(ctx, call, complete)
1309+ return a.Run(ctx, firstQueuedMessage)
1312+func (a *sessionAgent) Summarize(ctx context.Context, sessionID string, opts fantasy.ProviderOptions) error {
1313+ if a.IsSessionBusy(sessionID) {
1314+ return ErrSessionBusy
1317+ // Copy mutable fields under lock to avoid races with SetModels.
1318+ largeModel := a.largeModel.Get()
1319+ systemPromptPrefix := a.systemPromptPrefix.Get()
1321+ currentSession, err := a.sessions.Get(ctx, sessionID)
1323+ return fmt.Errorf("failed to get session: %w", err)
1325+ msgs, err := a.getSessionMessages(ctx, currentSession)
1329+ if len(msgs) == 0 {
1330+ // Nothing to summarize.
1334+ aiMsgs, _ := a.preparePrompt(msgs, largeModel.CatwalkCfg.SupportsImages)
1336+ genCtx, cancel := context.WithCancel(ctx)
1337+ a.activeRequests.Set(sessionID, cancel)
1338+ defer a.activeRequests.Del(sessionID)
1341+ if flushErr := a.messages.FlushAll(ctx); flushErr != nil {
1342+ slog.Error("Failed to flush pending message updates after summarize", "error", flushErr)
1346+ agent := fantasy.NewAgent(
1348+ fantasy.WithSystemPrompt(string(summaryPrompt)),
1349+ fantasy.WithUserAgent(userAgent),
1351+ summaryMessage, err := a.messages.Create(ctx, sessionID, message.CreateMessageParams{
1352+ Role: message.Assistant,
1353+ Model: largeModel.ModelCfg.Model,
1354+ Provider: largeModel.ModelCfg.Provider,
1355+ IsSummaryMessage: true,
1361+ summaryPromptText := buildSummaryPrompt(currentSession.Todos)
1363+ resp, err := agent.Stream(genCtx, fantasy.AgentStreamCall{
1364+ Prompt: summaryPromptText,
1366+ ProviderOptions: opts,
1367+ PrepareStep: func(callContext context.Context, options fantasy.PrepareStepFunctionOptions) (_ context.Context, prepared fantasy.PrepareStepResult, err error) {
1368+ prepared.Messages = options.Messages
1369+ if systemPromptPrefix != "" {
1370+ prepared.Messages = append([]fantasy.Message{fantasy.NewSystemMessage(systemPromptPrefix)}, prepared.Messages...)
1372+ return callContext, prepared, nil
1374+ OnReasoningDelta: func(id string, text string) error {
1375+ summaryMessage.AppendReasoningContent(text)
1376+ return a.messages.Update(genCtx, summaryMessage)
1378+ OnReasoningEnd: func(id string, reasoning fantasy.ReasoningContent) error {
1379+ // Handle anthropic signature.
1380+ if anthropicData, ok := reasoning.ProviderMetadata["anthropic"]; ok {
1381+ if signature, ok := anthropicData.(*anthropic.ReasoningOptionMetadata); ok && signature.Signature != "" {
1382+ summaryMessage.AppendReasoningSignature(signature.Signature)
1385+ summaryMessage.FinishThinking()
1386+ return a.messages.Update(genCtx, summaryMessage)
1388+ OnTextDelta: func(id, text string) error {
1389+ summaryMessage.AppendContent(text)
1390+ return a.messages.Update(genCtx, summaryMessage)
1394+ isCancelErr := errors.Is(err, context.Canceled)
1396+ // User cancelled summarize we need to remove the summary message.
1397+ deleteErr := a.messages.Delete(ctx, summaryMessage.ID)
1400+ // Mark the summary message as finished with an error so the UI
1402+ summaryMessage.AddFinish(message.FinishReasonError, "Summarization Error", err.Error())
1403+ if updateErr := a.messages.Update(ctx, summaryMessage); updateErr != nil {
1409+ summaryMessage.AddFinish(message.FinishReasonEndTurn, "", "")
1410+ err = a.messages.Update(genCtx, summaryMessage)
1415+ var openrouterCost *float64
1416+ for _, step := range resp.Steps {
1417+ stepCost := a.openrouterCost(step.ProviderMetadata)
1418+ if stepCost != nil {
1419+ newCost := *stepCost
1420+ if openrouterCost != nil {
1421+ newCost += *openrouterCost
1423+ openrouterCost = &newCost
1425+ extractHyperCredits(step.ProviderMetadata)
1428+ a.updateSessionUsage(largeModel, ¤tSession, resp.TotalUsage, openrouterCost, false)
1430+ // Just in case, get just the last usage info.
1431+ usage := resp.Response.Usage
1432+ currentSession.SummaryMessageID = summaryMessage.ID
1433+ currentSession.CompletionTokens = summaryCompletionTokens(usage, summaryMessage)
1434+ currentSession.PromptTokens = 0
1435+ currentSession.EstimatedUsage = usageIsZero(usage)
1436+ _, err = a.sessions.Save(genCtx, currentSession)
1441+ // Release the active request before processing queued messages so that
1442+ // Run() does not see the session as busy.
1443+ a.activeRequests.Del(sessionID)
1446+ // Process any messages that were queued while summarizing.
1447+ queuedMessages, ok := a.messageQueue.Get(sessionID)
1448+ if !ok || len(queuedMessages) == 0 {
1451+ firstQueuedMessage := queuedMessages[0]
1452+ a.messageQueue.Set(sessionID, queuedMessages[1:])
1453+ _, qErr := a.Run(ctx, firstQueuedMessage)
1457+// cacheControlOptions is computed once for the process lifetime: the env check
1458+// is constant and callers only read (never mutate) the returned map, so the
1459+// same shared value can be reused across the ~3 calls per step.
1460+var cacheControlOptions = sync.OnceValue(func() fantasy.ProviderOptions {
1461+ if t, _ := strconv.ParseBool(os.Getenv("CRUSH_DISABLE_ANTHROPIC_CACHE")); t {
1462+ return fantasy.ProviderOptions{}
1464+ return fantasy.ProviderOptions{
1465+ anthropic.Name: &anthropic.ProviderCacheControlOptions{
1466+ CacheControl: anthropic.CacheControl{Type: "ephemeral"},
1468+ bedrock.Name: &anthropic.ProviderCacheControlOptions{
1469+ CacheControl: anthropic.CacheControl{Type: "ephemeral"},
1471+ vercel.Name: &anthropic.ProviderCacheControlOptions{
1472+ CacheControl: anthropic.CacheControl{Type: "ephemeral"},
1477+func (a *sessionAgent) getCacheControlOptions() fantasy.ProviderOptions {
1478+ return cacheControlOptions()
1481+func (a *sessionAgent) createUserMessage(ctx context.Context, call SessionAgentCall) (message.Message, error) {
1482+ parts := []message.ContentPart{message.TextContent{Text: call.Prompt}}
1483+ var attachmentParts []message.ContentPart
1484+ for _, attachment := range call.Attachments {
1485+ attachmentParts = append(attachmentParts, message.BinaryContent{Path: attachment.FilePath, MIMEType: attachment.MimeType, Data: attachment.Content})
1487+ parts = append(parts, attachmentParts...)
1488+ msg, err := a.messages.Create(ctx, call.SessionID, message.CreateMessageParams{
1489+ Role: message.User,
1493+ return message.Message{}, fmt.Errorf("failed to create user message: %w", err)
1498+func (a *sessionAgent) preparePrompt(msgs []message.Message, supportsImages bool, attachments ...message.Attachment) ([]fantasy.Message, []fantasy.FilePart) {
1499+ history := make([]fantasy.Message, 0, len(msgs)+1)
1501+ history = append(history, fantasy.NewUserMessage(
1503+ "<system_reminder>%s</system_reminder>",
1504+ `This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.
1505+If you are working on tasks that would benefit from a todo list please use the "todos" tool to create one.
1506+If not, please feel free to ignore. Again do not mention this message to the user.`,
1510+ // Collect all tool call IDs present in assistant messages and all tool
1511+ // result IDs present in tool messages. This lets us detect both orphaned
1512+ // tool results (result without a call) and orphaned tool calls (call
1513+ // without a result).
1514+ knownToolCallIDs := make(map[string]struct{})
1515+ knownToolResultIDs := make(map[string]struct{})
1516+ for _, m := range msgs {
1518+ case message.Assistant:
1519+ for _, tc := range m.ToolCalls() {
1520+ knownToolCallIDs[tc.ID] = struct{}{}
1523+ for _, tr := range m.ToolResults() {
1524+ knownToolResultIDs[tr.ToolCallID] = struct{}{}
1529+ for _, m := range msgs {
1530+ if len(m.Parts) == 0 {
1533+ // Assistant message without content or tool calls (cancelled before it returned anything).
1534+ if m.Role == message.Assistant && len(m.ToolCalls()) == 0 && m.Content().Text == "" && m.ReasoningContent().String() == "" {
1537+ if m.Role == message.Tool {
1538+ if msg, ok := filterOrphanedToolResults(m, knownToolCallIDs); ok {
1539+ history = append(history, msg)
1543+ aiMsgs := m.ToAIMessage()
1544+ if !supportsImages {
1545+ for i := range aiMsgs {
1546+ if aiMsgs[i].Role == fantasy.MessageRoleUser {
1547+ aiMsgs[i].Content = filterFileParts(aiMsgs[i].Content)
1551+ history = append(history, aiMsgs...)
1553+ if m.Role == message.Assistant {
1554+ if msg, ok := syntheticToolResultsForOrphanedCalls(m, knownToolResultIDs); ok {
1555+ history = append(history, msg)
1560+ var files []fantasy.FilePart
1561+ for _, attachment := range attachments {
1562+ if attachment.IsText() {
1565+ files = append(files, fantasy.FilePart{
1566+ Filename: attachment.FileName,
1567+ Data: attachment.Content,
1568+ MediaType: attachment.MimeType,
1572+ return history, files
1575+// filterFileParts removes fantasy.FilePart entries from a slice of message
1576+// parts. Used to strip image attachments from historical user messages when
1577+// the current model does not support them.
1578+func filterFileParts(parts []fantasy.MessagePart) []fantasy.MessagePart {
1579+ filtered := make([]fantasy.MessagePart, 0, len(parts))
1580+ for _, part := range parts {
1581+ if _, ok := fantasy.AsMessagePart[fantasy.FilePart](part); ok {
1584+ filtered = append(filtered, part)
1589+// filterOrphanedToolResults converts a tool message to a fantasy.Message,
1590+// dropping any tool result parts whose tool_call_id has no matching tool call
1591+// in the known set. An orphaned result causes API validation to fail on every
1592+// subsequent turn, permanently locking the session. Returns the filtered
1593+// message and true if at least one valid part remains.
1594+func filterOrphanedToolResults(m message.Message, knownToolCallIDs map[string]struct{}) (fantasy.Message, bool) {
1595+ aiMsgs := m.ToAIMessage()
1596+ if len(aiMsgs) == 0 {
1597+ return fantasy.Message{}, false
1599+ validParts := make([]fantasy.MessagePart, 0, len(aiMsgs[0].Content))
1600+ for _, part := range aiMsgs[0].Content {
1601+ tr, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](part)
1603+ validParts = append(validParts, part)
1606+ if _, known := knownToolCallIDs[tr.ToolCallID]; known {
1607+ validParts = append(validParts, part)
1610+ "Dropping orphaned tool result with no matching tool call",
1611+ "tool_call_id", tr.ToolCallID,
1615+ if len(validParts) == 0 {
1616+ return fantasy.Message{}, false
1619+ msg.Content = validParts
1623+// syntheticToolResultsForOrphanedCalls returns a tool message containing
1624+// synthetic tool results for any tool calls in the assistant message that
1625+// have no matching result in knownToolResultIDs. LLM APIs require every
1626+// tool_use to be immediately followed by a tool_result; an interrupted
1627+// session can leave orphaned tool_use blocks that permanently lock the
1628+// conversation. Returns the message and true if any synthetic results were
1630+func syntheticToolResultsForOrphanedCalls(m message.Message, knownToolResultIDs map[string]struct{}) (fantasy.Message, bool) {
1631+ syntheticParts := make([]fantasy.MessagePart, 0, len(m.ToolCalls()))
1632+ for _, tc := range m.ToolCalls() {
1633+ if _, hasResult := knownToolResultIDs[tc.ID]; hasResult {
1637+ "Injecting synthetic tool result for orphaned tool call",
1638+ "tool_call_id", tc.ID,
1639+ "tool_name", tc.Name,
1641+ syntheticParts = append(syntheticParts, fantasy.ToolResultPart{
1643+ Output: fantasy.ToolResultOutputContentError{
1644+ Error: errors.New("tool call was interrupted and did not produce a result, you may retry this call if the result is still needed"),
1648+ if len(syntheticParts) == 0 {
1649+ return fantasy.Message{}, false
1651+ return fantasy.Message{
1652+ Role: fantasy.MessageRoleTool,
1653+ Content: syntheticParts,
1657+func (a *sessionAgent) getSessionMessages(ctx context.Context, session session.Session) ([]message.Message, error) {
1658+ if session.SummaryMessageID != "" {
1659+ msgs, err := a.messages.ListAfter(ctx, session.ID, session.SummaryMessageID)
1661+ return nil, fmt.Errorf("failed to list messages after summary: %w", err)
1664+ msgs[0].Role = message.User
1669+ msgs, err := a.messages.List(ctx, session.ID)
1671+ return nil, fmt.Errorf("failed to list messages: %w", err)
1676+// hasUserTextMessage reports whether any user message in msgs contains
1677+// text content (as opposed to only shell commands or other non-text parts).
1678+func hasUserTextMessage(msgs []message.Message) bool {
1679+ for _, msg := range msgs {
1680+ if msg.Role != message.User {
1683+ for _, part := range msg.Parts {
1684+ if tc, ok := part.(message.TextContent); ok && tc.Text != "" {
1692+// GenerateTitle generates a session title based on the initial prompt.
1693+func (a *sessionAgent) GenerateTitle(ctx context.Context, sessionID string, userPrompt string) {
1694+ if userPrompt == "" {
1698+ // Ensure the session always gets a title even if every path below
1699+ // fails or the context is cancelled before we finish.
1700+ var titleSaved bool
1703+ fallbackCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
1705+ if err := a.sessions.Rename(fallbackCtx, sessionID, DefaultSessionName); err != nil {
1706+ slog.Error("Failed to save fallback session title", "error", err)
1711+ smallModel := a.smallModel.Get()
1712+ largeModel := a.largeModel.Get()
1713+ systemPromptPrefix := a.systemPromptPrefix.Get()
1715+ newAgent := func(m fantasy.LanguageModel, p []byte, tok int64) fantasy.Agent {
1716+ return fantasy.NewAgent(
1718+ fantasy.WithSystemPrompt(string(p)+"\n /no_think"),
1719+ fantasy.WithMaxOutputTokens(tok),
1720+ fantasy.WithUserAgent(userAgent),
1724+ streamCall := fantasy.AgentStreamCall{
1725+ Prompt: fmt.Sprintf("Generate a concise title for the following content:\n\n%s\n <think>\n\n</think>", userPrompt),
1726+ PrepareStep: func(callCtx context.Context, opts fantasy.PrepareStepFunctionOptions) (_ context.Context, prepared fantasy.PrepareStepResult, err error) {
1727+ prepared.Messages = opts.Messages
1728+ if systemPromptPrefix != "" {
1729+ prepared.Messages = append([]fantasy.Message{
1730+ fantasy.NewSystemMessage(systemPromptPrefix),
1731+ }, prepared.Messages...)
1733+ return callCtx, prepared, nil
1737+ type modelAttempt struct {
1741+ attempts := []modelAttempt{
1742+ {"small", smallModel},
1743+ {"large", largeModel},
1746+ var resp *fantasy.AgentResult
1750+ for _, attempt := range attempts {
1752+ if attempt.model.CatwalkCfg.CanReason {
1753+ tok = attempt.model.CatwalkCfg.DefaultMaxTokens
1755+ agent := newAgent(attempt.model.Model, titlePrompt, tok)
1756+ resp, err = agent.Stream(ctx, streamCall)
1757+ if err == nil && resp.Response.FinishReason != fantasy.FinishReasonLength {
1758+ model = attempt.model
1759+ slog.Debug("Generated title with " + attempt.name + " model")
1764+ slog.Error("Error generating title with "+attempt.name+" model; trying next", "err", err)
1766+ slog.Error("Title generation hit token limit with " + attempt.name + " model; trying next")
1770+ // The deferred fallback will save the default session name.
1776+ title = strings.ReplaceAll(resp.Response.Content.Text(), "\n", " ")
1778+ // Remove thinking tags if present.
1779+ title = thinkTagRegex.ReplaceAllString(title, "")
1780+ title = orphanThinkTagRegex.ReplaceAllString(title, "")
1782+ title = strings.TrimSpace(title)
1784+ // LLM returned empty content. Use the prompt itself as a
1785+ // fallback title, truncated to 50 chars, before resorting to
1786+ // the generic default.
1787+ fallback := strings.ReplaceAll(userPrompt, "\n", " ")
1788+ fallback = strings.TrimSpace(fallback)
1789+ if len(fallback) > 50 {
1790+ fallback = ansi.Truncate(fallback, 50, "…")
1792+ title = cmp.Or(fallback, DefaultSessionName)
1795+ // Calculate usage and cost.
1796+ var openrouterCost *float64
1797+ for _, step := range resp.Steps {
1798+ stepCost := a.openrouterCost(step.ProviderMetadata)
1799+ if stepCost != nil {
1800+ newCost := *stepCost
1801+ if openrouterCost != nil {
1802+ newCost += *openrouterCost
1804+ openrouterCost = &newCost
1806+ extractHyperCredits(step.ProviderMetadata)
1809+ modelConfig := model.CatwalkCfg
1810+ cost := modelConfig.CostPer1MInCached/1e6*float64(resp.TotalUsage.CacheCreationTokens) +
1811+ modelConfig.CostPer1MOutCached/1e6*float64(resp.TotalUsage.CacheReadTokens) +
1812+ modelConfig.CostPer1MIn/1e6*float64(resp.TotalUsage.InputTokens) +
1813+ modelConfig.CostPer1MOut/1e6*float64(resp.TotalUsage.OutputTokens)
1815+ // Use override cost if available (e.g., from OpenRouter).
1816+ if openrouterCost != nil {
1817+ cost = *openrouterCost
1820+ // Skip cost accumulation
1821+ if model.FlatRate {
1825+ promptTokens := resp.TotalUsage.InputTokens + resp.TotalUsage.CacheCreationTokens
1826+ completionTokens := resp.TotalUsage.OutputTokens
1828+ // Atomically update only title and usage fields to avoid overriding other
1829+ // concurrent session updates.
1830+ saveErr := a.sessions.UpdateTitleAndUsage(ctx, sessionID, title, promptTokens, completionTokens, cost)
1831+ if saveErr != nil {
1832+ slog.Error("Failed to save session title and usage", "error", saveErr)
1838+func (a *sessionAgent) openrouterCost(metadata fantasy.ProviderMetadata) *float64 {
1839+ openrouterMetadata, ok := metadata[openrouter.Name]
1844+ opts, ok := openrouterMetadata.(*openrouter.ProviderMetadata)
1848+ return &opts.Usage.Cost
1851+// extractHyperCredits reads usage.remaining.hypercredits from OpenAI
1852+// provider metadata and stores it for the next FetchCredits call.
1853+func extractHyperCredits(metadata fantasy.ProviderMetadata) {
1854+ openaiMeta, ok := metadata[openai.Name]
1858+ pm, ok := openaiMeta.(*openai.ProviderMetadata)
1862+ var remaining struct {
1863+ Hypercredits float64 `json:"hypercredits"`
1865+ if pm.ExtraField("remaining", &remaining) && remaining.Hypercredits > 0 {
1866+ hyper.SetBalance(int(math.Round(remaining.Hypercredits)))
1870+func (a *sessionAgent) updateSessionUsage(model Model, session *session.Session, usage fantasy.Usage, overrideCost *float64, estimated bool) {
1871+ if !usageIsZero(usage) {
1872+ session.EstimatedUsage = estimated
1875+ modelConfig := model.CatwalkCfg
1876+ cost := modelConfig.CostPer1MInCached/1e6*float64(usage.CacheCreationTokens) +
1877+ modelConfig.CostPer1MOutCached/1e6*float64(usage.CacheReadTokens) +
1878+ modelConfig.CostPer1MIn/1e6*float64(usage.InputTokens) +
1879+ modelConfig.CostPer1MOut/1e6*float64(usage.OutputTokens)
1882+ a.eventTokensUsed(session.ID, model, usage, cost)
1888+ // Use override cost if available (e.g., from OpenRouter).
1889+ if overrideCost != nil {
1890+ cost = *overrideCost
1893+ // Skip cost accumulation
1894+ if model.FlatRate {
1899+ session.Cost += cost
1900+ updateSessionTokenCounters(session, usage)
1903+func updateSessionTokenCounters(session *session.Session, usage fantasy.Usage) {
1904+ if usage.OutputTokens != 0 {
1905+ session.CompletionTokens = usage.OutputTokens
1907+ if promptTokens := usage.InputTokens + usage.CacheReadTokens; promptTokens != 0 {
1908+ session.PromptTokens = promptTokens
1912+func summaryCompletionTokens(usage fantasy.Usage, summaryMessage message.Message) int64 {
1913+ if usage.OutputTokens != 0 {
1914+ return usage.OutputTokens
1916+ return approxTokenCount(summaryMessage.Content().Text) + approxTokenCount(summaryMessage.ReasoningContent().String())
1919+func (a *sessionAgent) Cancel(sessionID string) {
1920+ // Serialize against the dispatch handoff in Run so the accepted ->
1921+ // (cancel-on-entry | queued | active) transition is atomic against
1922+ // this cancel. Every cancel observes at least one of: an active
1923+ // request, an accepted run (recorded as a pending cancel), or a
1924+ // queue entry it then clears. If none of those hold, an idle Escape
1925+ // is a true no-op and must not poison the next prompt.
1926+ mu := a.sessionMu(sessionID)
1930+ // Cancel regular requests. Don't use Take() here - we need the entry to
1931+ // remain in activeRequests so IsBusy() returns true until the goroutine
1932+ // fully completes (including error handling that may access the DB).
1933+ // The defer in processRequest will clean up the entry.
1934+ if cancel, ok := a.activeRequests.Get(sessionID); ok && cancel != nil {
1935+ slog.Debug("Request cancellation initiated", "session_id", sessionID)
1939+ // Also check for summarize requests.
1940+ if cancel, ok := a.activeRequests.Get(sessionID + "-summarize"); ok && cancel != nil {
1941+ slog.Debug("Summarize cancellation initiated", "session_id", sessionID)
1945+ // Record a pending cancel only when a dispatched-but-not-yet-active
1946+ // run exists. This catches runs still in the goroutine scheduler or
1947+ // about to enter Run's busy-queue branch, while leaving an idle
1948+ // session untouched. Active and accepted are not mutually exclusive:
1949+ // when a run is active and a follow-up has been accepted, both the
1950+ // cancel above and this pending record fire.
1952+ // Raise the session's cancel mark to the latest accept sequence
1953+ // assigned so far. Every prompt currently accepted-but-not-yet-
1954+ // active has a sequence at or below that value, so one cancel covers
1955+ // all of them; a prompt accepted after this cancel gets a strictly
1956+ // higher sequence and is never poisoned. Using max keeps repeated
1957+ // cancels idempotent while the same prompts are in flight and lets a
1958+ // later cancel extend coverage to prompts accepted since.
1959+ a.acceptedMu.Lock()
1960+ count, ok := a.acceptedRuns.Get(sessionID)
1961+ mark := a.acceptSeqGen
1962+ a.acceptedMu.Unlock()
1963+ if ok && count > 0 {
1964+ slog.Debug("Recording cancel mark for accepted runs", "session_id", sessionID, "count", count, "mark", mark)
1965+ existing, _ := a.cancelMark.Get(sessionID)
1966+ a.cancelMark.Set(sessionID, max(existing, mark))
1969+ if a.QueuedPrompts(sessionID) > 0 {
1970+ slog.Debug("Clearing queued prompts", "session_id", sessionID)
1971+ a.clearQueueAndNotify(sessionID)
1975+func (a *sessionAgent) ClearQueue(sessionID string) {
1976+ if a.QueuedPrompts(sessionID) > 0 {
1977+ slog.Debug("Clearing queued prompts", "session_id", sessionID)
1978+ a.clearQueueAndNotify(sessionID)
1982+func (a *sessionAgent) CancelAll() {
1986+ for key := range a.activeRequests.Seq2() {
1987+ a.Cancel(key) // key is sessionID
1990+ timeout := time.After(5 * time.Second)
1996+ time.Sleep(200 * time.Millisecond)
2001+func (a *sessionAgent) IsBusy() bool {
2002+ // activeRequests only ever holds non-nil cancel funcs (Set with a
2003+ // real func, removed via Del), so a length check is exact — and it
2004+ // avoids cloning the whole map, which Seq() does on every call.
2005+ return a.activeRequests.Len() > 0
2008+func (a *sessionAgent) IsSessionBusy(sessionID string) bool {
2009+ _, busy := a.activeRequests.Get(sessionID)
2013+func (a *sessionAgent) QueuedPrompts(sessionID string) int {
2014+ l, ok := a.messageQueue.Get(sessionID)
2021+func (a *sessionAgent) QueuedPromptsList(sessionID string) []string {
2022+ l, ok := a.messageQueue.Get(sessionID)
2026+ prompts := make([]string, len(l))
2027+ for i, call := range l {
2028+ prompts[i] = call.Prompt
2033+func (a *sessionAgent) SetModels(large Model, small Model) {
2034+ a.largeModel.Set(large)
2035+ a.smallModel.Set(small)
2038+func (a *sessionAgent) SetTools(tools []fantasy.AgentTool) {
2039+ a.tools.SetSlice(tools)
2043+func (a *sessionAgent) SetSystemPrompt(systemPrompt string) {
2044+ a.systemPrompt.Set(systemPrompt)
2047+func (a *sessionAgent) Model() Model {
2048+ return a.largeModel.Get()
2051+// convertToToolResult converts a fantasy tool result to a message tool result.
2052+func (a *sessionAgent) convertToToolResult(result fantasy.ToolResultContent) message.ToolResult {
2053+ baseResult := message.ToolResult{
2054+ ToolCallID: result.ToolCallID,
2055+ Name: result.ToolName,
2056+ Metadata: result.ClientMetadata,
2059+ switch result.Result.GetType() {
2060+ case fantasy.ToolResultContentTypeText:
2061+ if r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](result.Result); ok {
2062+ baseResult.Content = r.Text
2064+ case fantasy.ToolResultContentTypeError:
2065+ if r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](result.Result); ok {
2066+ baseResult.Content = r.Error.Error()
2067+ baseResult.IsError = true
2069+ case fantasy.ToolResultContentTypeMedia:
2070+ if r, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentMedia](result.Result); ok {
2071+ if !stringext.IsValidBase64(r.Data) {
2073+ "Tool returned media with invalid base64 data, discarding image",
2074+ "tool", result.ToolName,
2075+ "tool_call_id", result.ToolCallID,
2077+ baseResult.Content = "Tool returned image data with invalid encoding"
2078+ baseResult.IsError = true
2082+ content = fmt.Sprintf("Loaded %s content", r.MediaType)
2084+ baseResult.Content = content
2085+ baseResult.Data = r.Data
2086+ baseResult.MIMEType = r.MediaType
2094+// workaroundProviderMediaLimitations converts media content in tool results to
2095+// user messages for providers that don't natively support images in tool results.
2097+// Problem: OpenAI, Google, OpenRouter, and other OpenAI-compatible providers
2098+// don't support sending images/media in tool result messages - they only accept
2099+// text in tool results. However, they DO support images in user messages.
2101+// If we send media in tool results to these providers, the API returns an error.
2103+// Solution: For these providers, we:
2104+// 1. Replace the media in the tool result with a text placeholder
2105+// 2. Inject a user message immediately after with the image as a file attachment
2106+// 3. This maintains the tool execution flow while working around API limitations
2108+// Anthropic and Bedrock support images natively in tool results, so we skip
2109+// this workaround for them.
2111+// Example transformation:
2113+// BEFORE: [tool result: image data]
2114+// AFTER: [tool result: "Image loaded - see attached"], [user: image attachment]
2115+func (a *sessionAgent) workaroundProviderMediaLimitations(messages []fantasy.Message, largeModel Model) []fantasy.Message {
2116+ providerSupportsMedia := largeModel.ModelCfg.Provider == string(catwalk.InferenceProviderAnthropic) ||
2117+ largeModel.ModelCfg.Provider == string(catwalk.InferenceProviderBedrock) ||
2118+ largeModel.ModelCfg.Provider == string(catwalk.InferenceProviderBedrockEurope)
2120+ if providerSupportsMedia {
2124+ supportsImages := largeModel.CatwalkCfg.SupportsImages
2126+ convertedMessages := make([]fantasy.Message, 0, len(messages))
2128+ for _, msg := range messages {
2129+ if msg.Role != fantasy.MessageRoleTool {
2130+ convertedMessages = append(convertedMessages, msg)
2134+ textParts := make([]fantasy.MessagePart, 0, len(msg.Content))
2135+ var mediaFiles []fantasy.FilePart
2137+ for _, part := range msg.Content {
2138+ toolResult, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](part)
2140+ textParts = append(textParts, part)
2144+ if media, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentMedia](toolResult.Output); ok {
2145+ if !supportsImages {
2146+ // Model cannot process images. Replace with a text
2147+ // placeholder and skip creating a synthetic user
2148+ // message with FilePart, which would brick the
2149+ // session on text-only models.
2150+ textParts = append(textParts, fantasy.ToolResultPart{
2151+ ToolCallID: toolResult.ToolCallID,
2152+ Output: fantasy.ToolResultOutputContentText{
2153+ Text: "[Image/media content not supported by this model]",
2155+ ProviderOptions: toolResult.ProviderOptions,
2160+ decoded, err := base64.StdEncoding.DecodeString(media.Data)
2162+ slog.Warn("Failed to decode media data", "error", err)
2163+ textParts = append(textParts, part)
2167+ mediaFiles = append(mediaFiles, fantasy.FilePart{
2169+ MediaType: media.MediaType,
2170+ Filename: fmt.Sprintf("tool-result-%s", toolResult.ToolCallID),
2173+ textParts = append(textParts, fantasy.ToolResultPart{
2174+ ToolCallID: toolResult.ToolCallID,
2175+ Output: fantasy.ToolResultOutputContentText{
2176+ Text: "[Image/media content loaded - see attached file]",
2178+ ProviderOptions: toolResult.ProviderOptions,
2181+ textParts = append(textParts, part)
2185+ convertedMessages = append(convertedMessages, fantasy.Message{
2186+ Role: fantasy.MessageRoleTool,
2187+ Content: textParts,
2190+ if len(mediaFiles) > 0 {
2191+ convertedMessages = append(convertedMessages, fantasy.NewUserMessage(
2192+ "Here is the media content from the tool result:",
2198+ return convertedMessages
2201+// buildSummaryPrompt constructs the prompt text for session summarization.
2202+func buildSummaryPrompt(todos []session.Todo) string {
2203+ var sb strings.Builder
2204+ sb.WriteString("Provide a detailed summary of our conversation above.")
2205+ if len(todos) > 0 {
2206+ sb.WriteString("\n\n## Current Todo List\n\n")
2207+ for _, t := range todos {
2208+ fmt.Fprintf(&sb, "- [%s] %s\n", t.Status, t.Content)
2210+ sb.WriteString("\nInclude these tasks and their statuses in your summary. ")
2211+ sb.WriteString("Instruct the resuming assistant to use the `todos` tool to continue tracking progress on these tasks.")
2216+func providerRetryLogFields(err *fantasy.ProviderError, delay time.Duration) []any {
2218+ "retry_delay", delay.String(),
2223+ fields = append(fields, "status_code", err.StatusCode)
2224+ if err.Title != "" {
2225+ fields = append(fields, "title", err.Title)
2227+ if err.Message != "" {
2228+ fields = append(fields, "message", err.Message)
2233+// sanitizeToolInput validates tool call JSON from the provider.
2234+// Malformed input is replaced with an empty object to prevent
2235+// stuck conversations from truncated or malformed model output.
2236+// The second return value indicates whether sanitization occurred.
2237+func sanitizeToolInput(toolName, toolCallID, input string) (string, bool) {
2238+ if !json.Valid([]byte(input)) {
2240+ "Malformed tool call JSON from provider, replacing with empty object",
2243+ "input_len", len(input),
2247+ return input, false
internal/agent/agent_test.gonew file+1015
@@ -0,0 +1,1015 @@
14+ "charm.land/catwalk/pkg/catwalk"
17+ "github.com/charmbracelet/crush/internal/agent/tools"
18+ "github.com/charmbracelet/crush/internal/config"
19+ "github.com/charmbracelet/crush/internal/message"
20+ "github.com/charmbracelet/crush/internal/session"
21+ "github.com/stretchr/testify/assert"
22+ "github.com/stretchr/testify/require"
24+ _ "github.com/joho/godotenv/autoload"
27+func TestMain(m *testing.M) {
28+ slog.SetLogLoggerLevel(slog.LevelError)
32+var modelPairs = []modelPair{
33+ {"glm-5.1", hyperBuilder("glm-5.1"), hyperBuilder("gpt-oss-120b")},
36+func getModels(t *testing.T, r *vcr.Recorder, pair modelPair) (fantasy.LanguageModel, fantasy.LanguageModel) {
37+ large, err := pair.largeModel(t, r)
38+ require.NoError(t, err)
39+ small, err := pair.smallModel(t, r)
40+ require.NoError(t, err)
44+func setupAgent(t *testing.T, pair modelPair) (SessionAgent, fakeEnv) {
45+ r := vcr.NewRecorder(t)
46+ large, small := getModels(t, r, pair)
49+ createSimpleGoProject(t, env.workingDir)
50+ agent, err := coderAgent(r, env, large, small)
51+ require.NoError(t, err)
55+func TestCoderAgent(t *testing.T) {
56+ if runtime.GOOS == "windows" {
57+ t.Skip("skipping on windows for now")
60+ for _, pair := range modelPairs {
61+ t.Run(pair.name, func(t *testing.T) {
62+ t.Run("simple test", func(t *testing.T) {
63+ agent, env := setupAgent(t, pair)
65+ session, err := env.sessions.Create(t.Context(), "New Session")
66+ require.NoError(t, err)
68+ res, err := agent.Run(t.Context(), SessionAgentCall{
70+ SessionID: session.ID,
71+ MaxOutputTokens: 10000,
73+ require.NoError(t, err)
74+ assert.NotNil(t, res)
76+ msgs, err := env.messages.List(t.Context(), session.ID)
77+ require.NoError(t, err)
78+ // Should have the agent and user message
79+ assert.Equal(t, len(msgs), 2)
81+ t.Run("read a file", func(t *testing.T) {
82+ agent, env := setupAgent(t, pair)
84+ session, err := env.sessions.Create(t.Context(), "New Session")
85+ require.NoError(t, err)
86+ res, err := agent.Run(t.Context(), SessionAgentCall{
87+ Prompt: "Read the go mod",
88+ SessionID: session.ID,
89+ MaxOutputTokens: 10000,
92+ require.NoError(t, err)
93+ assert.NotNil(t, res)
95+ msgs, err := env.messages.List(t.Context(), session.ID)
96+ require.NoError(t, err)
100+ for _, msg := range msgs {
101+ if msg.Role == message.Assistant {
102+ for _, tc := range msg.ToolCalls() {
103+ if tc.Name == tools.ViewToolName {
108+ if msg.Role == message.Tool {
109+ for _, tr := range msg.ToolResults() {
110+ if tr.ToolCallID == tcID {
111+ if strings.Contains(tr.Content, "module example.com/testproject") {
119+ require.True(t, foundFile)
121+ t.Run("update a file", func(t *testing.T) {
122+ agent, env := setupAgent(t, pair)
124+ session, err := env.sessions.Create(t.Context(), "New Session")
125+ require.NoError(t, err)
127+ res, err := agent.Run(t.Context(), SessionAgentCall{
128+ Prompt: "update the main.go file by changing the print to say hello from crush",
129+ SessionID: session.ID,
130+ MaxOutputTokens: 10000,
132+ require.NoError(t, err)
133+ assert.NotNil(t, res)
135+ msgs, err := env.messages.List(t.Context(), session.ID)
136+ require.NoError(t, err)
140+ var readTCID, writeTCID string
142+ for _, msg := range msgs {
143+ if msg.Role == message.Assistant {
144+ for _, tc := range msg.ToolCalls() {
145+ if tc.Name == tools.ViewToolName {
148+ if tc.Name == tools.EditToolName || tc.Name == tools.WriteToolName {
153+ if msg.Role == message.Tool {
154+ for _, tr := range msg.ToolResults() {
155+ if tr.ToolCallID == readTCID {
158+ if tr.ToolCallID == writeTCID {
165+ require.True(t, foundRead, "Expected to find a read operation")
166+ require.True(t, foundWrite, "Expected to find a write operation")
168+ mainGoPath := filepath.Join(env.workingDir, "main.go")
169+ content, err := os.ReadFile(mainGoPath)
170+ require.NoError(t, err)
171+ require.Contains(t, strings.ToLower(string(content)), "hello from crush")
173+ t.Run("bash tool", func(t *testing.T) {
174+ agent, env := setupAgent(t, pair)
176+ session, err := env.sessions.Create(t.Context(), "New Session")
177+ require.NoError(t, err)
179+ res, err := agent.Run(t.Context(), SessionAgentCall{
180+ Prompt: "use bash to create a file named test.txt with content 'hello bash'. do not print its timestamp",
181+ SessionID: session.ID,
182+ MaxOutputTokens: 10000,
184+ require.NoError(t, err)
185+ assert.NotNil(t, res)
187+ msgs, err := env.messages.List(t.Context(), session.ID)
188+ require.NoError(t, err)
193+ for _, msg := range msgs {
194+ if msg.Role == message.Assistant {
195+ for _, tc := range msg.ToolCalls() {
196+ if tc.Name == tools.BashToolName {
201+ if msg.Role == message.Tool {
202+ for _, tr := range msg.ToolResults() {
203+ if tr.ToolCallID == bashTCID {
210+ require.True(t, foundBash, "Expected to find a bash operation")
212+ testFilePath := filepath.Join(env.workingDir, "test.txt")
213+ content, err := os.ReadFile(testFilePath)
214+ require.NoError(t, err)
215+ require.Contains(t, string(content), "hello bash")
217+ t.Run("download tool", func(t *testing.T) {
218+ agent, env := setupAgent(t, pair)
220+ session, err := env.sessions.Create(t.Context(), "New Session")
221+ require.NoError(t, err)
223+ res, err := agent.Run(t.Context(), SessionAgentCall{
224+ Prompt: "download the file from https://example-files.online-convert.com/document/txt/example.txt and save it as example.txt",
225+ SessionID: session.ID,
226+ MaxOutputTokens: 10000,
228+ require.NoError(t, err)
229+ assert.NotNil(t, res)
231+ msgs, err := env.messages.List(t.Context(), session.ID)
232+ require.NoError(t, err)
234+ foundDownload := false
235+ var downloadTCID string
237+ for _, msg := range msgs {
238+ if msg.Role == message.Assistant {
239+ for _, tc := range msg.ToolCalls() {
240+ if tc.Name == tools.DownloadToolName {
241+ downloadTCID = tc.ID
245+ if msg.Role == message.Tool {
246+ for _, tr := range msg.ToolResults() {
247+ if tr.ToolCallID == downloadTCID {
248+ foundDownload = true
254+ require.True(t, foundDownload, "Expected to find a download operation")
256+ examplePath := filepath.Join(env.workingDir, "example.txt")
257+ _, err = os.Stat(examplePath)
258+ require.NoError(t, err, "Expected example.txt file to exist")
260+ t.Run("fetch tool", func(t *testing.T) {
261+ agent, env := setupAgent(t, pair)
263+ session, err := env.sessions.Create(t.Context(), "New Session")
264+ require.NoError(t, err)
266+ res, err := agent.Run(t.Context(), SessionAgentCall{
267+ Prompt: "fetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word 'John Doe'",
268+ SessionID: session.ID,
269+ MaxOutputTokens: 10000,
271+ require.NoError(t, err)
272+ assert.NotNil(t, res)
274+ msgs, err := env.messages.List(t.Context(), session.ID)
275+ require.NoError(t, err)
278+ var fetchTCID string
280+ for _, msg := range msgs {
281+ if msg.Role == message.Assistant {
282+ for _, tc := range msg.ToolCalls() {
283+ if tc.Name == tools.FetchToolName {
288+ if msg.Role == message.Tool {
289+ for _, tr := range msg.ToolResults() {
290+ if tr.ToolCallID == fetchTCID {
297+ require.True(t, foundFetch, "Expected to find a fetch operation")
299+ t.Run("glob tool", func(t *testing.T) {
300+ agent, env := setupAgent(t, pair)
302+ session, err := env.sessions.Create(t.Context(), "New Session")
303+ require.NoError(t, err)
305+ res, err := agent.Run(t.Context(), SessionAgentCall{
306+ Prompt: "use glob to find all .go files in the current directory",
307+ SessionID: session.ID,
308+ MaxOutputTokens: 10000,
310+ require.NoError(t, err)
311+ assert.NotNil(t, res)
313+ msgs, err := env.messages.List(t.Context(), session.ID)
314+ require.NoError(t, err)
319+ for _, msg := range msgs {
320+ if msg.Role == message.Assistant {
321+ for _, tc := range msg.ToolCalls() {
322+ if tc.Name == tools.GlobToolName {
327+ if msg.Role == message.Tool {
328+ for _, tr := range msg.ToolResults() {
329+ if tr.ToolCallID == globTCID {
331+ require.Contains(t, tr.Content, "main.go", "Expected glob to find main.go")
337+ require.True(t, foundGlob, "Expected to find a glob operation")
339+ t.Run("grep tool", func(t *testing.T) {
340+ agent, env := setupAgent(t, pair)
342+ session, err := env.sessions.Create(t.Context(), "New Session")
343+ require.NoError(t, err)
345+ res, err := agent.Run(t.Context(), SessionAgentCall{
346+ Prompt: "use grep to search for the word 'package' in go files",
347+ SessionID: session.ID,
348+ MaxOutputTokens: 10000,
350+ require.NoError(t, err)
351+ assert.NotNil(t, res)
353+ msgs, err := env.messages.List(t.Context(), session.ID)
354+ require.NoError(t, err)
359+ for _, msg := range msgs {
360+ if msg.Role == message.Assistant {
361+ for _, tc := range msg.ToolCalls() {
362+ if tc.Name == tools.GrepToolName {
367+ if msg.Role == message.Tool {
368+ for _, tr := range msg.ToolResults() {
369+ if tr.ToolCallID == grepTCID {
371+ require.Contains(t, tr.Content, "main.go", "Expected grep to find main.go")
377+ require.True(t, foundGrep, "Expected to find a grep operation")
379+ t.Run("ls tool", func(t *testing.T) {
380+ agent, env := setupAgent(t, pair)
382+ session, err := env.sessions.Create(t.Context(), "New Session")
383+ require.NoError(t, err)
385+ res, err := agent.Run(t.Context(), SessionAgentCall{
386+ Prompt: "use ls to list the files in the current directory",
387+ SessionID: session.ID,
388+ MaxOutputTokens: 10000,
390+ require.NoError(t, err)
391+ assert.NotNil(t, res)
393+ msgs, err := env.messages.List(t.Context(), session.ID)
394+ require.NoError(t, err)
399+ for _, msg := range msgs {
400+ if msg.Role == message.Assistant {
401+ for _, tc := range msg.ToolCalls() {
402+ if tc.Name == tools.LSToolName {
407+ if msg.Role == message.Tool {
408+ for _, tr := range msg.ToolResults() {
409+ if tr.ToolCallID == lsTCID {
411+ require.Contains(t, tr.Content, "main.go", "Expected ls to list main.go")
412+ require.Contains(t, tr.Content, "go.mod", "Expected ls to list go.mod")
418+ require.True(t, foundLS, "Expected to find an ls operation")
420+ t.Run("multiedit tool", func(t *testing.T) {
421+ agent, env := setupAgent(t, pair)
423+ session, err := env.sessions.Create(t.Context(), "New Session")
424+ require.NoError(t, err)
426+ res, err := agent.Run(t.Context(), SessionAgentCall{
427+ Prompt: "use multiedit to change 'Hello, World!' to 'Hello, Crush!' and add a comment '// Greeting' above the fmt.Println line in main.go",
428+ SessionID: session.ID,
429+ MaxOutputTokens: 10000,
431+ require.NoError(t, err)
432+ assert.NotNil(t, res)
434+ msgs, err := env.messages.List(t.Context(), session.ID)
435+ require.NoError(t, err)
437+ foundMultiEdit := false
438+ var multiEditTCID string
440+ for _, msg := range msgs {
441+ if msg.Role == message.Assistant {
442+ for _, tc := range msg.ToolCalls() {
443+ if tc.Name == tools.MultiEditToolName {
444+ multiEditTCID = tc.ID
448+ if msg.Role == message.Tool {
449+ for _, tr := range msg.ToolResults() {
450+ if tr.ToolCallID == multiEditTCID {
451+ foundMultiEdit = true
457+ require.True(t, foundMultiEdit, "Expected to find a multiedit operation")
459+ mainGoPath := filepath.Join(env.workingDir, "main.go")
460+ content, err := os.ReadFile(mainGoPath)
461+ require.NoError(t, err)
462+ require.Contains(t, string(content), "Hello, Crush!", "Expected file to contain 'Hello, Crush!'")
464+ t.Run("sourcegraph tool", func(t *testing.T) {
465+ agent, env := setupAgent(t, pair)
467+ session, err := env.sessions.Create(t.Context(), "New Session")
468+ require.NoError(t, err)
470+ res, err := agent.Run(t.Context(), SessionAgentCall{
471+ Prompt: "use sourcegraph to search for 'func main' in Go repositories",
472+ SessionID: session.ID,
473+ MaxOutputTokens: 10000,
475+ require.NoError(t, err)
476+ assert.NotNil(t, res)
478+ msgs, err := env.messages.List(t.Context(), session.ID)
479+ require.NoError(t, err)
481+ foundSourcegraph := false
482+ var sourcegraphTCID string
484+ for _, msg := range msgs {
485+ if msg.Role == message.Assistant {
486+ for _, tc := range msg.ToolCalls() {
487+ if tc.Name == tools.SourcegraphToolName {
488+ sourcegraphTCID = tc.ID
492+ if msg.Role == message.Tool {
493+ for _, tr := range msg.ToolResults() {
494+ if tr.ToolCallID == sourcegraphTCID {
495+ foundSourcegraph = true
501+ require.True(t, foundSourcegraph, "Expected to find a sourcegraph operation")
503+ t.Run("write tool", func(t *testing.T) {
504+ agent, env := setupAgent(t, pair)
506+ session, err := env.sessions.Create(t.Context(), "New Session")
507+ require.NoError(t, err)
509+ res, err := agent.Run(t.Context(), SessionAgentCall{
510+ Prompt: "use write to create a new file called config.json with content '{\"name\": \"test\", \"version\": \"1.0.0\"}'",
511+ SessionID: session.ID,
512+ MaxOutputTokens: 10000,
514+ require.NoError(t, err)
515+ assert.NotNil(t, res)
517+ msgs, err := env.messages.List(t.Context(), session.ID)
518+ require.NoError(t, err)
521+ var writeTCID string
523+ for _, msg := range msgs {
524+ if msg.Role == message.Assistant {
525+ for _, tc := range msg.ToolCalls() {
526+ if tc.Name == tools.WriteToolName {
531+ if msg.Role == message.Tool {
532+ for _, tr := range msg.ToolResults() {
533+ if tr.ToolCallID == writeTCID {
540+ require.True(t, foundWrite, "Expected to find a write operation")
542+ configPath := filepath.Join(env.workingDir, "config.json")
543+ content, err := os.ReadFile(configPath)
544+ require.NoError(t, err)
545+ require.Contains(t, string(content), "test", "Expected config.json to contain 'test'")
546+ require.Contains(t, string(content), "1.0.0", "Expected config.json to contain '1.0.0'")
548+ t.Run("parallel tool calls", func(t *testing.T) {
549+ agent, env := setupAgent(t, pair)
551+ session, err := env.sessions.Create(t.Context(), "New Session")
552+ require.NoError(t, err)
554+ res, err := agent.Run(t.Context(), SessionAgentCall{
555+ Prompt: "use glob to find all .go files and use ls to list the current directory, it is very important that you run both tool calls in parallel",
556+ SessionID: session.ID,
557+ MaxOutputTokens: 10000,
559+ require.NoError(t, err)
560+ assert.NotNil(t, res)
562+ msgs, err := env.messages.List(t.Context(), session.ID)
563+ require.NoError(t, err)
565+ var assistantMsg *message.Message
566+ var toolMsgs []message.Message
568+ for _, msg := range msgs {
569+ if msg.Role == message.Assistant && len(msg.ToolCalls()) > 0 {
572+ if msg.Role == message.Tool {
573+ toolMsgs = append(toolMsgs, msg)
577+ require.NotNil(t, assistantMsg, "Expected to find an assistant message with tool calls")
578+ require.NotNil(t, toolMsgs, "Expected to find a tool message")
580+ toolCalls := assistantMsg.ToolCalls()
581+ require.GreaterOrEqual(t, len(toolCalls), 2, "Expected at least 2 tool calls in parallel")
585+ var globTCID, lsTCID string
587+ for _, tc := range toolCalls {
588+ if tc.Name == tools.GlobToolName {
592+ if tc.Name == tools.LSToolName {
598+ require.True(t, foundGlob, "Expected to find a glob tool call")
599+ require.True(t, foundLS, "Expected to find an ls tool call")
601+ require.GreaterOrEqual(t, len(toolMsgs), 2, "Expected at least 2 tool results in the same message")
603+ foundGlobResult := false
604+ foundLSResult := false
606+ for _, msg := range toolMsgs {
607+ for _, tr := range msg.ToolResults() {
608+ if tr.ToolCallID == globTCID {
609+ foundGlobResult = true
610+ require.Contains(t, tr.Content, "main.go", "Expected glob result to contain main.go")
611+ require.False(t, tr.IsError, "Expected glob result to not be an error")
613+ if tr.ToolCallID == lsTCID {
614+ foundLSResult = true
615+ require.Contains(t, tr.Content, "main.go", "Expected ls result to contain main.go")
616+ require.False(t, tr.IsError, "Expected ls result to not be an error")
621+ require.True(t, foundGlobResult, "Expected to find glob tool result")
622+ require.True(t, foundLSResult, "Expected to find ls tool result")
628+func makeTestTodos(n int) []session.Todo {
629+ todos := make([]session.Todo, n)
631+ todos[i] = session.Todo{
632+ Status: session.TodoStatusPending,
633+ Content: fmt.Sprintf("Task %d: Implement feature with some description that makes it realistic", i),
639+func BenchmarkBuildSummaryPrompt(b *testing.B) {
650+ for _, tc := range cases {
651+ todos := makeTestTodos(tc.numTodos)
653+ b.Run(tc.name, func(b *testing.B) {
656+ _ = buildSummaryPrompt(todos)
662+func TestPreparePrompt_FiltersImageAttachments(t *testing.T) {
664+ sa := testSessionAgent(env, nil, nil, "test prompt")
665+ agent := sa.(*sessionAgent)
668+ sess, err := env.sessions.Create(ctx, "test")
669+ require.NoError(t, err)
671+ // User message with text, a text attachment, and an image attachment.
672+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
674+ Parts: []message.ContentPart{
675+ message.TextContent{Text: "hello world"},
676+ message.BinaryContent{Path: "notes.txt", MIMEType: "text/plain", Data: []byte("important notes")},
677+ message.BinaryContent{Path: "image.png", MIMEType: "image/png", Data: []byte("fake-image-data")},
680+ require.NoError(t, err)
682+ msgs, err := env.messages.List(ctx, sess.ID)
683+ require.NoError(t, err)
685+ // When supportsImages is false, image attachments should be stripped.
686+ history, _ := agent.preparePrompt(msgs, false)
687+ // First message is the system reminder, second is the user message.
688+ require.Len(t, history, 2)
689+ require.Len(t, history[1].Content, 1)
690+ text, ok := fantasy.AsMessagePart[fantasy.TextPart](history[1].Content[0])
692+ require.Contains(t, text.Text, "hello world")
693+ require.Contains(t, text.Text, "important notes")
695+ // When supportsImages is true, image attachments should remain.
696+ history, _ = agent.preparePrompt(msgs, true)
697+ require.Len(t, history, 2)
698+ require.Len(t, history[1].Content, 2)
699+ text, ok = fantasy.AsMessagePart[fantasy.TextPart](history[1].Content[0])
701+ require.Contains(t, text.Text, "hello world")
702+ file, ok := fantasy.AsMessagePart[fantasy.FilePart](history[1].Content[1])
704+ require.Equal(t, "image.png", file.Filename)
707+func TestPreparePrompt_OrphanedToolUse(t *testing.T) {
709+ sa := testSessionAgent(env, nil, nil, "test prompt")
710+ agent := sa.(*sessionAgent)
713+ sess, err := env.sessions.Create(ctx, "test")
714+ require.NoError(t, err)
716+ // Create a user message.
717+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
719+ Parts: []message.ContentPart{
720+ message.TextContent{Text: "hello"},
723+ require.NoError(t, err)
725+ // Create an assistant message with a tool call but no tool result —
726+ // this simulates a cancelled/interrupted agent tool call.
727+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
728+ Role: message.Assistant,
729+ Parts: []message.ContentPart{
730+ message.TextContent{Text: "let me check"},
732+ ID: "call_orphaned_1",
734+ Input: `{"prompt":"do something"}`,
739+ require.NoError(t, err)
741+ // Create the next user message (the one that interrupted the tool call).
742+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
744+ Parts: []message.ContentPart{
745+ message.TextContent{Text: "Fix #2"},
748+ require.NoError(t, err)
750+ msgs, err := env.messages.List(ctx, sess.ID)
751+ require.NoError(t, err)
753+ history, _ := agent.preparePrompt(msgs, true)
755+ // The history must contain a synthetic tool result for the orphaned call.
757+ for _, msg := range history {
758+ if msg.Role != fantasy.MessageRoleTool {
761+ for _, part := range msg.Content {
762+ if tr, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](part); ok {
763+ if tr.ToolCallID == "call_orphaned_1" {
765+ _, isError := tr.Output.(fantasy.ToolResultOutputContentError)
766+ require.True(t, isError, "orphaned tool result should be an error")
771+ require.True(t, found, "expected synthetic tool result for orphaned tool call")
774+func TestPreparePrompt_OrphanedToolUseMixed(t *testing.T) {
776+ sa := testSessionAgent(env, nil, nil, "test prompt")
777+ agent := sa.(*sessionAgent)
780+ sess, err := env.sessions.Create(ctx, "test")
781+ require.NoError(t, err)
783+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
785+ Parts: []message.ContentPart{
786+ message.TextContent{Text: "hello"},
789+ require.NoError(t, err)
791+ // Assistant with 2 tool calls: one has a result, one is orphaned.
792+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
793+ Role: message.Assistant,
794+ Parts: []message.ContentPart{
798+ Input: `{"path":"/foo"}`,
802+ ID: "call_orphaned",
804+ Input: `{"prompt":"search"}`,
809+ require.NoError(t, err)
811+ // Only one tool result — for call_ok.
812+ _, err = env.messages.Create(ctx, sess.ID, message.CreateMessageParams{
814+ Parts: []message.ContentPart{
816+ ToolCallID: "call_ok",
818+ Content: "file contents",
822+ require.NoError(t, err)
824+ msgs, err := env.messages.List(ctx, sess.ID)
825+ require.NoError(t, err)
827+ history, _ := agent.preparePrompt(msgs, true)
829+ // Should have a synthetic result only for the orphaned call.
830+ var syntheticCount int
831+ for _, msg := range history {
832+ if msg.Role != fantasy.MessageRoleTool {
835+ for _, part := range msg.Content {
836+ if tr, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](part); ok {
837+ if tr.ToolCallID == "call_orphaned" {
843+ require.Equal(t, 1, syntheticCount, "expected exactly one synthetic result for the orphaned call")
846+func TestWorkaroundProviderMediaLimitations_TextOnlyModel(t *testing.T) {
848+ sa := testSessionAgent(env, nil, nil, "test prompt")
849+ agent := sa.(*sessionAgent)
851+ pngBase64 := base64.StdEncoding.EncodeToString([]byte("fake-png-data"))
853+ messages := []fantasy.Message{
855+ Role: fantasy.MessageRoleTool,
856+ Content: []fantasy.MessagePart{
857+ fantasy.ToolResultPart{
858+ ToolCallID: "call_1",
859+ Output: fantasy.ToolResultOutputContentMedia{
861+ MediaType: "image/png",
868+ // Non-Anthropic provider, no image support — should replace media with
869+ // a text placeholder and not create a synthetic user message.
870+ largeModel := Model{
871+ ModelCfg: config.SelectedModel{Provider: "openai"},
872+ CatwalkCfg: catwalk.Model{
873+ SupportsImages: false,
877+ result := agent.workaroundProviderMediaLimitations(messages, largeModel)
879+ // Should produce exactly one message: the tool message with a text
880+ // placeholder. No synthetic user message with FilePart.
881+ require.Len(t, result, 1)
882+ require.Equal(t, fantasy.MessageRoleTool, result[0].Role)
884+ tr, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](result[0].Content[0])
886+ _, ok = fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](tr.Output)
890+func TestWorkaroundProviderMediaLimitations_VisionModel(t *testing.T) {
892+ sa := testSessionAgent(env, nil, nil, "test prompt")
893+ agent := sa.(*sessionAgent)
895+ pngBase64 := base64.StdEncoding.EncodeToString([]byte("fake-png-data"))
897+ messages := []fantasy.Message{
899+ Role: fantasy.MessageRoleTool,
900+ Content: []fantasy.MessagePart{
901+ fantasy.ToolResultPart{
902+ ToolCallID: "call_1",
903+ Output: fantasy.ToolResultOutputContentMedia{
905+ MediaType: "image/png",
912+ // Non-Anthropic provider, image support — should create a synthetic
913+ // user message with FilePart.
914+ largeModel := Model{
915+ ModelCfg: config.SelectedModel{Provider: "openai"},
916+ CatwalkCfg: catwalk.Model{
917+ SupportsImages: true,
921+ result := agent.workaroundProviderMediaLimitations(messages, largeModel)
923+ // Should produce two messages: tool message with placeholder text,
924+ // and synthetic user message with FilePart.
925+ require.Len(t, result, 2)
926+ require.Equal(t, fantasy.MessageRoleTool, result[0].Role)
927+ require.Equal(t, fantasy.MessageRoleUser, result[1].Role)
929+ // The tool message should have text placeholder.
930+ tr, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](result[0].Content[0])
932+ textOutput, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](tr.Output)
934+ require.Contains(t, textOutput.Text, "see attached file")
936+ // The synthetic user message should contain a TextPart and a FilePart.
937+ require.Len(t, result[1].Content, 2)
938+ file, ok := fantasy.AsMessagePart[fantasy.FilePart](result[1].Content[1])
940+ require.Equal(t, "image/png", file.MediaType)
943+func TestWorkaroundProviderMediaLimitations_AnthropicProvider(t *testing.T) {
945+ sa := testSessionAgent(env, nil, nil, "test prompt")
946+ agent := sa.(*sessionAgent)
948+ pngBase64 := base64.StdEncoding.EncodeToString([]byte("fake-png-data"))
950+ messages := []fantasy.Message{
952+ Role: fantasy.MessageRoleTool,
953+ Content: []fantasy.MessagePart{
954+ fantasy.ToolResultPart{
955+ ToolCallID: "call_1",
956+ Output: fantasy.ToolResultOutputContentMedia{
958+ MediaType: "image/png",
965+ // Anthropic provider — should return messages unchanged regardless of
966+ // SupportsImages, since Anthropic handles media in tool results natively.
967+ largeModel := Model{
968+ ModelCfg: config.SelectedModel{Provider: string(catwalk.InferenceProviderAnthropic)},
969+ CatwalkCfg: catwalk.Model{
970+ SupportsImages: true,
974+ result := agent.workaroundProviderMediaLimitations(messages, largeModel)
975+ require.Len(t, result, 1)
976+ require.Equal(t, fantasy.MessageRoleTool, result[0].Role)
978+ // The media should still be in the tool result, untouched.
979+ tr, ok := fantasy.AsMessagePart[fantasy.ToolResultPart](result[0].Content[0])
981+ media, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentMedia](tr.Output)
983+ require.Equal(t, "image/png", media.MediaType)
986+func TestProviderRetryLogFields(t *testing.T) {
987+ t.Run("nil provider error", func(t *testing.T) {
988+ fields := providerRetryLogFields(nil, 2*time.Second)
989+ require.Equal(t, []any{"retry_delay", "2s"}, fields)
992+ t.Run("provider error with title and message", func(t *testing.T) {
993+ fields := providerRetryLogFields(&fantasy.ProviderError{
995+ Title: "rate limit",
996+ Message: "too many requests",
997+ }, 1500*time.Millisecond)
998+ require.Equal(t, []any{
999+ "retry_delay", "1.5s",
1000+ "status_code", 429,
1001+ "title", "rate limit",
1002+ "message", "too many requests",
1006+ t.Run("provider error without optional strings", func(t *testing.T) {
1007+ fields := providerRetryLogFields(&fantasy.ProviderError{
1010+ require.Equal(t, []any{
1011+ "retry_delay", "1s",
1012+ "status_code", 503,
internal/agent/agent_tool.gonew file+68
@@ -0,0 +1,68 @@
10+ "github.com/charmbracelet/crush/internal/agent/prompt"
11+ "github.com/charmbracelet/crush/internal/agent/tools"
12+ "github.com/charmbracelet/crush/internal/config"
15+//go:embed templates/agent_tool.md
16+var agentToolDescription string
18+type AgentParams struct {
19+ Prompt string `json:"prompt" description:"The task for the agent to perform"`
23+ AgentToolName = "agent"
26+func (c *coordinator) agentTool(ctx context.Context) (fantasy.AgentTool, error) {
27+ agentCfg, ok := c.cfg.Config().Agents[config.AgentTask]
29+ return nil, errors.New("task agent not configured")
31+ prompt, err := taskPrompt(prompt.WithWorkingDir(c.cfg.WorkingDir()))
36+ agent, err := c.buildAgent(ctx, prompt, agentCfg, true)
40+ return fantasy.NewParallelAgentTool(
42+ agentToolDescription,
43+ func(ctx context.Context, params AgentParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
44+ if params.Prompt == "" {
45+ return fantasy.NewTextErrorResponse("prompt is required"), nil
48+ sessionID := tools.GetSessionFromContext(ctx)
50+ return fantasy.ToolResponse{}, errors.New("session id missing from context")
53+ agentMessageID := tools.GetMessageFromContext(ctx)
54+ if agentMessageID == "" {
55+ return fantasy.ToolResponse{}, errors.New("agent message id missing from context")
58+ return c.runSubAgent(ctx, subAgentParams{
60+ SessionID: sessionID,
61+ AgentMessageID: agentMessageID,
63+ Prompt: params.Prompt,
64+ SessionTitle: "New Agent Session",
internal/agent/agentic_fetch_tool.gonew file+206
@@ -0,0 +1,206 @@
14+ "github.com/charmbracelet/crush/internal/agent/prompt"
15+ "github.com/charmbracelet/crush/internal/agent/tools"
16+ "github.com/charmbracelet/crush/internal/permission"
19+//go:embed templates/agentic_fetch.md
20+var agenticFetchToolDescription string
22+// agenticFetchValidationResult holds the validated parameters from the tool call context.
23+type agenticFetchValidationResult struct {
25+ AgentMessageID string
28+// validateAgenticFetchParams validates the tool call parameters and extracts required context values.
29+func validateAgenticFetchParams(ctx context.Context, params tools.AgenticFetchParams) (agenticFetchValidationResult, error) {
30+ if params.Prompt == "" {
31+ return agenticFetchValidationResult{}, errors.New("prompt is required")
34+ sessionID := tools.GetSessionFromContext(ctx)
36+ return agenticFetchValidationResult{}, errors.New("session id missing from context")
39+ agentMessageID := tools.GetMessageFromContext(ctx)
40+ if agentMessageID == "" {
41+ return agenticFetchValidationResult{}, errors.New("agent message id missing from context")
44+ return agenticFetchValidationResult{
45+ SessionID: sessionID,
46+ AgentMessageID: agentMessageID,
50+//go:embed templates/agentic_fetch_prompt.md.tpl
51+var agenticFetchPromptTmpl []byte
53+func (c *coordinator) agenticFetchTool(_ context.Context, client *http.Client) (fantasy.AgentTool, error) {
55+ transport := http.DefaultTransport.(*http.Transport).Clone()
56+ transport.MaxIdleConns = 100
57+ transport.MaxIdleConnsPerHost = 10
58+ transport.IdleConnTimeout = 90 * time.Second
60+ client = &http.Client{
61+ Timeout: 30 * time.Second,
62+ Transport: transport,
66+ return fantasy.NewParallelAgentTool(
67+ tools.AgenticFetchToolName,
68+ agenticFetchToolDescription,
69+ func(ctx context.Context, params tools.AgenticFetchParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
70+ validationResult, err := validateAgenticFetchParams(ctx, params)
72+ return fantasy.NewTextErrorResponse(err.Error()), nil
75+ // Determine description based on mode.
76+ var description string
77+ if params.URL != "" {
78+ description = fmt.Sprintf("Fetch and analyze content from URL: %s", params.URL)
80+ description = "Search the web and analyze results"
83+ p, err := c.permissions.Request(
85+ permission.CreatePermissionRequest{
86+ SessionID: validationResult.SessionID,
87+ Path: c.cfg.WorkingDir(),
89+ ToolName: tools.AgenticFetchToolName,
91+ Description: description,
92+ Params: tools.AgenticFetchPermissionsParams(params),
96+ return fantasy.ToolResponse{}, err
99+ return tools.NewPermissionDeniedResponse(), nil
102+ tmpDir, err := os.MkdirTemp(c.cfg.Config().Options.DataDirectory, "crush-fetch-*")
104+ return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to create temporary directory: %s", err)), nil
106+ defer os.RemoveAll(tmpDir)
108+ var fullPrompt string
110+ if params.URL != "" {
111+ // URL mode: fetch the URL content first.
112+ content, err := tools.FetchURLAndConvert(ctx, client, params.URL)
114+ return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to fetch URL: %s", err)), nil
117+ hasLargeContent := len(content) > tools.LargeContentThreshold
119+ if hasLargeContent {
120+ tempFile, err := os.CreateTemp(tmpDir, "page-*.md")
122+ return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to create temporary file: %s", err)), nil
124+ tempFilePath := tempFile.Name()
126+ if _, err := tempFile.WriteString(content); err != nil {
128+ return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to write content to file: %s", err)), nil
132+ fullPrompt = fmt.Sprintf("%s\n\nThe web page from %s has been saved to: %s\n\nUse the view and grep tools to analyze this file and extract the requested information.", params.Prompt, params.URL, tempFilePath)
134+ fullPrompt = fmt.Sprintf("%s\n\nWeb page URL: %s\n\n<webpage_content>\n%s\n</webpage_content>", params.Prompt, params.URL, content)
137+ // Search mode: let the sub-agent search and fetch as needed.
138+ fullPrompt = fmt.Sprintf("%s\n\nUse the web_search tool to find relevant information. Break down the question into smaller, focused searches if needed. After searching, use web_fetch to get detailed content from the most relevant results.", params.Prompt)
141+ promptOpts := []prompt.Option{
142+ prompt.WithWorkingDir(tmpDir),
145+ promptTemplate, err := prompt.NewPrompt("agentic_fetch", string(agenticFetchPromptTmpl), promptOpts...)
147+ return fantasy.ToolResponse{}, fmt.Errorf("error creating prompt: %s", err)
150+ _, small, err := c.buildAgentModels(ctx, true)
152+ return fantasy.ToolResponse{}, fmt.Errorf("error building models: %s", err)
155+ systemPrompt, err := promptTemplate.Build(ctx, small.Model.Provider(), small.Model.Model(), c.cfg)
157+ return fantasy.ToolResponse{}, fmt.Errorf("error building system prompt: %s", err)
160+ smallProviderCfg, ok := c.cfg.Config().Providers.Get(small.ModelCfg.Provider)
162+ return fantasy.ToolResponse{}, errors.New("small model provider not configured")
165+ webFetchTool := tools.NewWebFetchTool(tmpDir, client)
166+ webSearchTool := tools.NewWebSearchTool(client)
167+ fetchTools := []fantasy.AgentTool{
170+ tools.NewGlobTool(tmpDir, c.cfg.Config().Tools.Glob),
171+ tools.NewGrepTool(tmpDir, c.cfg.Config().Tools.Grep),
172+ tools.NewSourcegraphTool(client),
173+ tools.NewViewTool(c.lspManager, c.permissions, c.filetracker, nil, tmpDir),
176+ // Sub-agent tools run without hook interception. The top-level
177+ // `agentic_fetch` call itself is already wrapped from the coder's
178+ // side; firing hooks again for every inner tool call would run
179+ // the user's hooks N times per delegated turn.
181+ agent := NewSessionAgent(SessionAgentOptions{
182+ LargeModel: small, // Use small model for both (fetch doesn't need large)
184+ SystemPromptPrefix: smallProviderCfg.SystemPromptPrefix,
185+ SystemPrompt: systemPrompt,
186+ DisableAutoSummarize: c.cfg.Config().Options.DisableAutoSummarize,
187+ IsYolo: c.permissions.SkipRequests(),
188+ Sessions: c.sessions,
189+ Messages: c.messages,
193+ return c.runSubAgent(ctx, subAgentParams{
195+ SessionID: validationResult.SessionID,
196+ AgentMessageID: validationResult.AgentMessageID,
197+ ToolCallID: call.ID,
199+ SessionTitle: "Fetch Analysis",
200+ SessionSetup: func(sessionID string) {
201+ c.permissions.AutoApproveSession(sessionID)
internal/agent/agenttest/coordinator.gonew file+80
@@ -0,0 +1,80 @@
1+// Package agenttest provides test-only constructors for wiring a real
2+// production agent.Coordinator without booting a full app.App. It is
3+// imported only from _test.go files (e.g. internal/backend integration
4+// tests) and is never referenced by production code, so it is compiled
5+// only under tests and never ships in the production binary or API.
11+ "charm.land/catwalk/pkg/catwalk"
12+ "charm.land/fantasy/providers/openaicompat"
13+ "github.com/charmbracelet/crush/internal/agent"
14+ "github.com/charmbracelet/crush/internal/config"
15+ "github.com/charmbracelet/crush/internal/message"
16+ "github.com/charmbracelet/crush/internal/permission"
17+ "github.com/charmbracelet/crush/internal/session"
20+// NewCoordinator builds a real agent.Coordinator through the production
21+// agent.NewCoordinator constructor so the RunAccepted / BeginAccepted /
22+// run path (including UpdateModels) is the actual code under test.
24+// It installs a minimal config with a single openai-compatible provider
25+// whose model resolves offline. run rebuilds the model on every call, so
26+// the provider must construct without network I/O; the cancel-on-entry
27+// path this helper is built to exercise returns before any model call,
28+// so no request is ever issued. The coder agent's allowed-tools list is
29+// cleared to keep tool construction cheap and free of sub-agent wiring.
31+// The optional coordinator dependencies (history, filetracker, LSP,
32+// notify, runComplete, skills) are nil: run guards the publisher fields
33+// and the cancel-on-entry path never touches the others.
37+ sessions session.Service,
38+ messages message.Service,
39+) (agent.Coordinator, error) {
40+ cfg, err := config.Init(workingDir, "", false)
46+ providerID = "test-openai-compat"
47+ modelID = "test-model"
49+ cfg.Config().Providers.Set(providerID, config.ProviderConfig{
52+ Type: openaicompat.Name,
53+ BaseURL: "http://127.0.0.1:0/v1",
55+ Models: []catwalk.Model{{ID: modelID, DefaultMaxTokens: 4096}},
57+ selected := config.SelectedModel{Provider: providerID, Model: modelID}
58+ cfg.OverridePreferredModel(config.SelectedModelTypeLarge, selected)
59+ cfg.OverridePreferredModel(config.SelectedModelTypeSmall, selected)
62+ // Keep buildTools light: no sub-agent or agentic-fetch construction.
63+ coderCfg := cfg.Config().Agents[config.AgentCoder]
64+ coderCfg.AllowedTools = nil
65+ cfg.Config().Agents[config.AgentCoder] = coderCfg
67+ return agent.NewCoordinator(
72+ permission.NewPermissionService(workingDir, true, nil),
internal/agent/common_test.gonew file+206
@@ -0,0 +1,206 @@
11+ "charm.land/catwalk/pkg/catwalk"
13+ "charm.land/fantasy/providers/openaicompat"
15+ "github.com/charmbracelet/crush/internal/agent/prompt"
16+ "github.com/charmbracelet/crush/internal/agent/tools"
17+ "github.com/charmbracelet/crush/internal/config"
18+ "github.com/charmbracelet/crush/internal/csync"
19+ "github.com/charmbracelet/crush/internal/db"
20+ "github.com/charmbracelet/crush/internal/filetracker"
21+ "github.com/charmbracelet/crush/internal/history"
22+ "github.com/charmbracelet/crush/internal/lsp"
23+ "github.com/charmbracelet/crush/internal/message"
24+ "github.com/charmbracelet/crush/internal/permission"
25+ "github.com/charmbracelet/crush/internal/session"
26+ "github.com/stretchr/testify/require"
28+ _ "github.com/joho/godotenv/autoload"
31+// fakeEnv is an environment for testing.
34+ sessions session.Service
35+ messages message.Service
36+ permissions permission.Service
37+ history history.Service
38+ filetracker *filetracker.Service
39+ lspClients *csync.Map[string, *lsp.Client]
42+type builderFunc func(t *testing.T, r *vcr.Recorder) (fantasy.LanguageModel, error)
44+type modelPair struct {
46+ largeModel builderFunc
47+ smallModel builderFunc
50+func hyperBuilder(model string) builderFunc {
51+ return func(t *testing.T, r *vcr.Recorder) (fantasy.LanguageModel, error) {
52+ provider, err := openaicompat.New(
53+ openaicompat.WithBaseURL("https://hyper.charm.land/v1"),
54+ openaicompat.WithAPIKey(os.Getenv("CRUSH_HYPER_API_KEY")),
55+ openaicompat.WithHTTPClient(&http.Client{Transport: r}),
60+ return provider.LanguageModel(t.Context(), model)
64+func testEnv(t *testing.T) fakeEnv {
65+ workingDir := filepath.Join("/tmp/crush-test/", t.Name())
66+ os.RemoveAll(workingDir)
68+ err := os.MkdirAll(workingDir, 0o755)
69+ require.NoError(t, err)
71+ conn, err := db.Connect(t.Context(), t.TempDir())
72+ require.NoError(t, err)
75+ sessions := session.NewService(q, conn)
76+ messages := message.NewService(q)
78+ permissions := permission.NewPermissionService(workingDir, true, []string{})
79+ history := history.NewService(q, conn)
80+ filetrackerService := filetracker.NewService(q)
81+ lspClients := csync.NewMap[string, *lsp.Client]()
85+ os.RemoveAll(workingDir)
99+func testSessionAgent(env fakeEnv, large, small fantasy.LanguageModel, systemPrompt string, tools ...fantasy.AgentTool) SessionAgent {
100+ largeModel := Model{
102+ CatwalkCfg: catwalk.Model{
103+ ContextWindow: 200000,
104+ DefaultMaxTokens: 10000,
107+ smallModel := Model{
109+ CatwalkCfg: catwalk.Model{
110+ ContextWindow: 200000,
111+ DefaultMaxTokens: 10000,
114+ agent := NewSessionAgent(SessionAgentOptions{
115+ LargeModel: largeModel,
116+ SmallModel: smallModel,
117+ SystemPrompt: systemPrompt,
119+ Sessions: env.sessions,
120+ Messages: env.messages,
126+func coderAgent(r *vcr.Recorder, env fakeEnv, large, small fantasy.LanguageModel) (SessionAgent, error) {
127+ fixedTime := func() time.Time {
128+ t, _ := time.Parse("1/2/2006", "1/1/2025")
131+ prompt, err := coderPrompt(
132+ prompt.WithTimeFunc(fixedTime),
133+ prompt.WithPlatform("linux"),
134+ prompt.WithWorkingDir(filepath.ToSlash(env.workingDir)),
139+ cfg, err := config.Init(env.workingDir, "", false)
144+ // NOTE(@andreynering): Set a fixed config to ensure cassettes match
145+ // independently of user config on `$HOME/.config/crush/crush.json`.
146+ cfg.Config().Options.Attribution = &config.Attribution{
147+ TrailerStyle: "co-authored-by",
148+ GeneratedWith: true,
151+ // Clear some fields to avoid issues with VCR cassette matching.
152+ cfg.Config().Options.SkillsPaths = nil
153+ cfg.Config().Options.DisabledSkills = []string{"crush-config"}
154+ cfg.Config().Options.ContextPaths = nil
155+ cfg.Config().Options.GlobalContextPaths = nil
156+ cfg.Config().LSP = nil
158+ systemPrompt, err := prompt.Build(context.TODO(), large.Provider(), large.Model(), cfg)
163+ // Get the model name for the bash tool
164+ modelName := large.Model() // fallback to ID if Name not available
165+ if model := cfg.Config().GetModel(large.Provider(), large.Model()); model != nil {
166+ modelName = model.Name
169+ allTools := []fantasy.AgentTool{
170+ tools.NewBashTool(env.permissions, env.workingDir, cfg.Config().Options.Attribution, modelName),
171+ tools.NewDownloadTool(env.permissions, env.workingDir, r.GetDefaultClient()),
172+ tools.NewEditTool(nil, env.permissions, env.history, *env.filetracker, env.workingDir),
173+ tools.NewMultiEditTool(nil, env.permissions, env.history, *env.filetracker, env.workingDir),
174+ tools.NewFetchTool(env.permissions, env.workingDir, r.GetDefaultClient()),
175+ tools.NewGlobTool(env.workingDir, cfg.Config().Tools.Glob),
176+ tools.NewGrepTool(env.workingDir, cfg.Config().Tools.Grep),
177+ tools.NewLsTool(env.permissions, env.workingDir, cfg.Config().Tools.Ls),
178+ tools.NewSourcegraphTool(r.GetDefaultClient()),
179+ tools.NewViewTool(nil, env.permissions, *env.filetracker, nil, env.workingDir),
180+ tools.NewWriteTool(nil, env.permissions, env.history, *env.filetracker, env.workingDir),
183+ return testSessionAgent(env, large, small, systemPrompt, allTools...), nil
186+// createSimpleGoProject creates a simple Go project structure in the given directory.
187+// It creates a go.mod file and a main.go file with a basic hello world program.
188+func createSimpleGoProject(t *testing.T, dir string) {
189+ goMod := `module example.com/testproject
193+ err := os.WriteFile(dir+"/go.mod", []byte(goMod), 0o644)
194+ require.NoError(t, err)
196+ mainGo := `package main
201+ fmt.Println("Hello, World!")
204+ err = os.WriteFile(dir+"/main.go", []byte(mainGo), 0o644)
205+ require.NoError(t, err)
internal/agent/convert_test.gonew file+94
@@ -0,0 +1,94 @@
8+ "github.com/stretchr/testify/require"
11+func TestConvertToToolResult_InvalidBase64(t *testing.T) {
15+ result := fantasy.ToolResultContent{
16+ ToolCallID: "call_123",
17+ ToolName: "test_tool",
18+ Result: fantasy.ToolResultOutputContentMedia{
20+ MediaType: "image/png",
24+ tr := a.convertToToolResult(result)
25+ require.True(t, tr.IsError)
26+ require.Empty(t, tr.Data)
27+ require.Contains(t, tr.Content, "invalid encoding")
28+ require.Equal(t, "call_123", tr.ToolCallID)
29+ require.Equal(t, "test_tool", tr.Name)
32+func TestConvertToToolResult_ValidMedia(t *testing.T) {
36+ validData := base64.StdEncoding.EncodeToString([]byte("test image data"))
38+ result := fantasy.ToolResultContent{
39+ ToolCallID: "call_456",
40+ ToolName: "screenshot",
41+ Result: fantasy.ToolResultOutputContentMedia{
43+ MediaType: "image/png",
44+ Text: "Screenshot captured",
48+ tr := a.convertToToolResult(result)
49+ require.False(t, tr.IsError)
50+ require.Equal(t, validData, tr.Data)
51+ require.Equal(t, "image/png", tr.MIMEType)
52+ require.Equal(t, "Screenshot captured", tr.Content)
55+func TestConvertToToolResult_ValidMediaNoText(t *testing.T) {
59+ validData := base64.StdEncoding.EncodeToString([]byte("test image data"))
61+ result := fantasy.ToolResultContent{
62+ ToolCallID: "call_789",
64+ Result: fantasy.ToolResultOutputContentMedia{
66+ MediaType: "image/jpeg",
70+ tr := a.convertToToolResult(result)
71+ require.False(t, tr.IsError)
72+ require.Equal(t, validData, tr.Data)
73+ require.Equal(t, "image/jpeg", tr.MIMEType)
74+ require.Equal(t, "Loaded image/jpeg content", tr.Content)
77+func TestConvertToToolResult_ASCIIButInvalidBase64(t *testing.T) {
81+ result := fantasy.ToolResultContent{
82+ ToolCallID: "call_abc",
83+ ToolName: "mcp_tool",
84+ Result: fantasy.ToolResultOutputContentMedia{
85+ Data: "not-valid-base64!!!",
86+ MediaType: "image/png",
90+ tr := a.convertToToolResult(result)
91+ require.True(t, tr.IsError)
92+ require.Empty(t, tr.Data)
93+ require.Contains(t, tr.Content, "invalid encoding")
internal/agent/coordinator.gonew file+1661
@@ -0,0 +1,1661 @@
21+ "charm.land/catwalk/pkg/catwalk"
23+ "github.com/charmbracelet/crush/internal/agent/hyper"
24+ "github.com/charmbracelet/crush/internal/agent/notify"
25+ "github.com/charmbracelet/crush/internal/agent/prompt"
26+ "github.com/charmbracelet/crush/internal/agent/tools"
27+ "github.com/charmbracelet/crush/internal/agent/tools/mcp"
28+ "github.com/charmbracelet/crush/internal/config"
29+ "github.com/charmbracelet/crush/internal/csync"
30+ "github.com/charmbracelet/crush/internal/discover"
31+ "github.com/charmbracelet/crush/internal/event"
32+ "github.com/charmbracelet/crush/internal/filetracker"
33+ "github.com/charmbracelet/crush/internal/history"
34+ "github.com/charmbracelet/crush/internal/hooks"
35+ "github.com/charmbracelet/crush/internal/log"
36+ "github.com/charmbracelet/crush/internal/lsp"
37+ "github.com/charmbracelet/crush/internal/message"
38+ "github.com/charmbracelet/crush/internal/oauth/copilot"
39+ "github.com/charmbracelet/crush/internal/permission"
40+ "github.com/charmbracelet/crush/internal/pubsub"
41+ "github.com/charmbracelet/crush/internal/session"
42+ "github.com/charmbracelet/crush/internal/skills"
43+ "golang.org/x/sync/errgroup"
45+ "charm.land/fantasy/providers/anthropic"
46+ "charm.land/fantasy/providers/azure"
47+ "charm.land/fantasy/providers/bedrock"
48+ "charm.land/fantasy/providers/google"
49+ "charm.land/fantasy/providers/openai"
50+ "charm.land/fantasy/providers/openaicompat"
51+ "charm.land/fantasy/providers/openrouter"
52+ "charm.land/fantasy/providers/vercel"
53+ openaisdk "github.com/charmbracelet/openai-go/option"
54+ "github.com/qjebbs/go-jsons"
57+// Coordinator errors.
59+ errCoderAgentNotConfigured = errors.New("coder agent not configured")
60+ errModelProviderNotConfigured = errors.New("model provider not configured")
61+ errLargeModelNotSelected = errors.New("large model not selected")
62+ errSmallModelNotSelected = errors.New("small model not selected")
63+ errLargeModelProviderNotConfigured = errors.New("large model provider not configured")
64+ errSmallModelProviderNotConfigured = errors.New("small model provider not configured")
65+ errLargeModelNotFound = errors.New("large model not found in provider config")
66+ errSmallModelNotFound = errors.New("small model not found in provider config")
69+// Copilot models that use the Responses API instead of Chat Completions.
70+var copilotResponsesModels = map[string]bool{
72+ "gpt-5.2-codex": true,
73+ "gpt-5.3-codex": true,
75+ "gpt-5.4-mini": true,
80+// OpenCode models that user Anthropic Messages API instead of Chat Completions.
81+var opencodeMessagesModels = map[string]bool{
85+type Coordinator interface {
86+ // INFO: (kujtim) this is not used yet we will use this when we have multiple agents
87+ // SetMainAgent(string)
88+ Run(ctx context.Context, sessionID, prompt string, attachments ...message.Attachment) (*fantasy.AgentResult, error)
89+ // RunAccepted runs a call that was already accepted via
90+ // BeginAccepted on the fire-and-forget dispatch path. The handle is
91+ // the only carrier of accept-state across the backend.runAgent /
92+ // Coordinator / sessionAgent.Run layers: it reaches
93+ // sessionAgent.Run as SessionAgentCall.Accepted, where it is
94+ // consumed under dispatchMu once the accepted -> (cancel-on-entry |
95+ // queued | active) transition is chosen.
96+ RunAccepted(ctx context.Context, accept *AcceptedRun, sessionID, prompt string, attachments ...message.Attachment) (*fantasy.AgentResult, error)
97+ BeginAccepted(sessionID string) *AcceptedRun
98+ Cancel(sessionID string)
100+ IsSessionBusy(sessionID string) bool
102+ QueuedPrompts(sessionID string) int
103+ QueuedPromptsList(sessionID string) []string
104+ ClearQueue(sessionID string)
105+ Summarize(context.Context, string) error
107+ UpdateModels(ctx context.Context) error
108+ GenerateTitle(ctx context.Context, sessionID, prompt string)
111+type coordinator struct {
112+ cfg *config.ConfigStore
113+ sessions session.Service
114+ messages message.Service
115+ permissions permission.Service
116+ history history.Service
117+ filetracker filetracker.Service
118+ lspManager *lsp.Manager
119+ notify pubsub.Publisher[notify.Notification]
120+ runComplete pubsub.Publisher[notify.RunComplete]
122+ currentAgent SessionAgent
123+ agents map[string]SessionAgent
125+ // Skills discovery results (session-start snapshot).
126+ allSkills []*skills.Skill // Pre-filter: all discovered after dedup.
127+ activeSkills []*skills.Skill // Post-filter: active skills only.
128+ skillTracker *skills.Tracker
130+ // providerClients caches built provider clients keyed by their fully
131+ // resolved configuration. UpdateModels rebuilds models every turn;
132+ // without this, each turn discards the provider's HTTP client and its
133+ // keep-alive connection pool, forcing a fresh TLS handshake. The key
134+ // captures every input buildProvider depends on, so any config/model/
135+ // credential change misses the cache and rebuilds.
136+ providerClients *csync.Map[string, fantasy.Provider]
138+ // toolsCache avoids rebuilding the tool set on every UpdateModels call.
139+ // The cache is invalidated when the config pointer changes (reload or
140+ // mutation) or when mcpToolsGen is bumped (MCP server connect/disconnect
141+ // or tools/list_changed notification).
142+ toolsCacheMu sync.Mutex
143+ toolsCache []fantasy.AgentTool
144+ toolsCacheCfg *config.Config
145+ toolsCacheMCP uint64
146+ mcpToolsGen atomic.Uint64
148+ // providerOptsCache avoids repeating the 3× JSON marshal + merge +
149+ // unmarshal in getProviderOptions on every turn when the model and
150+ // config have not changed. Keyed by config pointer + model CatwalkCfg
151+ // ID + provider name.
152+ providerOptsCacheMu sync.Mutex
153+ providerOptsCache fantasy.ProviderOptions
154+ providerOptsCacheKey string
156+ readyWg errgroup.Group
160+ ctx context.Context,
161+ cfg *config.ConfigStore,
162+ sessions session.Service,
163+ messages message.Service,
164+ permissions permission.Service,
165+ history history.Service,
166+ filetracker filetracker.Service,
167+ lspManager *lsp.Manager,
168+ notify pubsub.Publisher[notify.Notification],
169+ runComplete pubsub.Publisher[notify.RunComplete],
170+ skillsMgr *skills.Manager,
171+) (Coordinator, error) {
172+ // Skills are pre-discovered by the caller (see app.New /
173+ // backend.CreateWorkspace) and passed in via the manager. If no
174+ // manager was provided (legacy callers), fall back to an in-line
175+ // discovery so the coordinator still works.
176+ var allSkills, activeSkills []*skills.Skill
177+ if skillsMgr != nil {
178+ allSkills = skillsMgr.AllSkills()
179+ activeSkills = skillsMgr.ActiveSkills()
181+ allSkills, activeSkills = discoverSkills(cfg)
183+ skillTracker := skills.NewTracker(activeSkills)
189+ permissions: permissions,
191+ filetracker: filetracker,
192+ lspManager: lspManager,
194+ runComplete: runComplete,
195+ agents: make(map[string]SessionAgent),
196+ allSkills: allSkills,
197+ activeSkills: activeSkills,
198+ skillTracker: skillTracker,
200+ providerClients: csync.NewMap[string, fantasy.Provider](),
203+ agentCfg, ok := cfg.Config().Agents[config.AgentCoder]
205+ return nil, errCoderAgentNotConfigured
208+ // TODO: make this dynamic when we support multiple agents
209+ prompt, err := coderPrompt(prompt.WithWorkingDir(c.cfg.WorkingDir()))
214+ agent, err := c.buildAgent(ctx, prompt, agentCfg, false)
218+ c.currentAgent = agent
219+ c.agents[config.AgentCoder] = agent
221+ // Subscribe to MCP tool-list changes so the tools cache is invalidated
222+ // when MCP servers connect/disconnect or announce new tools.
224+ for ev := range mcp.SubscribeEvents(ctx) {
225+ if ev.Payload.Type == mcp.EventToolsListChanged || ev.Payload.Type == mcp.EventStateChanged {
226+ c.mcpToolsGen.Add(1)
234+// Run implements Coordinator.
235+func (c *coordinator) Run(ctx context.Context, sessionID string, prompt string, attachments ...message.Attachment) (*fantasy.AgentResult, error) {
236+ return c.run(ctx, nil, sessionID, prompt, attachments...)
239+// RunAccepted implements Coordinator.
240+func (c *coordinator) RunAccepted(ctx context.Context, accept *AcceptedRun, sessionID string, prompt string, attachments ...message.Attachment) (*fantasy.AgentResult, error) {
241+ return c.run(ctx, accept, sessionID, prompt, attachments...)
244+// run is the shared implementation behind Run and RunAccepted. When
245+// accept is non-nil it is threaded onto the SessionAgentCall as
246+// Accepted so sessionAgent.Run can consume the accept reservation under
247+// dispatchMu; when nil (the in-process/local path) no accept tracking
249+func (c *coordinator) run(ctx context.Context, accept *AcceptedRun, sessionID string, prompt string, attachments ...message.Attachment) (*fantasy.AgentResult, error) {
250+ if err := c.readyWg.Wait(); err != nil {
254+ // refresh models before each run
255+ if err := c.UpdateModels(ctx); err != nil {
256+ return nil, fmt.Errorf("failed to update models: %w", err)
259+ model := c.currentAgent.Model()
260+ maxTokens := model.CatwalkCfg.DefaultMaxTokens
261+ if model.ModelCfg.MaxTokens != 0 {
262+ maxTokens = model.ModelCfg.MaxTokens
265+ if !model.CatwalkCfg.SupportsImages && attachments != nil {
266+ // filter out image attachments
267+ filteredAttachments := make([]message.Attachment, 0, len(attachments))
268+ for _, att := range attachments {
270+ filteredAttachments = append(filteredAttachments, att)
273+ attachments = filteredAttachments
276+ providerCfg, ok := c.cfg.Config().Providers.Get(model.ModelCfg.Provider)
278+ return nil, errModelProviderNotConfigured
281+ mergedOptions, temp, topP, topK, freqPenalty, presPenalty := c.cachedMergeCallOptions(model, providerCfg)
283+ if err := c.refreshTokenIfExpired(ctx, providerCfg); err != nil {
284+ // NOTE(@andreynering): We don't return here because the event handling to ask the user to reauthenticate
285+ // depends on the flow below. If refresh fails, proceed with the token we have.
286+ slog.Error("Failed to refresh OAuth2 token. Proceeding with existing token.", "error", err)
289+ // Coalesce per-attempt RunComplete payloads so only the final
290+ // outcome reaches subscribers. Without this, the first attempt's
291+ // failed RunComplete (unauthorized) would race ahead of the
292+ // retry's success, and `crush run` would exit on the stale error
293+ // before ever seeing the retry result. Each attempt's
294+ // SessionAgentCall.OnComplete hook overwrites latest; we publish
295+ // exactly once after retries resolve, via PublishMustDeliver, so
296+ // a momentarily-full subscriber buffer can't silently drop the
299+ latest notify.RunComplete
302+ onComplete := func(rc notify.RunComplete) {
306+ // Propagate the caller-supplied RunID (set via agent.WithRunID
307+ // at the HTTP boundary in backend.SendMessage) onto the
308+ // SessionAgentCall so the terminal RunComplete event echoes it
309+ // back. Both attempts in the retry chain reuse the same RunID;
310+ // the coalesce closure publishes the final outcome under that
312+ runID := RunIDFromContext(ctx)
313+ run := func() (*fantasy.AgentResult, error) {
314+ return c.currentAgent.Run(ctx, SessionAgentCall{
315+ SessionID: sessionID,
318+ Attachments: attachments,
319+ MaxOutputTokens: maxTokens,
320+ ProviderOptions: mergedOptions,
324+ FrequencyPenalty: freqPenalty,
325+ PresencePenalty: presPenalty,
326+ OnComplete: onComplete,
330+ beforeLoaded := c.skillTracker.LoadedNames()
331+ var result *fantasy.AgentResult
332+ originalErr := c.runWithUnauthorizedRetry(ctx, providerCfg, func() error {
337+ logTurnSkillUsage(sessionID, prompt, c.activeSkills, c.skillTracker, beforeLoaded)
339+ // Notify only if still unauthorized after retry — a successful
340+ // retry means the user doesn't need to re-authenticate.
341+ if originalErr != nil && c.isUnauthorized(originalErr) && c.notify != nil && model.ModelCfg.Provider == hyper.Name {
342+ c.notify.Publish(pubsub.CreatedEvent, notify.Notification{
343+ Type: notify.TypeReAuthenticate,
344+ ProviderID: model.ModelCfg.Provider,
348+ if hasLatest && c.runComplete != nil {
349+ c.runComplete.PublishMustDeliver(ctx, pubsub.UpdatedEvent, latest)
350+ // Signal to the dispatcher (backend.runAgent) that the
351+ // authoritative terminal RunComplete for this run was already
352+ // emitted, so it does not publish a duplicate fallback for the
353+ // error it is about to receive.
354+ MarkRunCompletePublished(ctx)
356+ return result, originalErr
359+// effectiveReasoningEffort returns the reasoning effort to apply for provider calls.
360+// It prefers the user-selected effort when valid, otherwise the model default when
361+// valid, and finally falls back to the first configured reasoning level.
362+func effectiveReasoningEffort(model Model) string {
363+ if !model.CatwalkCfg.CanReason {
367+ if effort := model.ModelCfg.ReasoningEffort; effort != "" && slices.Contains(model.CatwalkCfg.ReasoningLevels, effort) {
370+ if effort := model.CatwalkCfg.DefaultReasoningEffort; effort != "" && slices.Contains(model.CatwalkCfg.ReasoningLevels, effort) {
373+ if len(model.CatwalkCfg.ReasoningLevels) > 0 {
374+ return model.CatwalkCfg.ReasoningLevels[0]
379+func getProviderOptions(model Model, providerCfg config.ProviderConfig) fantasy.ProviderOptions {
380+ options := fantasy.ProviderOptions{}
382+ cfgOpts := []byte("{}")
383+ providerCfgOpts := []byte("{}")
384+ catwalkOpts := []byte("{}")
386+ if model.ModelCfg.ProviderOptions != nil {
387+ data, err := json.Marshal(model.ModelCfg.ProviderOptions)
393+ if providerCfg.ProviderOptions != nil {
394+ data, err := json.Marshal(providerCfg.ProviderOptions)
396+ providerCfgOpts = data
400+ if model.CatwalkCfg.Options.ProviderOptions != nil {
401+ data, err := json.Marshal(model.CatwalkCfg.Options.ProviderOptions)
407+ readers := []io.Reader{
408+ bytes.NewReader(catwalkOpts),
409+ bytes.NewReader(providerCfgOpts),
410+ bytes.NewReader(cfgOpts),
413+ got, err := jsons.Merge(readers)
415+ slog.Error("Could not merge call config", "err", err)
419+ mergedOptions := make(map[string]any)
421+ err = json.Unmarshal([]byte(got), &mergedOptions)
423+ slog.Error("Could not create config for call", "err", err)
427+ reasoningEffort := effectiveReasoningEffort(model)
428+ shouldSetEffort := model.CatwalkCfg.CanReason &&
429+ reasoningEffort != "" &&
430+ slices.Contains(model.CatwalkCfg.ReasoningLevels, reasoningEffort)
432+ switch providerCfg.Type {
433+ case openai.Name, azure.Name:
434+ _, hasReasoningEffort := mergedOptions["reasoning_effort"]
435+ if !hasReasoningEffort && shouldSetEffort {
436+ mergedOptions["reasoning_effort"] = reasoningEffort
438+ if openai.IsResponsesModel(model.CatwalkCfg.ID) {
439+ if openai.IsResponsesReasoningModel(model.CatwalkCfg.ID) {
440+ mergedOptions["reasoning_summary"] = "auto"
441+ mergedOptions["include"] = []openai.IncludeType{openai.IncludeReasoningEncryptedContent}
443+ parsed, err := openai.ParseResponsesOptions(mergedOptions)
445+ options[openai.Name] = parsed
448+ parsed, err := openai.ParseOptions(mergedOptions)
450+ options[openai.Name] = parsed
454+ case anthropic.Name, bedrock.Name:
456+ _, hasEffort = mergedOptions["effort"]
457+ _, hasThink = mergedOptions["thinking"]
458+ extraBody = make(map[string]any)
461+ switch providerCfg.ID {
462+ case string(catwalk.InferenceProviderAlibabaSingapore), string(catwalk.InferenceProviderAlibabaUS):
464+ case !hasEffort && shouldSetEffort:
465+ extraBody["reasoning_effort"] = reasoningEffort
466+ case !hasThink && model.CatwalkCfg.CanReason:
467+ if model.ModelCfg.Think {
468+ extraBody["thinking"] = map[string]any{"type": "enabled"}
470+ extraBody["thinking"] = map[string]any{"type": "disabled"}
473+ mergedOptions["extra_body"] = extraBody
477+ case !hasEffort && shouldSetEffort:
478+ mergedOptions["effort"] = reasoningEffort
479+ case !hasThink && model.ModelCfg.Think:
480+ mergedOptions["thinking"] = map[string]any{"budget_tokens": 2000}
484+ parsed, err := anthropic.ParseOptions(mergedOptions)
486+ options[anthropic.Name] = parsed
489+ case openrouter.Name:
490+ _, hasReasoning := mergedOptions["reasoning"]
491+ if !hasReasoning && shouldSetEffort {
492+ mergedOptions["reasoning"] = map[string]any{
494+ "effort": reasoningEffort,
497+ parsed, err := openrouter.ParseOptions(mergedOptions)
499+ options[openrouter.Name] = parsed
503+ _, hasReasoning := mergedOptions["reasoning"]
504+ if !hasReasoning && shouldSetEffort {
505+ mergedOptions["reasoning"] = map[string]any{
507+ "effort": reasoningEffort,
510+ parsed, err := vercel.ParseOptions(mergedOptions)
512+ options[vercel.Name] = parsed
516+ _, hasReasoning := mergedOptions["thinking_config"]
518+ if strings.HasPrefix(model.CatwalkCfg.ID, "gemini-2") {
519+ mergedOptions["thinking_config"] = map[string]any{
520+ "thinking_budget": 2000,
521+ "include_thoughts": true,
524+ mergedOptions["thinking_config"] = map[string]any{
525+ "thinking_level": reasoningEffort,
526+ "include_thoughts": true,
530+ parsed, err := google.ParseOptions(mergedOptions)
532+ options[google.Name] = parsed
535+ case openaicompat.Name, hyper.Name:
536+ extraBody := make(map[string]any)
538+ _, hasReasoningEffort := mergedOptions["reasoning_effort"]
539+ if !hasReasoningEffort && shouldSetEffort {
540+ switch providerCfg.ID {
541+ case string(catwalk.InferenceProviderIoNet):
542+ extraBody["reasoning"] = map[string]string{"effort": reasoningEffort}
544+ mergedOptions["reasoning_effort"] = reasoningEffort
548+ // "reasoning effort" is a standard OpenAI field, but "thinking" is not.
549+ // Setting it in the right way for each provider.
550+ // TODO: Abstract this in Fantasy somehow?
551+ // TODO: Allow custom providers to specify how to set this?
552+ switch providerCfg.ID {
554+ extraBody["thinking"] = model.ModelCfg.Think
555+ case string(catwalk.InferenceProviderIoNet):
556+ if _, ok := extraBody["reasoning"]; !ok && model.CatwalkCfg.CanReason {
557+ if model.ModelCfg.Think {
558+ extraBody["reasoning"] = map[string]string{"effort": "medium"}
560+ extraBody["reasoning"] = map[string]string{"effort": "none"}
564+ case string(catwalk.InferenceProviderZAI), string(catwalk.InferenceProviderDeepSeek):
565+ if model.ModelCfg.Think || reasoningEffort != "" {
566+ extraBody["thinking"] = map[string]any{"type": "enabled"}
568+ extraBody["thinking"] = map[string]any{"type": "disabled"}
571+ case string(catwalk.InferenceProviderFireworks):
572+ // NOTE: Fireworks break if we set both `reasoning_effort` and `thinking`.
573+ if reasoningEffort == "" {
574+ if model.ModelCfg.Think {
575+ extraBody["thinking"] = map[string]any{"type": "enabled"}
577+ extraBody["thinking"] = map[string]any{"type": "disabled"}
581+ case string(catwalk.InferenceProviderBaseten):
582+ extraBody["chat_template_args"] = map[string]any{
583+ "enable_thinking": model.ModelCfg.Think || reasoningEffort != "",
586+ case string(catwalk.InferenceProviderAlibabaSingapore), string(catwalk.InferenceProviderAlibabaUS):
587+ if model.CatwalkCfg.CanReason {
588+ extraBody["enable_thinking"] = model.ModelCfg.Think || reasoningEffort != ""
592+ mergedOptions["extra_body"] = extraBody
594+ parsed, err := openaicompat.ParseOptions(mergedOptions)
596+ options[openaicompat.Name] = parsed
600+ // Known custom providers (litellm, ollama, omlx) are
601+ // openai-compat under the hood.
602+ if discover.IsKnownCustomProvider(string(providerCfg.Type)) {
603+ parsed, err := openaicompat.ParseOptions(mergedOptions)
605+ options[openaicompat.Name] = parsed
613+func mergeCallOptions(model Model, cfg config.ProviderConfig) (fantasy.ProviderOptions, *float64, *float64, *int64, *float64, *float64) {
614+ modelOptions := getProviderOptions(model, cfg)
615+ temp := cmp.Or(model.ModelCfg.Temperature, model.CatwalkCfg.Options.Temperature)
616+ topP := cmp.Or(model.ModelCfg.TopP, model.CatwalkCfg.Options.TopP)
617+ topK := cmp.Or(model.ModelCfg.TopK, model.CatwalkCfg.Options.TopK)
618+ freqPenalty := cmp.Or(model.ModelCfg.FrequencyPenalty, model.CatwalkCfg.Options.FrequencyPenalty)
619+ presPenalty := cmp.Or(model.ModelCfg.PresencePenalty, model.CatwalkCfg.Options.PresencePenalty)
620+ return modelOptions, temp, topP, topK, freqPenalty, presPenalty
623+// cachedMergeCallOptions wraps mergeCallOptions with a memoization cache.
624+// The provider options JSON merge is expensive (3× marshal + merge +
625+// unmarshal) and the inputs rarely change between turns. The cache key
626+// combines the config pointer identity with the model's catwalk ID and
627+// provider name so any config reload or model switch misses the cache.
628+func (c *coordinator) cachedMergeCallOptions(model Model, cfg config.ProviderConfig) (fantasy.ProviderOptions, *float64, *float64, *int64, *float64, *float64) {
629+ key := fmt.Sprintf("%p|%s|%s", c.cfg.Config(), model.CatwalkCfg.ID, model.ModelCfg.Provider)
631+ c.providerOptsCacheMu.Lock()
632+ if c.providerOptsCacheKey == key {
633+ opts := c.providerOptsCache
634+ c.providerOptsCacheMu.Unlock()
635+ // Recompute the scalar overrides (cheap) since they don't need
636+ // the JSON merge — they're just cmp.Or calls.
637+ temp := cmp.Or(model.ModelCfg.Temperature, model.CatwalkCfg.Options.Temperature)
638+ topP := cmp.Or(model.ModelCfg.TopP, model.CatwalkCfg.Options.TopP)
639+ topK := cmp.Or(model.ModelCfg.TopK, model.CatwalkCfg.Options.TopK)
640+ freqPenalty := cmp.Or(model.ModelCfg.FrequencyPenalty, model.CatwalkCfg.Options.FrequencyPenalty)
641+ presPenalty := cmp.Or(model.ModelCfg.PresencePenalty, model.CatwalkCfg.Options.PresencePenalty)
642+ return opts, temp, topP, topK, freqPenalty, presPenalty
644+ c.providerOptsCacheMu.Unlock()
646+ opts, temp, topP, topK, freqPenalty, presPenalty := mergeCallOptions(model, cfg)
648+ c.providerOptsCacheMu.Lock()
649+ c.providerOptsCache = opts
650+ c.providerOptsCacheKey = key
651+ c.providerOptsCacheMu.Unlock()
653+ return opts, temp, topP, topK, freqPenalty, presPenalty
656+func (c *coordinator) buildAgent(ctx context.Context, prompt *prompt.Prompt, agent config.Agent, isSubAgent bool) (SessionAgent, error) {
657+ large, small, err := c.buildAgentModels(ctx, isSubAgent)
662+ largeProviderCfg, _ := c.cfg.Config().Providers.Get(large.ModelCfg.Provider)
663+ result := NewSessionAgent(SessionAgentOptions{
666+ SystemPromptPrefix: largeProviderCfg.SystemPromptPrefix,
668+ IsSubAgent: isSubAgent,
669+ DisableAutoSummarize: c.cfg.Config().Options.DisableAutoSummarize,
670+ IsYolo: c.permissions.SkipRequests(),
671+ Sessions: c.sessions,
672+ Messages: c.messages,
675+ RunComplete: c.runComplete,
678+ c.readyWg.Go(func() error {
679+ systemPrompt, err := prompt.Build(ctx, large.Model.Provider(), large.Model.Model(), c.cfg)
683+ result.SetSystemPrompt(systemPrompt)
687+ c.readyWg.Go(func() error {
688+ tools, err := c.buildTools(ctx, agent, isSubAgent)
692+ result.SetTools(tools)
699+func (c *coordinator) buildTools(ctx context.Context, agent config.Agent, isSubAgent bool) ([]fantasy.AgentTool, error) {
700+ var allTools []fantasy.AgentTool
701+ if slices.Contains(agent.AllowedTools, AgentToolName) {
702+ agentTool, err := c.agentTool(ctx)
706+ allTools = append(allTools, agentTool)
709+ if slices.Contains(agent.AllowedTools, tools.AgenticFetchToolName) {
710+ agenticFetchTool, err := c.agenticFetchTool(ctx, nil)
714+ allTools = append(allTools, agenticFetchTool)
717+ // Get the model name for the agent
719+ if modelCfg, ok := c.cfg.Config().Models[agent.Model]; ok {
720+ if model := c.cfg.Config().GetModel(modelCfg.Provider, modelCfg.Model); model != nil {
725+ logFile := filepath.Join(c.cfg.Config().Options.DataDirectory, "logs", "crush.log")
727+ // Build hook runner if PreToolUse hooks are configured.
728+ var hookRunner *hooks.Runner
729+ if preToolHooks := c.cfg.Config().Hooks[hooks.EventPreToolUse]; len(preToolHooks) > 0 {
730+ hookRunner = hooks.NewRunner(preToolHooks, c.cfg.WorkingDir(), c.cfg.WorkingDir())
735+ tools.NewBashTool(c.permissions, c.cfg.WorkingDir(), c.cfg.Config().Options.Attribution, modelID),
736+ tools.NewCrushInfoTool(c.cfg, c.lspManager, c.allSkills, c.activeSkills, c.skillTracker),
737+ tools.NewCrushLogsTool(logFile),
738+ tools.NewJobOutputTool(),
739+ tools.NewJobKillTool(),
740+ tools.NewDownloadTool(c.permissions, c.cfg.WorkingDir(), nil),
741+ tools.NewEditTool(c.lspManager, c.permissions, c.history, c.filetracker, c.cfg.WorkingDir()),
742+ tools.NewMultiEditTool(c.lspManager, c.permissions, c.history, c.filetracker, c.cfg.WorkingDir()),
743+ tools.NewFetchTool(c.permissions, c.cfg.WorkingDir(), nil),
744+ tools.NewGlobTool(c.cfg.WorkingDir(), c.cfg.Config().Tools.Glob),
745+ tools.NewGrepTool(c.cfg.WorkingDir(), c.cfg.Config().Tools.Grep),
746+ tools.NewLsTool(c.permissions, c.cfg.WorkingDir(), c.cfg.Config().Tools.Ls),
747+ tools.NewSourcegraphTool(nil),
748+ tools.NewTodosTool(c.sessions),
749+ tools.NewViewTool(c.lspManager, c.permissions, c.filetracker, c.skillTracker, c.cfg.WorkingDir(), c.cfg.Config().Options.SkillsPaths...),
750+ tools.NewWriteTool(c.lspManager, c.permissions, c.history, c.filetracker, c.cfg.WorkingDir()),
753+ // Add LSP tools if user has configured LSPs or auto_lsp is enabled (nil or true).
754+ if len(c.cfg.Config().LSP) > 0 || c.cfg.Config().Options.AutoLSP == nil || *c.cfg.Config().Options.AutoLSP {
755+ allTools = append(allTools, tools.NewDiagnosticsTool(c.lspManager), tools.NewReferencesTool(c.lspManager), tools.NewLSPRestartTool(c.lspManager))
758+ if len(c.cfg.Config().MCP) > 0 {
761+ tools.NewListMCPResourcesTool(c.cfg, c.permissions),
762+ tools.NewReadMCPResourceTool(c.cfg, c.permissions),
766+ var filteredTools []fantasy.AgentTool
767+ for _, tool := range allTools {
768+ if slices.Contains(agent.AllowedTools, tool.Info().Name) {
769+ filteredTools = append(filteredTools, tool)
773+ for _, tool := range tools.GetMCPTools(c.permissions, c.cfg, c.cfg.WorkingDir()) {
774+ if agent.AllowedMCP == nil {
775+ // No MCP restrictions
776+ filteredTools = append(filteredTools, tool)
779+ if len(agent.AllowedMCP) == 0 {
781+ slog.Debug("No MCPs allowed", "tool", tool.Name(), "agent", agent.Name)
785+ for mcp, tools := range agent.AllowedMCP {
786+ if mcp != tool.MCP() {
789+ if len(tools) == 0 || slices.Contains(tools, tool.MCPToolName()) {
790+ filteredTools = append(filteredTools, tool)
793+ slog.Debug("MCP not allowed", "tool", tool.Name(), "agent", agent.Name)
796+ slices.SortFunc(filteredTools, func(a, b fantasy.AgentTool) int {
797+ return strings.Compare(a.Info().Name, b.Info().Name)
800+ // Wrap tools with hook interception for the top-level agent only.
801+ // Sub-agents (the `agent` task tool, `agentic_fetch`, etc.) run
802+ // without hook interception to avoid firing the user's hook N times
803+ // per delegated turn. The top-level invocation of the sub-agent tool
804+ // itself is still wrapped from the coder's side.
805+ filteredTools = wrapToolsWithHooks(filteredTools, hookRunner, isSubAgent)
807+ return filteredTools, nil
810+// TODO: when we support multiple agents we need to change this so that we pass in the agent specific model config
811+func (c *coordinator) buildAgentModels(ctx context.Context, isSubAgent bool) (Model, Model, error) {
812+ largeModelCfg, ok := c.cfg.Config().Models[config.SelectedModelTypeLarge]
814+ return Model{}, Model{}, errLargeModelNotSelected
816+ smallModelCfg, ok := c.cfg.Config().Models[config.SelectedModelTypeSmall]
818+ return Model{}, Model{}, errSmallModelNotSelected
821+ largeProviderCfg, ok := c.cfg.Config().Providers.Get(largeModelCfg.Provider)
823+ return Model{}, Model{}, errLargeModelProviderNotConfigured
826+ largeProvider, err := c.buildProvider(largeProviderCfg, largeModelCfg, isSubAgent)
828+ return Model{}, Model{}, err
831+ smallProviderCfg, ok := c.cfg.Config().Providers.Get(smallModelCfg.Provider)
833+ return Model{}, Model{}, errSmallModelProviderNotConfigured
836+ smallProvider, err := c.buildProvider(smallProviderCfg, smallModelCfg, true)
838+ return Model{}, Model{}, err
841+ var largeCatwalkModel *catwalk.Model
842+ var smallCatwalkModel *catwalk.Model
844+ for _, m := range largeProviderCfg.Models {
845+ if m.ID == largeModelCfg.Model {
846+ largeCatwalkModel = &m
849+ for _, m := range smallProviderCfg.Models {
850+ if m.ID == smallModelCfg.Model {
851+ smallCatwalkModel = &m
855+ if largeCatwalkModel == nil {
856+ return Model{}, Model{}, errLargeModelNotFound
859+ if smallCatwalkModel == nil {
860+ return Model{}, Model{}, errSmallModelNotFound
863+ largeModelID := largeModelCfg.Model
864+ smallModelID := smallModelCfg.Model
866+ if largeModelCfg.Provider == openrouter.Name && isExactoSupported(largeModelID) {
867+ largeModelID += ":exacto"
870+ if smallModelCfg.Provider == openrouter.Name && isExactoSupported(smallModelID) {
871+ smallModelID += ":exacto"
874+ largeModel, err := largeProvider.LanguageModel(ctx, largeModelID)
876+ return Model{}, Model{}, err
878+ smallModel, err := smallProvider.LanguageModel(ctx, smallModelID)
880+ return Model{}, Model{}, err
885+ CatwalkCfg: *largeCatwalkModel,
886+ ModelCfg: largeModelCfg,
887+ FlatRate: largeProviderCfg.FlatRate,
890+ CatwalkCfg: *smallCatwalkModel,
891+ ModelCfg: smallModelCfg,
892+ FlatRate: smallProviderCfg.FlatRate,
896+func (c *coordinator) buildAnthropicProvider(baseURL, apiKey string, headers map[string]string, providerID string) (fantasy.Provider, error) {
897+ var opts []anthropic.Option
900+ case strings.HasPrefix(apiKey, "Bearer "):
901+ // NOTE: Prevent the SDK from picking up the API key from env.
902+ os.Setenv("ANTHROPIC_API_KEY", "")
903+ headers["Authorization"] = apiKey
904+ case providerID == string(catwalk.InferenceProviderMiniMax) || providerID == string(catwalk.InferenceProviderMiniMaxChina):
905+ // NOTE: Prevent the SDK from picking up the API key from env.
906+ os.Setenv("ANTHROPIC_API_KEY", "")
907+ headers["Authorization"] = "Bearer " + apiKey
910+ opts = append(opts, anthropic.WithAPIKey(apiKey))
913+ if len(headers) > 0 {
914+ opts = append(opts, anthropic.WithHeaders(headers))
918+ opts = append(opts, anthropic.WithBaseURL(baseURL))
921+ if c.cfg.Config().Options.Debug {
922+ httpClient := log.NewHTTPClient()
923+ opts = append(opts, anthropic.WithHTTPClient(httpClient))
925+ return anthropic.New(opts...)
928+func (c *coordinator) buildOpenaiProvider(baseURL, apiKey string, headers map[string]string) (fantasy.Provider, error) {
929+ opts := []openai.Option{
930+ openai.WithAPIKey(apiKey),
931+ openai.WithUseResponsesAPI(),
933+ if c.cfg.Config().Options.Debug {
934+ httpClient := log.NewHTTPClient()
935+ opts = append(opts, openai.WithHTTPClient(httpClient))
937+ if len(headers) > 0 {
938+ opts = append(opts, openai.WithHeaders(headers))
941+ opts = append(opts, openai.WithBaseURL(baseURL))
943+ return openai.New(opts...)
946+func (c *coordinator) buildOpenrouterProvider(_, apiKey string, headers map[string]string) (fantasy.Provider, error) {
947+ opts := []openrouter.Option{
948+ openrouter.WithAPIKey(apiKey),
950+ if c.cfg.Config().Options.Debug {
951+ httpClient := log.NewHTTPClient()
952+ opts = append(opts, openrouter.WithHTTPClient(httpClient))
954+ if len(headers) > 0 {
955+ opts = append(opts, openrouter.WithHeaders(headers))
957+ return openrouter.New(opts...)
960+func (c *coordinator) buildVercelProvider(_, apiKey string, headers map[string]string) (fantasy.Provider, error) {
961+ opts := []vercel.Option{
962+ vercel.WithAPIKey(apiKey),
964+ if c.cfg.Config().Options.Debug {
965+ httpClient := log.NewHTTPClient()
966+ opts = append(opts, vercel.WithHTTPClient(httpClient))
968+ if len(headers) > 0 {
969+ opts = append(opts, vercel.WithHeaders(headers))
971+ return vercel.New(opts...)
974+func (c *coordinator) buildOpenaiCompatProvider(baseURL, apiKey string, headers map[string]string, extraBody map[string]any, providerID string, isSubAgent bool) (fantasy.Provider, error) {
975+ opts := []openaicompat.Option{
976+ openaicompat.WithBaseURL(baseURL),
977+ openaicompat.WithAPIKey(apiKey),
980+ // Set HTTP client based on provider and debug mode.
981+ var httpClient *http.Client
983+ case string(catwalk.InferenceProviderCopilot):
986+ openaicompat.WithUseResponsesAPI(),
987+ openaicompat.WithResponsesAPIFunc(func(modelID string) bool {
988+ return copilotResponsesModels[modelID]
991+ httpClient = copilot.NewClient(isSubAgent, c.cfg.Config().Options.Debug)
993+ if httpClient == nil && c.cfg.Config().Options.Debug {
994+ httpClient = log.NewHTTPClient()
996+ if httpClient != nil {
997+ opts = append(opts, openaicompat.WithHTTPClient(httpClient))
1000+ if len(headers) > 0 {
1001+ opts = append(opts, openaicompat.WithHeaders(headers))
1004+ for extraKey, extraValue := range extraBody {
1005+ opts = append(opts, openaicompat.WithSDKOptions(openaisdk.WithJSONSet(extraKey, extraValue)))
1008+ return openaicompat.New(opts...)
1011+func (c *coordinator) buildAzureProvider(baseURL, apiKey string, headers map[string]string, options map[string]string) (fantasy.Provider, error) {
1012+ opts := []azure.Option{
1013+ azure.WithBaseURL(baseURL),
1014+ azure.WithAPIKey(apiKey),
1015+ azure.WithUseResponsesAPI(),
1017+ if c.cfg.Config().Options.Debug {
1018+ httpClient := log.NewHTTPClient()
1019+ opts = append(opts, azure.WithHTTPClient(httpClient))
1021+ if options == nil {
1022+ options = make(map[string]string)
1024+ if apiVersion, ok := options["apiVersion"]; ok {
1025+ opts = append(opts, azure.WithAPIVersion(apiVersion))
1027+ if len(headers) > 0 {
1028+ opts = append(opts, azure.WithHeaders(headers))
1031+ return azure.New(opts...)
1034+func (c *coordinator) buildBedrockProvider(apiKey string, headers map[string]string, providerID string) (fantasy.Provider, error) {
1035+ var opts []bedrock.Option
1036+ if c.cfg.Config().Options.Debug {
1037+ httpClient := log.NewHTTPClient()
1038+ opts = append(opts, bedrock.WithHTTPClient(httpClient))
1040+ if len(headers) > 0 {
1041+ opts = append(opts, bedrock.WithHeaders(headers))
1046+ opts = append(opts, bedrock.WithAPIKey(apiKey))
1047+ case os.Getenv("AWS_BEARER_TOKEN_BEDROCK") != "":
1048+ opts = append(opts, bedrock.WithAPIKey(os.Getenv("AWS_BEARER_TOKEN_BEDROCK")))
1050+ // Skip, let the SDK do authentication.
1053+ switch providerID {
1054+ case string(catwalk.InferenceProviderBedrockEurope):
1055+ opts = append(opts, bedrock.WithRegion("eu-west-1"))
1057+ opts = append(opts, bedrock.WithRegion("us-east-1"))
1060+ return bedrock.New(opts...)
1063+func (c *coordinator) buildGoogleProvider(baseURL, apiKey string, headers map[string]string) (fantasy.Provider, error) {
1064+ opts := []google.Option{
1065+ google.WithBaseURL(baseURL),
1066+ google.WithGeminiAPIKey(apiKey),
1068+ if c.cfg.Config().Options.Debug {
1069+ httpClient := log.NewHTTPClient()
1070+ opts = append(opts, google.WithHTTPClient(httpClient))
1072+ if len(headers) > 0 {
1073+ opts = append(opts, google.WithHeaders(headers))
1075+ return google.New(opts...)
1078+func (c *coordinator) buildGoogleVertexProvider(headers map[string]string, options map[string]string) (fantasy.Provider, error) {
1079+ opts := []google.Option{}
1080+ if c.cfg.Config().Options.Debug {
1081+ httpClient := log.NewHTTPClient()
1082+ opts = append(opts, google.WithHTTPClient(httpClient))
1084+ if len(headers) > 0 {
1085+ opts = append(opts, google.WithHeaders(headers))
1088+ project := options["project"]
1089+ location := options["location"]
1091+ opts = append(opts, google.WithVertex(project, location))
1093+ return google.New(opts...)
1096+func (c *coordinator) isAnthropicThinking(model config.SelectedModel) bool {
1100+ opts, err := anthropic.ParseOptions(model.ProviderOptions)
1101+ return err == nil && opts.Thinking != nil
1104+func (c *coordinator) buildProvider(providerCfg config.ProviderConfig, model config.SelectedModel, isSubAgent bool) (fantasy.Provider, error) {
1105+ headers := maps.Clone(providerCfg.ExtraHeaders)
1106+ if headers == nil {
1107+ headers = make(map[string]string)
1110+ // handle special headers for anthropic
1111+ if providerCfg.Type == anthropic.Name && c.isAnthropicThinking(model) {
1112+ if v, ok := headers["anthropic-beta"]; ok {
1113+ headers["anthropic-beta"] = v + ",interleaved-thinking-2025-05-14"
1115+ headers["anthropic-beta"] = "interleaved-thinking-2025-05-14"
1119+ apiKey, _ := c.cfg.Resolve(providerCfg.APIKey)
1120+ baseURL, _ := c.cfg.Resolve(providerCfg.BaseURL)
1122+ // Reuse a previously built client when nothing that affects it has
1123+ // changed, so the HTTP keep-alive pool survives across turns. The key
1124+ // is derived from the resolved inputs above (plus the debug flag); the
1125+ // per-provider adjustments inside the switch below are deterministic
1126+ // functions of these, so identical inputs always yield an identical
1128+ cacheKey := c.providerCacheKey(providerCfg, model, apiKey, baseURL, headers, isSubAgent)
1129+ if p, ok := c.providerClients.Get(cacheKey); ok {
1132+ provider, err := c.buildProviderUncached(providerCfg, model, apiKey, baseURL, headers, isSubAgent)
1136+ c.providerClients.Set(cacheKey, provider)
1137+ return provider, nil
1140+// providerCacheKey builds a stable key from every input buildProvider's
1141+// switch consumes, so any credential, endpoint, header, or option change
1142+// produces a distinct key (and thus a rebuilt client).
1143+func (c *coordinator) providerCacheKey(providerCfg config.ProviderConfig, model config.SelectedModel, apiKey, baseURL string, headers map[string]string, isSubAgent bool) string {
1144+ var b strings.Builder
1145+ b.WriteString(providerCfg.ID)
1147+ b.WriteString(string(providerCfg.Type))
1149+ // The opencode providers pick their client type from the model, so the
1150+ // model must participate in the key.
1151+ b.WriteString(model.Model)
1153+ b.WriteString(apiKey)
1155+ // Bedrock falls back to AWS_BEARER_TOKEN_BEDROCK when no apiKey is
1156+ // configured, and that token is baked into the built client. Fold it
1157+ // into the key so a rotated token rebuilds the client instead of
1158+ // reusing a stale one.
1159+ if apiKey == "" && providerCfg.Type == bedrock.Name {
1160+ b.WriteString(os.Getenv("AWS_BEARER_TOKEN_BEDROCK"))
1163+ b.WriteString(baseURL)
1165+ for _, k := range slices.Sorted(maps.Keys(headers)) {
1168+ b.WriteString(headers[k])
1172+ if extra, err := json.Marshal(providerCfg.ExtraBody); err == nil {
1176+ if extra, err := json.Marshal(providerCfg.ExtraParams); err == nil {
1183+ if c.cfg.Config().Options.Debug {
1189+func (c *coordinator) buildProviderUncached(providerCfg config.ProviderConfig, model config.SelectedModel, apiKey, baseURL string, headers map[string]string, isSubAgent bool) (fantasy.Provider, error) {
1190+ switch providerCfg.ID {
1191+ case string(catwalk.InferenceProviderOpenCodeGo), string(catwalk.InferenceProviderOpenCodeZen):
1192+ if opencodeMessagesModels[model.Model] {
1193+ baseURL = strings.TrimSuffix(baseURL, "/v1")
1194+ return c.buildAnthropicProvider(baseURL, apiKey, headers, providerCfg.ID)
1198+ switch providerCfg.Type {
1200+ return c.buildOpenaiProvider(baseURL, apiKey, headers)
1201+ case anthropic.Name:
1202+ return c.buildAnthropicProvider(baseURL, apiKey, headers, providerCfg.ID)
1203+ case openrouter.Name:
1204+ return c.buildOpenrouterProvider(baseURL, apiKey, headers)
1206+ return c.buildVercelProvider(baseURL, apiKey, headers)
1208+ return c.buildAzureProvider(baseURL, apiKey, headers, providerCfg.ExtraParams)
1210+ return c.buildBedrockProvider(apiKey, headers, providerCfg.ID)
1212+ return c.buildGoogleProvider(baseURL, apiKey, headers)
1213+ case "google-vertex":
1214+ return c.buildGoogleVertexProvider(headers, providerCfg.ExtraParams)
1215+ case openaicompat.Name, hyper.Name:
1216+ switch providerCfg.ID {
1218+ baseURL = hyper.BaseURL() + "/v1"
1219+ headers["x-crush-id"] = event.GetID()
1220+ case string(catwalk.InferenceProviderZAI):
1221+ if providerCfg.ExtraBody == nil {
1222+ providerCfg.ExtraBody = map[string]any{}
1224+ providerCfg.ExtraBody["tool_stream"] = true
1226+ return c.buildOpenaiCompatProvider(baseURL, apiKey, headers, providerCfg.ExtraBody, providerCfg.ID, isSubAgent)
1228+ // Known custom providers (litellm, ollama, omlx) are
1229+ // openai-compat under the hood.
1230+ if discover.IsKnownCustomProvider(string(providerCfg.Type)) {
1231+ return c.buildOpenaiCompatProvider(baseURL, apiKey, headers, providerCfg.ExtraBody, providerCfg.ID, isSubAgent)
1233+ return nil, fmt.Errorf("provider type not supported: %q", providerCfg.Type)
1237+func isExactoSupported(modelID string) bool {
1238+ supportedModels := []string{
1239+ "moonshotai/kimi-k2-0905",
1240+ "deepseek/deepseek-v3.1-terminus",
1242+ "openai/gpt-oss-120b",
1243+ "qwen/qwen3-coder",
1245+ return slices.Contains(supportedModels, modelID)
1248+// BeginAccepted reserves an accept slot for sessionID on the active
1249+// agent and returns the ownership handle. It is the fire-and-forget
1250+// dispatch path's only way to mark a run as accepted-but-not-yet-active
1251+// so a cancel arriving before the run registers in activeRequests is not
1253+func (c *coordinator) BeginAccepted(sessionID string) *AcceptedRun {
1254+ return c.currentAgent.BeginAccepted(sessionID)
1257+func (c *coordinator) Cancel(sessionID string) {
1258+ c.currentAgent.Cancel(sessionID)
1261+func (c *coordinator) CancelAll() {
1262+ c.currentAgent.CancelAll()
1265+func (c *coordinator) ClearQueue(sessionID string) {
1266+ c.currentAgent.ClearQueue(sessionID)
1269+func (c *coordinator) IsBusy() bool {
1270+ return c.currentAgent.IsBusy()
1273+func (c *coordinator) IsSessionBusy(sessionID string) bool {
1274+ return c.currentAgent.IsSessionBusy(sessionID)
1277+func (c *coordinator) Model() Model {
1278+ return c.currentAgent.Model()
1281+func (c *coordinator) UpdateModels(ctx context.Context) error {
1282+ // build the models again so we make sure we get the latest config
1283+ large, small, err := c.buildAgentModels(ctx, false)
1287+ c.currentAgent.SetModels(large, small)
1289+ cfg := c.cfg.Config()
1290+ agentCfg, ok := cfg.Agents[config.AgentCoder]
1292+ return errCoderAgentNotConfigured
1295+ // Fast path: reuse cached tools when neither the config nor the MCP
1296+ // tool set has changed since the last build.
1297+ mcpGen := c.mcpToolsGen.Load()
1298+ c.toolsCacheMu.Lock()
1299+ if c.toolsCache != nil && c.toolsCacheCfg == cfg && c.toolsCacheMCP == mcpGen {
1300+ c.currentAgent.SetTools(c.toolsCache)
1301+ c.toolsCacheMu.Unlock()
1304+ c.toolsCacheMu.Unlock()
1306+ tools, err := c.buildTools(ctx, agentCfg, false)
1311+ c.toolsCacheMu.Lock()
1312+ c.toolsCache = tools
1313+ c.toolsCacheCfg = cfg
1314+ c.toolsCacheMCP = mcpGen
1315+ c.toolsCacheMu.Unlock()
1317+ c.currentAgent.SetTools(tools)
1321+func (c *coordinator) QueuedPrompts(sessionID string) int {
1322+ return c.currentAgent.QueuedPrompts(sessionID)
1325+func (c *coordinator) QueuedPromptsList(sessionID string) []string {
1326+ return c.currentAgent.QueuedPromptsList(sessionID)
1329+func (c *coordinator) Summarize(ctx context.Context, sessionID string) error {
1330+ providerCfg, ok := c.cfg.Config().Providers.Get(c.currentAgent.Model().ModelCfg.Provider)
1332+ return errModelProviderNotConfigured
1335+ if err := c.refreshTokenIfExpired(ctx, providerCfg); err != nil {
1336+ slog.Error("Failed to refresh OAuth2 token before summarize. Proceeding with existing token.", "error", err)
1339+ summarize := func() error {
1340+ return c.currentAgent.Summarize(ctx, sessionID, getProviderOptions(c.currentAgent.Model(), providerCfg))
1343+ return c.runWithUnauthorizedRetry(ctx, providerCfg, summarize)
1346+// GenerateTitle generates a session title using the current agent.
1347+func (c *coordinator) GenerateTitle(ctx context.Context, sessionID, prompt string) {
1348+ if c.currentAgent == nil {
1351+ c.currentAgent.GenerateTitle(ctx, sessionID, prompt)
1354+// refreshTokenIfExpired proactively refreshes the OAuth token if it has expired.
1355+func (c *coordinator) refreshTokenIfExpired(ctx context.Context, providerCfg config.ProviderConfig) error {
1356+ if providerCfg.OAuthToken == nil || !providerCfg.OAuthToken.IsExpired() {
1359+ slog.Debug("Token needs to be refreshed", "provider", providerCfg.ID)
1360+ return c.refreshOAuth2Token(ctx, providerCfg)
1363+// runWithUnauthorizedRetry executes fn. If fn returns a 401 error, it
1364+// attempts to refresh credentials and re-runs fn once. Returns the
1365+// final error: from the retry if a retry was attempted, otherwise from
1366+// the original run. Callers that need to notify the user on persistent
1367+// failure should check isUnauthorized on the returned error.
1368+func (c *coordinator) runWithUnauthorizedRetry(ctx context.Context, providerCfg config.ProviderConfig, fn func() error) error {
1370+ if err != nil && c.isUnauthorized(err) {
1371+ if retryErr := c.retryAfterUnauthorized(ctx, providerCfg); retryErr == nil {
1378+// retryAfterUnauthorized attempts to refresh credentials after receiving a 401
1379+// and returns nil if retry should be attempted.
1380+func (c *coordinator) retryAfterUnauthorized(ctx context.Context, providerCfg config.ProviderConfig) error {
1382+ case providerCfg.OAuthToken != nil:
1383+ slog.Debug("Received 401. Refreshing token and retrying", "provider", providerCfg.ID)
1384+ return c.refreshOAuth2Token(ctx, providerCfg)
1385+ case strings.Contains(providerCfg.APIKeyTemplate, "$"):
1386+ slog.Debug("Received 401. Refreshing API Key template and retrying", "provider", providerCfg.ID)
1387+ return c.refreshApiKeyTemplate(ctx, providerCfg)
1393+func (c *coordinator) isUnauthorized(err error) bool {
1394+ var providerErr *fantasy.ProviderError
1395+ return errors.As(err, &providerErr) && providerErr.StatusCode == http.StatusUnauthorized
1398+func (c *coordinator) refreshOAuth2Token(ctx context.Context, providerCfg config.ProviderConfig) error {
1399+ if err := c.cfg.RefreshOAuthToken(ctx, config.ScopeGlobal, providerCfg.ID); err != nil {
1400+ slog.Error("Failed to refresh OAuth token after 401 error", "provider", providerCfg.ID, "error", err)
1403+ if err := c.UpdateModels(ctx); err != nil {
1409+func (c *coordinator) refreshApiKeyTemplate(ctx context.Context, providerCfg config.ProviderConfig) error {
1410+ newAPIKey, err := c.cfg.Resolve(providerCfg.APIKeyTemplate)
1412+ slog.Error("Failed to re-resolve API key after 401 error", "provider", providerCfg.ID, "error", err)
1416+ providerCfg.APIKey = newAPIKey
1417+ c.cfg.Config().Providers.Set(providerCfg.ID, providerCfg)
1419+ if err := c.UpdateModels(ctx); err != nil {
1425+// subAgentParams holds the parameters for running a sub-agent.
1426+type subAgentParams struct {
1429+ AgentMessageID string
1432+ SessionTitle string
1433+ // SessionSetup is an optional callback invoked after session creation
1434+ // but before agent execution, for custom session configuration.
1435+ SessionSetup func(sessionID string)
1438+// runSubAgent runs a sub-agent and handles session management and cost accumulation.
1439+// It creates a sub-session, runs the agent with the given prompt, and propagates
1440+// the cost to the parent session.
1441+func (c *coordinator) runSubAgent(ctx context.Context, params subAgentParams) (fantasy.ToolResponse, error) {
1442+ // Create sub-session
1443+ agentToolSessionID := c.sessions.CreateAgentToolSessionID(params.AgentMessageID, params.ToolCallID)
1444+ session, err := c.sessions.CreateTaskSession(ctx, agentToolSessionID, params.SessionID, params.SessionTitle)
1446+ return fantasy.ToolResponse{}, fmt.Errorf("create session: %w", err)
1449+ // Call session setup function if provided
1450+ if params.SessionSetup != nil {
1451+ params.SessionSetup(session.ID)
1454+ // Get model configuration
1455+ model := params.Agent.Model()
1456+ maxTokens := model.CatwalkCfg.DefaultMaxTokens
1457+ if model.ModelCfg.MaxTokens != 0 {
1458+ maxTokens = model.ModelCfg.MaxTokens
1461+ providerCfg, ok := c.cfg.Config().Providers.Get(model.ModelCfg.Provider)
1463+ return fantasy.ToolResponse{}, errModelProviderNotConfigured
1467+ run := func() (*fantasy.AgentResult, error) {
1468+ return params.Agent.Run(ctx, SessionAgentCall{
1469+ SessionID: session.ID,
1470+ Prompt: params.Prompt,
1471+ MaxOutputTokens: maxTokens,
1472+ ProviderOptions: getProviderOptions(model, providerCfg),
1473+ Temperature: model.ModelCfg.Temperature,
1474+ TopP: model.ModelCfg.TopP,
1475+ TopK: model.ModelCfg.TopK,
1476+ FrequencyPenalty: model.ModelCfg.FrequencyPenalty,
1477+ PresencePenalty: model.ModelCfg.PresencePenalty,
1478+ NonInteractive: true,
1481+ var result *fantasy.AgentResult
1482+ err = c.runWithUnauthorizedRetry(ctx, providerCfg, func() error {
1484+ result, runErr = run()
1487+ // Notify only if still unauthorized after retry.
1488+ if err != nil && c.isUnauthorized(err) && c.notify != nil && model.ModelCfg.Provider == hyper.Name {
1489+ c.notify.Publish(pubsub.CreatedEvent, notify.Notification{
1490+ Type: notify.TypeReAuthenticate,
1491+ ProviderID: model.ModelCfg.Provider,
1495+ return fantasy.NewTextErrorResponse(fmt.Sprintf("Failed to generate response: %s", err)), nil
1498+ // Update parent session cost on a best-effort basis. A failure here must
1499+ // not discard the sub-agent output that was already produced.
1500+ if err := c.updateParentSessionCost(ctx, session.ID, params.SessionID); err != nil {
1502+ "Failed to update parent session cost",
1503+ "child_session", session.ID,
1504+ "parent_session", params.SessionID,
1509+ output := subAgentOutput(result)
1511+ return fantasy.NewTextErrorResponse("Sub-agent completed but produced no text output."), nil
1513+ return fantasy.NewTextResponse(output), nil
1516+func subAgentOutput(result *fantasy.AgentResult) string {
1520+ return result.Response.Content.Text()
1523+// updateParentSessionCost accumulates the cost from a child session to its parent session.
1524+func (c *coordinator) updateParentSessionCost(ctx context.Context, childSessionID, parentSessionID string) error {
1525+ childSession, err := c.sessions.Get(ctx, childSessionID)
1527+ return fmt.Errorf("get child session: %w", err)
1530+ parentSession, err := c.sessions.Get(ctx, parentSessionID)
1532+ return fmt.Errorf("get parent session: %w", err)
1535+ parentSession.Cost += childSession.Cost
1537+ if _, err := c.sessions.Save(ctx, parentSession); err != nil {
1538+ return fmt.Errorf("save parent session: %w", err)
1544+// discoverSkills is a thin fallback wrapper used only when no
1545+// skills.Manager has been threaded through to the coordinator. All
1546+// production call sites (backend.CreateWorkspace, setupLocalWorkspace)
1547+// run discovery in advance and pass the results via the manager;
1548+// reaching this path means a caller bypassed both. It deliberately does
1549+// NOT publish to the package-level broker — there are no subscribers in
1550+// that case, so doing so would be misleading without delivering the
1551+// snapshot anywhere useful.
1552+func discoverSkills(cfg *config.ConfigStore) (allSkills, activeSkills []*skills.Skill) {
1553+ opts := cfg.Config().Options
1554+ var paths, disabled []string
1556+ paths = opts.SkillsPaths
1557+ disabled = opts.DisabledSkills
1559+ var resolver func(string) (string, error)
1560+ if r := cfg.Resolver(); r != nil {
1561+ resolver = r.ResolveValue
1563+ allSkills, activeSkills, states := skills.DiscoverFromConfig(skills.DiscoveryConfig{
1564+ SkillsPaths: paths,
1565+ DisabledSkills: disabled,
1566+ Resolver: resolver,
1568+ logDiscoveryStats(states, paths, allSkills, activeSkills, disabled)
1569+ return allSkills, activeSkills
1572+// logTurnSkillUsage emits a per-turn diagnostic line showing which skills
1573+// (if any) were loaded during this turn and which looked relevant based on
1574+// a cheap keyword match against the user prompt. The goal is to surface
1575+// "should-have-loaded but didn't" situations for later analysis.
1577+// Logged at Info level under component=skills; heavy fields are elided when
1578+// there is nothing interesting to report.
1579+func logTurnSkillUsage(
1582+ activeSkills []*skills.Skill,
1583+ tracker *skills.Tracker,
1586+ if tracker == nil || len(activeSkills) == 0 {
1590+ after := tracker.LoadedNames()
1592+ beforeSet := make(map[string]bool, len(before))
1593+ for _, n := range before {
1594+ beforeSet[n] = true
1596+ var loadedThisTurn []string
1597+ for _, n := range after {
1599+ loadedThisTurn = append(loadedThisTurn, n)
1604+ "Skill turn summary",
1605+ "component", "skills",
1606+ "session_id", sessionID,
1607+ "prompt_len", len(prompt),
1608+ "active_total", len(activeSkills),
1609+ "loaded_total", len(after),
1610+ "loaded_this_turn", loadedThisTurn,
1614+// logDiscoveryStats emits a single structured log line summarising skill
1615+// discovery for the current session. It is intentionally low-volume: one
1616+// line per session start. Builtin vs user counts are derived from the
1617+// SkillState.Path — builtin states use the "builtin/" embed prefix.
1618+func logDiscoveryStats(
1619+ states []*skills.SkillState,
1620+ userPaths []string,
1621+ allSkills, activeSkills []*skills.Skill,
1624+ var builtinOK, builtinErr, userOK, userErr int
1625+ for _, s := range states {
1626+ isBuiltin := strings.HasPrefix(s.Path, "builtin/")
1628+ case isBuiltin && s.State == skills.StateNormal:
1630+ case isBuiltin && s.State == skills.StateError:
1632+ case !isBuiltin && s.State == skills.StateNormal:
1634+ case !isBuiltin && s.State == skills.StateError:
1639+ activeNames := make([]string, 0, len(activeSkills))
1640+ for _, s := range activeSkills {
1641+ activeNames = append(activeNames, s.Name)
1644+ xml := skills.ToPromptXML(activeSkills)
1647+ "Skill discovery complete",
1648+ "component", "skills",
1649+ "builtin_ok", builtinOK,
1650+ "builtin_errors", builtinErr,
1652+ "user_errors", userErr,
1653+ "user_paths", len(userPaths),
1654+ "deduped_total", len(allSkills),
1655+ "active", len(activeSkills),
1656+ "disabled", len(disabled),
1657+ "prompt_bytes", len(xml),
1658+ "prompt_tok_est", skills.ApproxTokenCount(xml),
1659+ "active_names", activeNames,
internal/agent/coordinator_test.gonew file+554
@@ -0,0 +1,554 @@
8+ "charm.land/catwalk/pkg/catwalk"
10+ "charm.land/fantasy/providers/anthropic"
11+ "charm.land/fantasy/providers/bedrock"
12+ "charm.land/fantasy/providers/openaicompat"
13+ "github.com/charmbracelet/crush/internal/config"
14+ "github.com/stretchr/testify/assert"
15+ "github.com/stretchr/testify/require"
18+// mockSessionAgent is a minimal mock for the SessionAgent interface.
19+type mockSessionAgent struct {
21+ runFunc func(ctx context.Context, call SessionAgentCall) (*fantasy.AgentResult, error)
25+func (m *mockSessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy.AgentResult, error) {
26+ return m.runFunc(ctx, call)
29+func (m *mockSessionAgent) BeginAccepted(sessionID string) *AcceptedRun {
30+ return &AcceptedRun{sessionID: sessionID}
33+func (m *mockSessionAgent) Model() Model { return m.model }
34+func (m *mockSessionAgent) SetModels(large, small Model) {}
35+func (m *mockSessionAgent) SetTools(tools []fantasy.AgentTool) {}
36+func (m *mockSessionAgent) SetSystemPrompt(systemPrompt string) {}
37+func (m *mockSessionAgent) Cancel(sessionID string) {
38+ m.cancelled = append(m.cancelled, sessionID)
40+func (m *mockSessionAgent) CancelAll() {}
41+func (m *mockSessionAgent) IsSessionBusy(sessionID string) bool { return false }
42+func (m *mockSessionAgent) IsBusy() bool { return false }
43+func (m *mockSessionAgent) QueuedPrompts(sessionID string) int { return 0 }
44+func (m *mockSessionAgent) QueuedPromptsList(sessionID string) []string { return nil }
45+func (m *mockSessionAgent) ClearQueue(sessionID string) {}
46+func (m *mockSessionAgent) Summarize(context.Context, string, fantasy.ProviderOptions) error {
49+func (m *mockSessionAgent) GenerateTitle(context.Context, string, string) {}
51+// newTestCoordinator creates a minimal coordinator for unit testing runSubAgent.
52+func newTestCoordinator(t *testing.T, env fakeEnv, providerID string, providerCfg config.ProviderConfig) *coordinator {
53+ cfg, err := config.Init(env.workingDir, "", false)
54+ require.NoError(t, err)
55+ cfg.Config().Providers.Set(providerID, providerCfg)
58+ sessions: env.sessions,
59+ messages: env.messages,
63+// newMockAgent creates a mockSessionAgent with the given provider and run function.
64+func newMockAgent(providerID string, maxTokens int64, runFunc func(context.Context, SessionAgentCall) (*fantasy.AgentResult, error)) *mockSessionAgent {
65+ return &mockSessionAgent{
67+ CatwalkCfg: catwalk.Model{
68+ DefaultMaxTokens: maxTokens,
70+ ModelCfg: config.SelectedModel{
71+ Provider: providerID,
78+// agentResultWithText creates a minimal AgentResult with the given text response.
79+func agentResultWithText(text string) *fantasy.AgentResult {
80+ return &fantasy.AgentResult{
81+ Response: fantasy.Response{
82+ Content: fantasy.ResponseContent{
83+ fantasy.TextContent{Text: text},
89+func TestRunSubAgent(t *testing.T) {
90+ const providerID = "test-provider"
91+ providerCfg := config.ProviderConfig{ID: providerID}
93+ t.Run("happy path", func(t *testing.T) {
95+ coord := newTestCoordinator(t, env, providerID, providerCfg)
97+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
98+ require.NoError(t, err)
100+ agent := newMockAgent(providerID, 4096, func(_ context.Context, call SessionAgentCall) (*fantasy.AgentResult, error) {
101+ assert.Equal(t, "do something", call.Prompt)
102+ assert.Equal(t, int64(4096), call.MaxOutputTokens)
103+ return agentResultWithText("done"), nil
106+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
108+ SessionID: parentSession.ID,
109+ AgentMessageID: "msg-1",
110+ ToolCallID: "call-1",
111+ Prompt: "do something",
112+ SessionTitle: "Test Session",
114+ require.NoError(t, err)
115+ assert.Equal(t, "done", resp.Content)
116+ assert.False(t, resp.IsError)
119+ t.Run("cost update failure preserves output", func(t *testing.T) {
121+ coord := newTestCoordinator(t, env, providerID, providerCfg)
123+ agent := newMockAgent(providerID, 4096, func(_ context.Context, _ SessionAgentCall) (*fantasy.AgentResult, error) {
124+ return agentResultWithText("output before cost failure"), nil
127+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
129+ SessionID: "missing-parent-session",
130+ AgentMessageID: "msg-1",
131+ ToolCallID: "call-1",
133+ SessionTitle: "Test",
135+ require.NoError(t, err)
136+ assert.False(t, resp.IsError)
137+ assert.Equal(t, "output before cost failure", resp.Content)
140+ t.Run("response with text returns it", func(t *testing.T) {
142+ coord := newTestCoordinator(t, env, providerID, providerCfg)
144+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
145+ require.NoError(t, err)
147+ agent := newMockAgent(providerID, 4096, func(_ context.Context, _ SessionAgentCall) (*fantasy.AgentResult, error) {
148+ return agentResultWithText("the answer"), nil
151+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
153+ SessionID: parentSession.ID,
154+ AgentMessageID: "msg-1",
155+ ToolCallID: "call-1",
157+ SessionTitle: "Test",
159+ require.NoError(t, err)
160+ assert.False(t, resp.IsError)
161+ assert.Equal(t, "the answer", resp.Content)
164+ t.Run("nil result returns error response", func(t *testing.T) {
166+ coord := newTestCoordinator(t, env, providerID, providerCfg)
168+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
169+ require.NoError(t, err)
171+ agent := newMockAgent(providerID, 4096, func(_ context.Context, _ SessionAgentCall) (*fantasy.AgentResult, error) {
175+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
177+ SessionID: parentSession.ID,
178+ AgentMessageID: "msg-1",
179+ ToolCallID: "call-1",
181+ SessionTitle: "Test",
183+ require.NoError(t, err)
184+ assert.True(t, resp.IsError)
185+ assert.Equal(t, "Sub-agent completed but produced no text output.", resp.Content)
188+ t.Run("empty result returns error response", func(t *testing.T) {
190+ coord := newTestCoordinator(t, env, providerID, providerCfg)
192+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
193+ require.NoError(t, err)
195+ agent := newMockAgent(providerID, 4096, func(_ context.Context, _ SessionAgentCall) (*fantasy.AgentResult, error) {
196+ return &fantasy.AgentResult{}, nil
199+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
201+ SessionID: parentSession.ID,
202+ AgentMessageID: "msg-1",
203+ ToolCallID: "call-1",
205+ SessionTitle: "Test",
207+ require.NoError(t, err)
208+ assert.True(t, resp.IsError)
209+ assert.Equal(t, "Sub-agent completed but produced no text output.", resp.Content)
212+ t.Run("ModelCfg.MaxTokens overrides default", func(t *testing.T) {
214+ coord := newTestCoordinator(t, env, providerID, providerCfg)
216+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
217+ require.NoError(t, err)
219+ agent := &mockSessionAgent{
221+ CatwalkCfg: catwalk.Model{
222+ DefaultMaxTokens: 4096,
224+ ModelCfg: config.SelectedModel{
225+ Provider: providerID,
229+ runFunc: func(_ context.Context, call SessionAgentCall) (*fantasy.AgentResult, error) {
230+ assert.Equal(t, int64(8192), call.MaxOutputTokens)
231+ return agentResultWithText("ok"), nil
235+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
237+ SessionID: parentSession.ID,
238+ AgentMessageID: "msg-1",
239+ ToolCallID: "call-1",
241+ SessionTitle: "Test",
243+ require.NoError(t, err)
244+ assert.Equal(t, "ok", resp.Content)
247+ t.Run("session creation failure with canceled context", func(t *testing.T) {
249+ coord := newTestCoordinator(t, env, providerID, providerCfg)
251+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
252+ require.NoError(t, err)
254+ agent := newMockAgent(providerID, 4096, nil)
256+ // Use a canceled context to trigger CreateTaskSession failure.
257+ ctx, cancel := context.WithCancel(t.Context())
260+ _, err = coord.runSubAgent(ctx, subAgentParams{
262+ SessionID: parentSession.ID,
263+ AgentMessageID: "msg-1",
264+ ToolCallID: "call-1",
266+ SessionTitle: "Test",
268+ require.Error(t, err)
271+ t.Run("provider not configured", func(t *testing.T) {
273+ coord := newTestCoordinator(t, env, providerID, providerCfg)
275+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
276+ require.NoError(t, err)
278+ // Agent references a provider that doesn't exist in config.
279+ agent := newMockAgent("unknown-provider", 4096, nil)
281+ _, err = coord.runSubAgent(t.Context(), subAgentParams{
283+ SessionID: parentSession.ID,
284+ AgentMessageID: "msg-1",
285+ ToolCallID: "call-1",
287+ SessionTitle: "Test",
289+ require.Error(t, err)
290+ assert.Contains(t, err.Error(), "model provider not configured")
293+ t.Run("agent run error returns error response", func(t *testing.T) {
295+ coord := newTestCoordinator(t, env, providerID, providerCfg)
297+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
298+ require.NoError(t, err)
300+ agent := newMockAgent(providerID, 4096, func(_ context.Context, _ SessionAgentCall) (*fantasy.AgentResult, error) {
301+ return nil, errors.New("provider request failed")
304+ resp, err := coord.runSubAgent(t.Context(), subAgentParams{
306+ SessionID: parentSession.ID,
307+ AgentMessageID: "msg-1",
308+ ToolCallID: "call-1",
310+ SessionTitle: "Test",
312+ // runSubAgent returns (errorResponse, nil) when agent.Run fails — not a Go error.
313+ require.NoError(t, err)
314+ assert.True(t, resp.IsError)
315+ assert.Equal(t, "Failed to generate response: provider request failed", resp.Content)
318+ t.Run("session setup callback is invoked", func(t *testing.T) {
320+ coord := newTestCoordinator(t, env, providerID, providerCfg)
322+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
323+ require.NoError(t, err)
325+ var setupCalledWith string
326+ agent := newMockAgent(providerID, 4096, func(_ context.Context, _ SessionAgentCall) (*fantasy.AgentResult, error) {
327+ return agentResultWithText("ok"), nil
330+ _, err = coord.runSubAgent(t.Context(), subAgentParams{
332+ SessionID: parentSession.ID,
333+ AgentMessageID: "msg-1",
334+ ToolCallID: "call-1",
336+ SessionTitle: "Test",
337+ SessionSetup: func(sessionID string) {
338+ setupCalledWith = sessionID
341+ require.NoError(t, err)
342+ assert.NotEmpty(t, setupCalledWith, "SessionSetup should have been called")
345+ t.Run("cost propagation to parent session", func(t *testing.T) {
347+ coord := newTestCoordinator(t, env, providerID, providerCfg)
349+ parentSession, err := env.sessions.Create(t.Context(), "Parent")
350+ require.NoError(t, err)
352+ agent := newMockAgent(providerID, 4096, func(ctx context.Context, call SessionAgentCall) (*fantasy.AgentResult, error) {
353+ // Simulate the agent incurring cost by updating the child session.
354+ childSession, err := env.sessions.Get(ctx, call.SessionID)
358+ childSession.Cost = 0.05
359+ _, err = env.sessions.Save(ctx, childSession)
363+ return agentResultWithText("ok"), nil
366+ _, err = coord.runSubAgent(t.Context(), subAgentParams{
368+ SessionID: parentSession.ID,
369+ AgentMessageID: "msg-1",
370+ ToolCallID: "call-1",
372+ SessionTitle: "Test",
374+ require.NoError(t, err)
376+ updated, err := env.sessions.Get(t.Context(), parentSession.ID)
377+ require.NoError(t, err)
378+ assert.InDelta(t, 0.05, updated.Cost, 1e-9)
382+func TestUpdateParentSessionCost(t *testing.T) {
383+ t.Run("accumulates cost correctly", func(t *testing.T) {
385+ cfg, err := config.Init(env.workingDir, "", false)
386+ require.NoError(t, err)
387+ coord := &coordinator{cfg: cfg, sessions: env.sessions}
389+ parent, err := env.sessions.Create(t.Context(), "Parent")
390+ require.NoError(t, err)
392+ child, err := env.sessions.CreateTaskSession(t.Context(), "tool-1", parent.ID, "Child")
393+ require.NoError(t, err)
397+ _, err = env.sessions.Save(t.Context(), child)
398+ require.NoError(t, err)
400+ err = coord.updateParentSessionCost(t.Context(), child.ID, parent.ID)
401+ require.NoError(t, err)
403+ updated, err := env.sessions.Get(t.Context(), parent.ID)
404+ require.NoError(t, err)
405+ assert.InDelta(t, 0.10, updated.Cost, 1e-9)
408+ t.Run("accumulates multiple child costs", func(t *testing.T) {
410+ cfg, err := config.Init(env.workingDir, "", false)
411+ require.NoError(t, err)
412+ coord := &coordinator{cfg: cfg, sessions: env.sessions}
414+ parent, err := env.sessions.Create(t.Context(), "Parent")
415+ require.NoError(t, err)
417+ child1, err := env.sessions.CreateTaskSession(t.Context(), "tool-1", parent.ID, "Child1")
418+ require.NoError(t, err)
420+ _, err = env.sessions.Save(t.Context(), child1)
421+ require.NoError(t, err)
423+ child2, err := env.sessions.CreateTaskSession(t.Context(), "tool-2", parent.ID, "Child2")
424+ require.NoError(t, err)
426+ _, err = env.sessions.Save(t.Context(), child2)
427+ require.NoError(t, err)
429+ err = coord.updateParentSessionCost(t.Context(), child1.ID, parent.ID)
430+ require.NoError(t, err)
431+ err = coord.updateParentSessionCost(t.Context(), child2.ID, parent.ID)
432+ require.NoError(t, err)
434+ updated, err := env.sessions.Get(t.Context(), parent.ID)
435+ require.NoError(t, err)
436+ assert.InDelta(t, 0.08, updated.Cost, 1e-9)
439+ t.Run("child session not found", func(t *testing.T) {
441+ cfg, err := config.Init(env.workingDir, "", false)
442+ require.NoError(t, err)
443+ coord := &coordinator{cfg: cfg, sessions: env.sessions}
445+ parent, err := env.sessions.Create(t.Context(), "Parent")
446+ require.NoError(t, err)
448+ err = coord.updateParentSessionCost(t.Context(), "non-existent", parent.ID)
449+ require.Error(t, err)
450+ assert.Contains(t, err.Error(), "get child session")
453+ t.Run("parent session not found", func(t *testing.T) {
455+ cfg, err := config.Init(env.workingDir, "", false)
456+ require.NoError(t, err)
457+ coord := &coordinator{cfg: cfg, sessions: env.sessions}
459+ parent, err := env.sessions.Create(t.Context(), "Parent")
460+ require.NoError(t, err)
461+ child, err := env.sessions.CreateTaskSession(t.Context(), "tool-1", parent.ID, "Child")
462+ require.NoError(t, err)
464+ err = coord.updateParentSessionCost(t.Context(), child.ID, "non-existent")
465+ require.Error(t, err)
466+ assert.Contains(t, err.Error(), "get parent session")
469+ t.Run("zero cost handled correctly", func(t *testing.T) {
471+ cfg, err := config.Init(env.workingDir, "", false)
472+ require.NoError(t, err)
473+ coord := &coordinator{cfg: cfg, sessions: env.sessions}
475+ parent, err := env.sessions.Create(t.Context(), "Parent")
476+ require.NoError(t, err)
477+ child, err := env.sessions.CreateTaskSession(t.Context(), "tool-1", parent.ID, "Child")
478+ require.NoError(t, err)
480+ err = coord.updateParentSessionCost(t.Context(), child.ID, parent.ID)
481+ require.NoError(t, err)
483+ updated, err := env.sessions.Get(t.Context(), parent.ID)
484+ require.NoError(t, err)
485+ assert.InDelta(t, 0.0, updated.Cost, 1e-9)
489+func TestGetProviderOptionsReasoningEffort(t *testing.T) {
490+ // Bedrock is Fantasy's Anthropic under a different provider name; options
491+ // must land under anthropic.Name so the Anthropic language model picks them up.
494+ providerType catwalk.Type
496+ {"anthropic honors reasoning_effort", catwalk.Type(anthropic.Name)},
497+ {"bedrock honors reasoning_effort", catwalk.Type(bedrock.Name)},
499+ for _, tc := range tests {
500+ t.Run(tc.name, func(t *testing.T) {
502+ CatwalkCfg: catwalk.Model{
503+ ID: "claude-opus-4-7",
505+ ReasoningLevels: []string{"max"},
507+ ModelCfg: config.SelectedModel{
509+ ReasoningEffort: "max",
512+ providerCfg := config.ProviderConfig{ID: "test", Type: tc.providerType}
514+ opts := getProviderOptions(model, providerCfg)
516+ raw, ok := opts[anthropic.Name]
517+ require.True(t, ok, "options should be keyed under anthropic.Name for type %q", tc.providerType)
518+ parsed, ok := raw.(*anthropic.ProviderOptions)
520+ require.NotNil(t, parsed.Effort)
521+ assert.Equal(t, anthropic.Effort("max"), *parsed.Effort)
526+func TestGetProviderOptionsReasoningEffortFallback(t *testing.T) {
528+ CatwalkCfg: catwalk.Model{
531+ ReasoningLevels: []string{"high", "max"},
533+ ModelCfg: config.SelectedModel{
537+ providerCfg := config.ProviderConfig{
538+ ID: string(catwalk.InferenceProviderZAI),
539+ Type: openaicompat.Name,
542+ opts := getProviderOptions(model, providerCfg)
544+ raw, ok := opts[openaicompat.Name]
546+ parsed, ok := raw.(*openaicompat.ProviderOptions)
548+ require.NotNil(t, parsed.ReasoningEffort)
549+ assert.Equal(t, "high", string(*parsed.ReasoningEffort))
551+ thinking, ok := parsed.ExtraBody["thinking"].(map[string]any)
553+ assert.Equal(t, "enabled", thinking["type"])
internal/agent/dispatch_cancel_test.gonew file+447
@@ -0,0 +1,447 @@
11+ "github.com/charmbracelet/crush/internal/agent/notify"
12+ "github.com/charmbracelet/crush/internal/message"
13+ "github.com/charmbracelet/crush/internal/pubsub"
14+ "github.com/stretchr/testify/assert"
15+ "github.com/stretchr/testify/require"
18+// finishStreamModel is a minimal fantasy.LanguageModel that streams a
19+// single text part followed by a normal (FinishReasonStop) finish. It
20+// is enough to drive sessionAgent.Run through PrepareStep and a clean
21+// completion without a recorded provider cassette.
22+type finishStreamModel struct {
26+func (m *finishStreamModel) Provider() string { return "fake" }
27+func (m *finishStreamModel) Model() string { return "fake-model" }
29+func (m *finishStreamModel) Generate(ctx context.Context, call fantasy.Call) (*fantasy.Response, error) {
30+ return &fantasy.Response{
31+ Content: fantasy.ResponseContent{fantasy.TextContent{Text: m.text}},
32+ FinishReason: fantasy.FinishReasonStop,
36+func (m *finishStreamModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.StreamResponse, error) {
38+ return func(yield func(fantasy.StreamPart) bool) {
39+ if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextStart, ID: "1"}) {
42+ if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextDelta, ID: "1", Delta: text}) {
45+ if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextEnd, ID: "1"}) {
48+ yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeFinish, FinishReason: fantasy.FinishReasonStop})
52+func (m *finishStreamModel) GenerateObject(ctx context.Context, call fantasy.ObjectCall) (*fantasy.ObjectResponse, error) {
53+ return nil, errors.New("not implemented")
56+func (m *finishStreamModel) StreamObject(ctx context.Context, call fantasy.ObjectCall) (fantasy.ObjectStreamResponse, error) {
57+ return nil, errors.New("not implemented")
60+func newStreamTestAgent(t *testing.T) (*sessionAgent, fakeEnv) {
63+ model := &finishStreamModel{text: "done"}
64+ sa := testSessionAgent(env, model, model, "system").(*sessionAgent)
68+// TestCancel_ActiveAndAcceptedFiresBothBranches covers the case where a
69+// session is actively running (activeRequests set) AND a follow-up has
70+// been accepted (acceptedRuns > 0). A single Cancel must fire both: it
71+// invokes the active cancel func and records a pending cancel for the
72+// accepted follow-up.
73+func TestCancel_ActiveAndAcceptedFiresBothBranches(t *testing.T) {
75+ sa, _ := newCancelTestAgent(t)
78+ var activeCanceled atomic.Bool
79+ sa.activeRequests.Set(sid, func() { activeCanceled.Store(true) })
81+ accept := sa.BeginAccepted(sid)
86+ require.True(t, activeCanceled.Load(), "active cancel func must fire")
87+ require.True(t, sa.hasPendingCancel(sid), "accepted follow-up must record a pending cancel")
90+// TestRun_BusyWithPendingCancelTakesCancelOnEntry covers the busy-queue
91+// branch consulting pendingCancels: when the session is busy AND a
92+// cancel has been recorded for an accepted follow-up, Run must take the
93+// cancel-on-entry path (persist a canceled turn) instead of enqueueing
94+// the call behind the active run.
95+func TestRun_BusyWithPendingCancelTakesCancelOnEntry(t *testing.T) {
97+ sa, env := newCancelTestAgent(t)
99+ sess, err := env.sessions.Create(t.Context(), "session")
100+ require.NoError(t, err)
102+ // Make the session look busy: an earlier prompt is active.
103+ sa.activeRequests.Set(sess.ID, func() {})
105+ accept := sa.BeginAccepted(sess.ID)
106+ // A cancel arrives while this follow-up is accepted-but-not-active.
108+ require.True(t, sa.hasPendingCancel(sess.ID))
110+ result, err := sa.Run(t.Context(), SessionAgentCall{
112+ Prompt: "follow-up",
115+ require.NoError(t, err)
116+ require.Nil(t, result)
118+ // The follow-up was canceled on entry, not enqueued.
119+ require.Equal(t, 0, sa.QueuedPrompts(sess.ID),
120+ "cancel-on-entry must not enqueue the follow-up behind the active run")
121+ require.False(t, sa.hasPendingCancel(sess.ID), "pending cancel must be consumed")
122+ require.Equal(t, 0, sa.acceptedCount(sess.ID), "accept reservation must be released")
124+ msgs, err := env.messages.List(t.Context(), sess.ID)
125+ require.NoError(t, err)
126+ require.Len(t, msgs, 2)
127+ assert.Equal(t, message.User, msgs[0].Role)
128+ assert.Equal(t, message.Assistant, msgs[1].Role)
129+ assert.Equal(t, message.FinishReasonCanceled, msgs[1].FinishReason())
132+// TestRun_PrepareStepDrainSkipsQueuedOnPendingCancel verifies that the
133+// queue drain inside PrepareStep skips queued follow-up prompts when a
134+// cancel has been recorded for the session: the queued prompt must not
135+// be folded into the active turn as an extra user message.
136+func TestRun_PrepareStepDrainSkipsQueuedOnPendingCancel(t *testing.T) {
138+ sa, env := newStreamTestAgent(t)
140+ sess, err := env.sessions.Create(t.Context(), "session")
141+ require.NoError(t, err)
143+ // A follow-up prompt sits queued for the session.
144+ sa.enqueueCall(SessionAgentCall{SessionID: sess.ID, Prompt: "queued-followup"})
145+ // A cancel was recorded for the session while it sat in the queue.
146+ sa.cancelMark.Set(sess.ID, 1)
148+ result, err := sa.Run(t.Context(), SessionAgentCall{
152+ require.NoError(t, err)
153+ require.NotNil(t, result)
155+ // Only the main prompt produced a user message; the queued
156+ // follow-up was skipped, not folded into the turn.
157+ msgs, err := env.messages.List(t.Context(), sess.ID)
158+ require.NoError(t, err)
159+ var userMsgs []message.Message
160+ for _, m := range msgs {
161+ if m.Role == message.User {
162+ userMsgs = append(userMsgs, m)
165+ require.Len(t, userMsgs, 1, "queued follow-up must not create a user message")
166+ assert.Equal(t, "main", userMsgs[0].Content().String())
168+ // The queue was drained and the pending cancel consumed.
169+ require.Equal(t, 0, sa.QueuedPrompts(sess.ID))
170+ require.False(t, sa.hasPendingCancel(sess.ID))
173+// TestRun_NormalCompletionClearsStalePendingCancel verifies that a Run
174+// which completes normally clears any stale pending-cancel entry for the
175+// session, so it cannot catch a future run.
176+func TestRun_NormalCompletionClearsStalePendingCancel(t *testing.T) {
178+ sa, env := newStreamTestAgent(t)
180+ sess, err := env.sessions.Create(t.Context(), "session")
181+ require.NoError(t, err)
183+ // A stale cancel mark lingers (no queued work, no accepted run).
184+ sa.cancelMark.Set(sess.ID, 1)
186+ result, err := sa.Run(t.Context(), SessionAgentCall{
190+ require.NoError(t, err)
191+ require.NotNil(t, result)
193+ require.False(t, sa.hasPendingCancel(sess.ID),
194+ "normal completion must clear the stale pending cancel")
196+ msgs, err := env.messages.List(t.Context(), sess.ID)
197+ require.NoError(t, err)
198+ require.Len(t, msgs, 2)
199+ assert.Equal(t, message.Assistant, msgs[1].Role)
200+ assert.Equal(t, message.FinishReasonEndTurn, msgs[1].FinishReason())
203+// newCancelTestAgentWithRunComplete builds a DB-backed sessionAgent wired
204+// to a RunComplete broker so tests can observe the terminal event a
205+// RunID-bearing caller (e.g. `crush run`) blocks on.
206+func newCancelTestAgentWithRunComplete(t *testing.T) (*sessionAgent, fakeEnv, *pubsub.Broker[notify.RunComplete]) {
209+ broker := pubsub.NewBroker[notify.RunComplete]()
210+ t.Cleanup(broker.Shutdown)
211+ sa := NewSessionAgent(SessionAgentOptions{
212+ Sessions: env.sessions,
213+ Messages: env.messages,
214+ RunComplete: broker,
216+ return sa, env, broker
219+// TestRun_CancelOnEntryPublishesRunComplete covers the first review
220+// finding: the cancel-on-entry path returned before the streaming defer
221+// that publishes RunComplete was installed. A caller that dispatches a
222+// run with a RunID and blocks on RunComplete (ignoring message events,
223+// like `crush run`) would hang on an immediately-canceled accepted run.
224+// The cancel-on-entry path must publish a terminal RunComplete carrying
225+// the originating RunID.
226+func TestRun_CancelOnEntryPublishesRunComplete(t *testing.T) {
228+ sa, env, broker := newCancelTestAgentWithRunComplete(t)
230+ sess, err := env.sessions.Create(t.Context(), "session")
231+ require.NoError(t, err)
233+ ctx, cancel := context.WithCancel(t.Context())
235+ ch := broker.Subscribe(ctx)
237+ accept := sa.BeginAccepted(sess.ID)
238+ // A cancel arrives in the accepted-but-not-yet-active window.
240+ require.True(t, sa.hasPendingCancel(sess.ID))
242+ result, err := sa.Run(t.Context(), SessionAgentCall{
244+ RunID: "run-cancel-on-entry",
248+ require.NoError(t, err)
249+ require.Nil(t, result)
253+ assert.Equal(t, "run-cancel-on-entry", got.Payload.RunID,
254+ "RunComplete must echo the originating RunID")
255+ assert.Equal(t, sess.ID, got.Payload.SessionID)
256+ assert.True(t, got.Payload.Cancelled,
257+ "cancel-on-entry RunComplete must be marked cancelled")
258+ case <-time.After(2 * time.Second):
259+ t.Fatal("cancel-on-entry must publish RunComplete; a RunID caller would hang otherwise")
263+// TestCancel_TwoAcceptedBothObserveCancellation covers the second review
264+// finding: a single cancel with two accepted-not-yet-active prompts must
265+// cancel both. The cancel raises the session's high-water mark to the
266+// latest accept sequence, so every prompt accepted-but-not-yet-active at
267+// cancel time is covered and both take the cancel-on-entry path.
268+func TestCancel_TwoAcceptedBothObserveCancellation(t *testing.T) {
270+ sa, env := newCancelTestAgent(t)
272+ sess, err := env.sessions.Create(t.Context(), "session")
273+ require.NoError(t, err)
275+ // Two prompts are accepted-but-not-yet-active for the same session.
276+ accept1 := sa.BeginAccepted(sess.ID)
277+ accept2 := sa.BeginAccepted(sess.ID)
278+ require.Equal(t, 2, sa.acceptedCount(sess.ID))
280+ // A single cancel arrives before either becomes active.
282+ require.Equal(t, accept2.seq, sa.pendingCancelMark(sess.ID),
283+ "one cancel must mark every currently-accepted prompt as canceled")
284+ require.GreaterOrEqual(t, sa.pendingCancelMark(sess.ID), accept1.seq,
285+ "the mark must cover the earlier accepted prompt too")
287+ // Both prompts enter Run; each must take cancel-on-entry, not run.
288+ r1, err := sa.Run(t.Context(), SessionAgentCall{
293+ require.NoError(t, err)
296+ r2, err := sa.Run(t.Context(), SessionAgentCall{
301+ require.NoError(t, err)
304+ require.False(t, sa.hasPendingCancel(sess.ID),
305+ "both reserved units must be consumed")
306+ require.Equal(t, 0, sa.acceptedCount(sess.ID),
307+ "both accept reservations must be released")
309+ // Each canceled-on-entry turn writes a user + canceled assistant
310+ // message, and neither prompt was enqueued to run normally.
311+ require.Equal(t, 0, sa.QueuedPrompts(sess.ID),
312+ "neither accepted prompt may be enqueued to run normally")
313+ msgs, err := env.messages.List(t.Context(), sess.ID)
314+ require.NoError(t, err)
315+ require.Len(t, msgs, 4, "two canceled turns produce two user + two assistant messages")
317+ for _, m := range msgs {
318+ if m.Role == message.Assistant {
319+ assert.Equal(t, message.FinishReasonCanceled, m.FinishReason())
323+ require.Equal(t, 2, canceled, "both turns must finish canceled")
326+// TestRun_IdleCancelDoesNotPoisonNextPrompt covers the idle-cancel
327+// no-op guarantee end-to-end: an Escape on an idle session must not
328+// record a pending cancel that leaks into the next accepted prompt, which
329+// must run normally to completion.
330+func TestRun_IdleCancelDoesNotPoisonNextPrompt(t *testing.T) {
332+ sa, env := newStreamTestAgent(t)
334+ sess, err := env.sessions.Create(t.Context(), "session")
335+ require.NoError(t, err)
337+ // Idle Escape: no accepted run, no active request.
339+ require.False(t, sa.hasPendingCancel(sess.ID),
340+ "idle cancel must not record a pending cancel")
342+ // The next accepted prompt must run normally, not cancel on entry.
343+ accept := sa.BeginAccepted(sess.ID)
344+ result, err := sa.Run(t.Context(), SessionAgentCall{
349+ require.NoError(t, err)
350+ require.NotNil(t, result, "next prompt must run normally after an idle cancel")
352+ msgs, err := env.messages.List(t.Context(), sess.ID)
353+ require.NoError(t, err)
354+ require.Len(t, msgs, 2)
355+ assert.Equal(t, message.User, msgs[0].Role)
356+ assert.Equal(t, message.Assistant, msgs[1].Role)
357+ assert.Equal(t, message.FinishReasonEndTurn, msgs[1].FinishReason(),
358+ "the prompt must finish normally, not canceled")
361+// TestCancel_AcceptedAfterCancelIsNotPoisoned is the regression test for
362+// the reviewer's finding: a counted session-level pending cancel let a
363+// prompt accepted after the cancel enter Run first and consume a unit
364+// reserved for the earlier prompts. With a sequence high-water mark, a
365+// single cancel covers exactly the prompts accepted-but-not-yet-active at
366+// cancel time (A and B); a prompt accepted afterwards (C) gets a higher
367+// sequence and must run normally without consuming A or B's cancellation.
368+// C is run first to prove it neither cancels nor drains the mark, then A
369+// and B are run and must both cancel on entry.
370+func TestCancel_AcceptedAfterCancelIsNotPoisoned(t *testing.T) {
372+ sa, env := newStreamTestAgent(t)
374+ sess, err := env.sessions.Create(t.Context(), "session")
375+ require.NoError(t, err)
377+ // A and B are accepted-but-not-yet-active.
378+ acceptA := sa.BeginAccepted(sess.ID)
379+ acceptB := sa.BeginAccepted(sess.ID)
381+ // One cancel arrives covering both A and B.
383+ require.True(t, sa.hasPendingCancel(sess.ID))
384+ require.Equal(t, acceptB.seq, sa.pendingCancelMark(sess.ID),
385+ "the mark must cover every prompt accepted before the cancel")
387+ // C is accepted AFTER the cancel; its sequence is above the mark.
388+ acceptC := sa.BeginAccepted(sess.ID)
389+ require.Greater(t, acceptC.seq, sa.pendingCancelMark(sess.ID),
390+ "a prompt accepted after the cancel must not be covered by the mark")
392+ // Run C first. It must run normally to completion and must not
393+ // consume or clear the cancellation reserved for A and B.
394+ rc, err := sa.Run(t.Context(), SessionAgentCall{
399+ require.NoError(t, err)
400+ require.NotNil(t, rc, "C was accepted after the cancel and must run normally")
401+ require.True(t, sa.hasPendingCancel(sess.ID),
402+ "running C must not drain the cancellation reserved for A and B")
404+ // Now A and B run. Both were accepted before the cancel and must
405+ // take the cancel-on-entry path.
406+ ra, err := sa.Run(t.Context(), SessionAgentCall{
411+ require.NoError(t, err)
412+ require.Nil(t, ra, "A must cancel on entry, not run")
414+ rb, err := sa.Run(t.Context(), SessionAgentCall{
419+ require.NoError(t, err)
420+ require.Nil(t, rb, "B must cancel on entry, not run")
422+ require.False(t, sa.hasPendingCancel(sess.ID),
423+ "the mark clears once all covered handles are resolved")
424+ require.Equal(t, 0, sa.acceptedCount(sess.ID))
425+ require.Equal(t, 0, sa.QueuedPrompts(sess.ID),
426+ "neither A nor B may be enqueued to run normally")
428+ // C produced a normal turn; A and B each produced a canceled turn.
429+ msgs, err := env.messages.List(t.Context(), sess.ID)
430+ require.NoError(t, err)
431+ require.Len(t, msgs, 6, "C normal + A canceled + B canceled = 3 user + 3 assistant")
433+ var normal, canceled int
434+ for _, m := range msgs {
435+ if m.Role != message.Assistant {
438+ switch m.FinishReason() {
439+ case message.FinishReasonEndTurn:
441+ case message.FinishReasonCanceled:
445+ require.Equal(t, 1, normal, "only C finished normally")
446+ require.Equal(t, 2, canceled, "both A and B finished canceled")
internal/agent/errors.gonew file+10
@@ -0,0 +1,10 @@
6+ ErrRequestCancelled = errors.New("request canceled by user")
7+ ErrSessionBusy = errors.New("session is currently processing another request")
8+ ErrEmptyPrompt = errors.New("prompt is empty")
9+ ErrSessionMissing = errors.New("session id is missing")
internal/agent/event.gonew file+51
@@ -0,0 +1,51 @@
7+ "github.com/charmbracelet/crush/internal/event"
10+func (a *sessionAgent) eventPromptSent(sessionID string) {
12+ a.eventCommon(sessionID, a.largeModel.Get())...,
16+func (a *sessionAgent) eventPromptResponded(sessionID string, duration time.Duration) {
17+ event.PromptResponded(
19+ a.eventCommon(sessionID, a.largeModel.Get()),
20+ "prompt duration pretty", duration.String(),
21+ "prompt duration in seconds", int64(duration.Seconds()),
26+func (a *sessionAgent) eventTokensUsed(sessionID string, model Model, usage fantasy.Usage, cost float64) {
29+ a.eventCommon(sessionID, model),
30+ "input tokens", usage.InputTokens,
31+ "output tokens", usage.OutputTokens,
32+ "cache read tokens", usage.CacheReadTokens,
33+ "cache creation tokens", usage.CacheCreationTokens,
34+ "total tokens", usage.InputTokens+usage.OutputTokens+usage.CacheReadTokens+usage.CacheCreationTokens,
40+func (a *sessionAgent) eventCommon(sessionID string, model Model) []any {
44+ "session id", sessionID,
45+ "provider", m.Provider,
47+ "reasoning effort", m.ReasoningEffort,
48+ "thinking mode", m.Think,
49+ "yolo mode", a.isYolo,
internal/agent/hooked_tool.gonew file+142
@@ -0,0 +1,142 @@
10+ "github.com/charmbracelet/crush/internal/agent/tools"
11+ "github.com/charmbracelet/crush/internal/hooks"
12+ "github.com/charmbracelet/crush/internal/permission"
13+ "github.com/tidwall/sjson"
16+// hookedTool wraps a fantasy.AgentTool to run PreToolUse hooks before
17+// delegating to the inner tool.
18+type hookedTool struct {
19+ inner fantasy.AgentTool
23+func newHookedTool(inner fantasy.AgentTool, runner *hooks.Runner) *hookedTool {
24+ return &hookedTool{inner: inner, runner: runner}
27+// wrapToolsWithHooks returns a tool slice with each entry wrapped in a
28+// hookedTool. Returns the original slice unchanged when runner is nil or
29+// when isSubAgent is true — sub-agents never fire hooks, the top-level
30+// invocation of the sub-agent tool itself is wrapped on the caller's side.
31+func wrapToolsWithHooks(tools []fantasy.AgentTool, runner *hooks.Runner, isSubAgent bool) []fantasy.AgentTool {
32+ if runner == nil || isSubAgent {
35+ out := make([]fantasy.AgentTool, len(tools))
36+ for i, tool := range tools {
37+ out[i] = newHookedTool(tool, runner)
42+func (h *hookedTool) Info() fantasy.ToolInfo {
43+ return h.inner.Info()
46+func (h *hookedTool) ProviderOptions() fantasy.ProviderOptions {
47+ return h.inner.ProviderOptions()
50+func (h *hookedTool) SetProviderOptions(opts fantasy.ProviderOptions) {
51+ h.inner.SetProviderOptions(opts)
54+func (h *hookedTool) Run(ctx context.Context, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
55+ sessionID := tools.GetSessionFromContext(ctx)
56+ result, err := h.runner.Run(ctx, hooks.EventPreToolUse, sessionID, call.Name, call.Input)
58+ slog.Warn("Hook execution error, proceeding with tool call",
59+ "tool", call.Name, "error", err)
62+ if result.Decision == hooks.DecisionDeny || result.Halt {
63+ reason := fmt.Sprintf("Tool call blocked by hook. Reason: %s", result.Reason)
65+ reason = fmt.Sprintf("Turn halted by hook. Reason: %s", result.Reason)
67+ resp := fantasy.NewTextErrorResponse(reason)
68+ // Halt ends the whole turn; a plain deny only blocks this tool
69+ // call so the model can see the error and try something else.
70+ resp.StopTurn = result.Halt
71+ resp.Metadata = hookMetadataJSON(result)
75+ if result.UpdatedInput != "" {
76+ call.Input = result.UpdatedInput
79+ // An explicit allow from a hook pre-approves the permission prompt for
80+ // this tool call. Deny is already handled above; silence falls through
81+ // to the normal permission flow.
82+ if result.Decision == hooks.DecisionAllow {
83+ ctx = permission.WithHookApproval(ctx, call.ID)
86+ resp, err := h.inner.Run(ctx, call)
91+ if result.Context != "" {
92+ if resp.Content != "" {
95+ resp.Content += result.Context
98+ resp.Metadata = mergeHookMetadata(resp.Metadata, result)
102+// buildHookMetadata creates a HookMetadata from an AggregateResult.
103+func buildHookMetadata(result hooks.AggregateResult) hooks.HookMetadata {
104+ return hooks.HookMetadata{
105+ HookCount: result.HookCount,
106+ Decision: result.Decision.String(),
108+ Reason: result.Reason,
109+ InputRewrite: result.UpdatedInput != "",
110+ Hooks: result.Hooks,
114+// hookMetadataJSON builds a JSON string containing only the hook metadata.
115+func hookMetadataJSON(result hooks.AggregateResult) string {
116+ meta := buildHookMetadata(result)
117+ data, err := json.Marshal(meta)
121+ return `{"hook":` + string(data) + `}`
124+// mergeHookMetadata injects hook metadata into existing tool metadata.
125+func mergeHookMetadata(existing string, result hooks.AggregateResult) string {
126+ if result.HookCount == 0 {
129+ meta := buildHookMetadata(result)
130+ data, err := json.Marshal(meta)
137+ merged, err := sjson.SetRaw(existing, "hook", string(data))
internal/agent/hooked_tool_test.gonew file+147
@@ -0,0 +1,147 @@
8+ "github.com/charmbracelet/crush/internal/config"
9+ "github.com/charmbracelet/crush/internal/hooks"
10+ "github.com/charmbracelet/crush/internal/permission"
11+ "github.com/stretchr/testify/require"
14+// fakeTool records the context it was invoked with so tests can assert on
15+// values stamped onto it by the hookedTool decorator.
16+type fakeTool struct {
19+ gotCtx context.Context
20+ resp fantasy.ToolResponse
23+func (f *fakeTool) Info() fantasy.ToolInfo {
24+ return fantasy.ToolInfo{Name: f.name}
27+func (f *fakeTool) Run(ctx context.Context, _ fantasy.ToolCall) (fantasy.ToolResponse, error) {
33+func (f *fakeTool) ProviderOptions() fantasy.ProviderOptions { return nil }
34+func (f *fakeTool) SetProviderOptions(_ fantasy.ProviderOptions) {}
36+// newRunner builds a hooks.Runner from a single HookConfig, running the
37+// config-loader path that compiles the matcher regex.
38+func newRunner(t *testing.T, cmd string) *hooks.Runner {
40+ cfg := &config.Config{
41+ Hooks: map[string][]config.HookConfig{
42+ hooks.EventPreToolUse: {{Command: cmd}},
45+ require.NoError(t, cfg.ValidateHooks())
46+ return hooks.NewRunner(cfg.Hooks[hooks.EventPreToolUse], t.TempDir(), t.TempDir())
49+func TestHookedTool_AllowStampsHookApproval(t *testing.T) {
52+ inner := &fakeTool{name: "view", resp: fantasy.NewTextResponse("ok")}
53+ runner := newRunner(t, `echo '{"decision":"allow"}'`)
54+ tool := newHookedTool(inner, runner)
56+ _, err := tool.Run(t.Context(), fantasy.ToolCall{ID: "call-1", Name: "view"})
57+ require.NoError(t, err)
58+ require.True(t, inner.called, "inner tool should have run")
60+ // The inner tool's permission service can now treat call-1 as pre-approved.
61+ svc := permission.NewPermissionService(t.TempDir(), false, nil)
62+ granted, err := svc.Request(inner.gotCtx, permission.CreatePermissionRequest{
64+ ToolCallID: "call-1",
69+ require.NoError(t, err)
70+ require.True(t, granted, "hook allow should bypass the permission prompt")
73+func TestHookedTool_SilentDoesNotStampApproval(t *testing.T) {
76+ inner := &fakeTool{name: "view", resp: fantasy.NewTextResponse("ok")}
77+ runner := newRunner(t, `exit 0`) // no stdout, no decision
78+ tool := newHookedTool(inner, runner)
80+ _, err := tool.Run(t.Context(), fantasy.ToolCall{ID: "call-2", Name: "view"})
81+ require.NoError(t, err)
82+ require.True(t, inner.called)
84+ // With no hook opinion, a fresh permission request has nothing stamped
85+ // and must fall through to the normal flow. We verify by checking that
86+ // the context does not look pre-approved for this call ID: sending a
87+ // request that no subscriber resolves will block until cancelled.
88+ svc := permission.NewPermissionService(t.TempDir(), false, nil)
89+ ctx, cancel := context.WithCancel(inner.gotCtx)
91+ granted, err := svc.Request(ctx, permission.CreatePermissionRequest{
93+ ToolCallID: "call-2",
98+ require.Error(t, err, "no approval stamped => request should reach the prompt path")
99+ require.False(t, granted)
102+func TestHookedTool_DenySkipsInnerTool(t *testing.T) {
105+ inner := &fakeTool{name: "bash"}
106+ runner := newRunner(t, `echo "blocked" >&2; exit 2`)
107+ tool := newHookedTool(inner, runner)
109+ resp, err := tool.Run(t.Context(), fantasy.ToolCall{ID: "call-3", Name: "bash"})
110+ require.NoError(t, err)
111+ require.False(t, inner.called, "denied call must not reach the inner tool")
112+ require.True(t, resp.IsError)
113+ require.Contains(t, resp.Content, "blocked")
116+func TestWrapToolsWithHooks(t *testing.T) {
119+ runner := newRunner(t, `exit 0`)
120+ inputs := []fantasy.AgentTool{&fakeTool{name: "a"}, &fakeTool{name: "b"}}
122+ t.Run("top-level agent wraps every tool", func(t *testing.T) {
124+ out := wrapToolsWithHooks(inputs, runner, false)
125+ require.Len(t, out, len(inputs))
126+ for i, tool := range out {
127+ _, ok := tool.(*hookedTool)
128+ require.Truef(t, ok, "tool %d should be a *hookedTool", i)
132+ t.Run("sub-agent skips the wrap", func(t *testing.T) {
134+ out := wrapToolsWithHooks(inputs, runner, true)
135+ require.Equal(t, inputs, out, "sub-agent tools should be returned unwrapped")
136+ for _, tool := range out {
137+ _, isHooked := tool.(*hookedTool)
138+ require.False(t, isHooked, "sub-agent tool should not be wrapped")
142+ t.Run("nil runner skips the wrap for both agent kinds", func(t *testing.T) {
144+ require.Equal(t, inputs, wrapToolsWithHooks(inputs, nil, false))
145+ require.Equal(t, inputs, wrapToolsWithHooks(inputs, nil, true))
internal/agent/hyper/provider.gonew file+105
@@ -0,0 +1,105 @@
1+// Package hyper provides a fantasy.Provider that proxies requests to Hyper.
17+ "charm.land/catwalk/pkg/catwalk"
20+//go:generate wget -O provider.json https://hyper.charm.land/v1/provider
22+//go:embed provider.json
25+// Embedded returns the embedded Hyper provider.
26+var Embedded = sync.OnceValue(func() catwalk.Provider {
27+ var provider catwalk.Provider
28+ if err := json.Unmarshal(embedded, &provider); err != nil {
29+ slog.Error("Could not use embedded provider data", "err", err)
31+ if e := os.Getenv("HYPER_URL"); e != "" {
32+ provider.APIEndpoint = e + "/api/v1/fantasy"
38+ // Name is the default name of this meta provider.
40+ // DisplayName is the display name of Hyper.
41+ DisplayName = "Charm Hyper"
42+ // defaultBaseURL is the default proxy URL.
43+ defaultBaseURL = "https://hyper.charm.land"
46+// BaseURL returns the base URL, which is either $HYPER_URL or the default.
47+var BaseURL = sync.OnceValue(func() string {
48+ return cmp.Or(os.Getenv("HYPER_URL"), defaultBaseURL)
51+// lastKnownBalance stores the most recently extracted hypercredit balance
52+// from API response metadata. FetchCredits checks this before making a
53+// separate HTTP call.
54+var lastKnownBalance atomic.Int64
56+// hasBalance tracks whether lastKnownBalance has been set.
57+var hasBalance atomic.Bool
59+// SetBalance stores a credit balance extracted from API response metadata.
60+func SetBalance(balance int) {
61+ lastKnownBalance.Store(int64(balance))
62+ hasBalance.Store(true)
65+// FetchCredits returns the remaining hypercredit balance. It first checks
66+// for a balance extracted from the most recent API response's usage
67+// metadata. If none is available, it falls back to calling the /v1/credits
69+func FetchCredits(ctx context.Context, apiKey string) (int, error) {
70+ if hasBalance.Load() {
71+ hasBalance.Store(false)
72+ return int(lastKnownBalance.Load()), nil
75+ req, err := http.NewRequestWithContext(
78+ BaseURL()+"/v1/credits",
82+ return 0, fmt.Errorf("could not create request: %w", err)
84+ req.Header.Set("Authorization", "Bearer "+apiKey)
86+ client := &http.Client{Timeout: 10 * time.Second}
87+ resp, err := client.Do(req)
89+ return 0, fmt.Errorf("failed to make request: %w", err)
91+ defer resp.Body.Close()
93+ if resp.StatusCode != http.StatusOK {
94+ return 0, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
98+ Balance int `json:"balance"`
100+ if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
101+ return 0, fmt.Errorf("failed to decode response: %w", err)
104+ return result.Balance, nil
internal/agent/hyper/provider.jsonnew file+295
@@ -0,0 +1,295 @@
2+ "name": "Charm Hyper",
4+ "api_endpoint": "https://hyper.charm.land/api/v1/fantasy",
6+ "default_large_model_id": "qwen3.7-plus",
7+ "default_small_model_id": "deepseek-v4-flash",
10+ "id": "deepseek-v4-flash",
11+ "name": "DeepSeek V4 Flash",
12+ "cost_per_1m_in": 0.14,
13+ "cost_per_1m_out": 0.28,
14+ "cost_per_1m_in_cached": 0.0028,
15+ "cost_per_1m_out_cached": 0,
16+ "context_window": 1000000,
17+ "default_max_tokens": 384000,
19+ "reasoning_levels": [
23+ "default_reasoning_effort": "high",
24+ "supports_attachments": false
27+ "id": "deepseek-v4-pro",
28+ "name": "DeepSeek V4 Pro",
29+ "cost_per_1m_in": 0.435,
30+ "cost_per_1m_out": 0.87,
31+ "cost_per_1m_in_cached": 0.0036,
32+ "cost_per_1m_out_cached": 0,
33+ "context_window": 1000000,
34+ "default_max_tokens": 384000,
36+ "reasoning_levels": [
40+ "default_reasoning_effort": "high",
41+ "supports_attachments": false
44+ "id": "gemma-4-26b-a4b-it",
45+ "name": "Gemma 4 26B A4B",
46+ "cost_per_1m_in": 0.126,
47+ "cost_per_1m_out": 0.42,
48+ "cost_per_1m_in_cached": 0.063,
49+ "cost_per_1m_out_cached": 0,
50+ "context_window": 256000,
51+ "default_max_tokens": 25600,
53+ "supports_attachments": false
58+ "cost_per_1m_in": 0.86,
59+ "cost_per_1m_out": 2.784,
60+ "cost_per_1m_in_cached": 0.43,
61+ "cost_per_1m_out_cached": 0,
62+ "context_window": 202752,
63+ "default_max_tokens": 20275,
65+ "supports_attachments": false
70+ "cost_per_1m_in": 1.3,
71+ "cost_per_1m_out": 4.3,
72+ "cost_per_1m_in_cached": 0.26,
73+ "cost_per_1m_out_cached": 0,
74+ "context_window": 202000,
75+ "default_max_tokens": 202000,
77+ "reasoning_levels": [
82+ "default_reasoning_effort": "medium",
83+ "supports_attachments": false
88+ "cost_per_1m_in": 1.5,
89+ "cost_per_1m_out": 4.5,
90+ "cost_per_1m_in_cached": 0.3,
91+ "cost_per_1m_out_cached": 0,
92+ "context_window": 1000000,
93+ "default_max_tokens": 128000,
95+ "reasoning_levels": [
99+ "default_reasoning_effort": "high",
100+ "supports_attachments": false
103+ "id": "gpt-oss-120b",
104+ "name": "gpt-oss-120b",
105+ "cost_per_1m_in": 0.168,
106+ "cost_per_1m_out": 0.562,
107+ "cost_per_1m_in_cached": 0.084,
108+ "cost_per_1m_out_cached": 0,
109+ "context_window": 131072,
110+ "default_max_tokens": 13107,
112+ "reasoning_levels": [
117+ "default_reasoning_effort": "medium",
118+ "supports_attachments": false
122+ "name": "Kimi K2.5",
123+ "cost_per_1m_in": 0.51,
124+ "cost_per_1m_out": 2.67,
125+ "cost_per_1m_in_cached": 0.255,
126+ "cost_per_1m_out_cached": 0,
127+ "context_window": 262144,
128+ "default_max_tokens": 26214,
130+ "supports_attachments": false
134+ "name": "Kimi K2.6",
135+ "cost_per_1m_in": 0.95,
136+ "cost_per_1m_out": 4,
137+ "cost_per_1m_in_cached": 0.16,
138+ "cost_per_1m_out_cached": 0,
139+ "context_window": 262000,
140+ "default_max_tokens": 262000,
142+ "reasoning_levels": [
147+ "default_reasoning_effort": "medium",
148+ "supports_attachments": true
151+ "id": "kimi-k2.7-code",
152+ "name": "Kimi K2.7 Code",
153+ "cost_per_1m_in": 0.95,
154+ "cost_per_1m_out": 4,
155+ "cost_per_1m_in_cached": 0.19,
156+ "cost_per_1m_out_cached": 0,
157+ "context_window": 256000,
158+ "default_max_tokens": 32768,
160+ "reasoning_levels": [
165+ "default_reasoning_effort": "medium",
166+ "supports_attachments": true
169+ "id": "llama-3.3-70b-instruct",
170+ "name": "Llama 3.3 70B Instruct",
171+ "cost_per_1m_in": 0.6066,
172+ "cost_per_1m_out": 1.0386,
173+ "cost_per_1m_in_cached": 0.3033,
174+ "cost_per_1m_out_cached": 0,
175+ "context_window": 128000,
176+ "default_max_tokens": 12800,
178+ "supports_attachments": false
181+ "id": "llama-4-maverick-17b-128e-instruct-fp8",
182+ "name": "Llama 4 Maverick 17B 128E Instruct FP8",
183+ "cost_per_1m_in": 0.274,
184+ "cost_per_1m_out": 0.894,
185+ "cost_per_1m_in_cached": 0.137,
186+ "cost_per_1m_out_cached": 0,
187+ "context_window": 430000,
188+ "default_max_tokens": 43000,
190+ "supports_attachments": false
193+ "id": "minimax-m2.7",
194+ "name": "MiniMax M2.7",
195+ "cost_per_1m_in": 0.3,
196+ "cost_per_1m_out": 1.2,
197+ "cost_per_1m_in_cached": 0.06,
198+ "cost_per_1m_out_cached": 0.375,
199+ "context_window": 204800,
200+ "default_max_tokens": 131000,
202+ "reasoning_levels": [
207+ "default_reasoning_effort": "medium",
208+ "supports_attachments": false
211+ "id": "qwen3.6-flash",
212+ "name": "Qwen3.6-Flash",
213+ "cost_per_1m_in": 1,
214+ "cost_per_1m_out": 4,
215+ "cost_per_1m_in_cached": 1.25,
216+ "cost_per_1m_out_cached": 0.1,
217+ "context_window": 1000000,
218+ "default_max_tokens": 64000,
220+ "supports_attachments": true
223+ "id": "qwen3.6-max",
224+ "name": "Qwen3.6-Max",
225+ "cost_per_1m_in": 2,
226+ "cost_per_1m_out": 12,
227+ "cost_per_1m_in_cached": 2.5,
228+ "cost_per_1m_out_cached": 0.2,
229+ "context_window": 256000,
230+ "default_max_tokens": 64000,
232+ "supports_attachments": false
235+ "id": "qwen3.6-plus",
236+ "name": "Qwen3.6-Plus",
237+ "cost_per_1m_in": 2,
238+ "cost_per_1m_out": 6,
239+ "cost_per_1m_in_cached": 2.5,
240+ "cost_per_1m_out_cached": 0.2,
241+ "context_window": 1000000,
242+ "default_max_tokens": 64000,
244+ "supports_attachments": true
247+ "id": "qwen3.7-max",
248+ "name": "Qwen3.7-Max",
249+ "cost_per_1m_in": 2.5,
250+ "cost_per_1m_out": 7.5,
251+ "cost_per_1m_in_cached": 3.125,
252+ "cost_per_1m_out_cached": 0.25,
253+ "context_window": 1000000,
254+ "default_max_tokens": 64000,
256+ "supports_attachments": false
259+ "id": "qwen3.7-plus",
260+ "name": "Qwen3.7-Plus",
261+ "cost_per_1m_in": 1.2,
262+ "cost_per_1m_out": 4.8,
263+ "cost_per_1m_in_cached": 1.5,
264+ "cost_per_1m_out_cached": 0.12,
265+ "context_window": 1000000,
266+ "default_max_tokens": 64000,
268+ "supports_attachments": true
271+ "id": "qwen3-coder-480b-a35b-instruct-int4-mixed-ar",
272+ "name": "Qwen3 Coder 480B A35B Instruct INT4 Mixed AR",
273+ "cost_per_1m_in": 0.557,
274+ "cost_per_1m_out": 2.545,
275+ "cost_per_1m_in_cached": 0.2785,
276+ "cost_per_1m_out_cached": 0,
277+ "context_window": 106000,
278+ "default_max_tokens": 10600,
279+ "can_reason": false,
280+ "supports_attachments": false
283+ "id": "qwen3-next-80b-a3b-instruct",
284+ "name": "Qwen3 Next 80B A3B Instruct",
285+ "cost_per_1m_in": 0.128,
286+ "cost_per_1m_out": 1.28,
287+ "cost_per_1m_in_cached": 0.064,
288+ "cost_per_1m_out_cached": 0,
289+ "context_window": 262144,
290+ "default_max_tokens": 26214,
291+ "can_reason": false,
292+ "supports_attachments": false
internal/agent/loop_detection.gonew file+92
@@ -0,0 +1,92 @@
11+ loopDetectionWindowSize = 10
12+ loopDetectionMaxRepeats = 5
15+// hasRepeatedToolCalls checks whether the agent is stuck in a loop by looking
16+// at recent steps. It examines the last windowSize steps and returns true if
17+// any tool-call signature appears more than maxRepeats times.
18+func hasRepeatedToolCalls(steps []fantasy.StepResult, windowSize, maxRepeats int) bool {
19+ if len(steps) < windowSize {
23+ window := steps[len(steps)-windowSize:]
24+ counts := make(map[uint64]int, windowSize)
26+ for _, step := range window {
27+ sig := getToolInteractionSignature(step.Content)
32+ if counts[sig] > maxRepeats {
40+// getToolInteractionSignature computes a hash signature for the tool
41+// interactions in a single step's content. It pairs tool calls with their
42+// results (matched by ToolCallID) and returns an FNV-1a hash. FNV is ~10x
43+// faster than SHA-256 and collision risk is negligible for loop detection
44+// over a 10-step window. If the step contains no tool calls, it returns 0.
45+func getToolInteractionSignature(content fantasy.ResponseContent) uint64 {
46+ toolCalls := content.ToolCalls()
47+ if len(toolCalls) == 0 {
51+ // Index tool results by their ToolCallID for fast lookup.
52+ resultsByID := make(map[string]fantasy.ToolResultContent, len(toolCalls))
53+ for _, tr := range content.ToolResults() {
54+ resultsByID[tr.ToolCallID] = tr
58+ for _, tc := range toolCalls {
60+ if tr, ok := resultsByID[tc.ToolCallID]; ok {
61+ output = toolResultOutputString(tr.Result)
63+ _, _ = io.WriteString(h, tc.ToolName)
65+ _, _ = io.WriteString(h, tc.Input)
67+ _, _ = io.WriteString(h, output)
73+// toolResultOutputString converts a ToolResultOutputContent to a stable string
74+// representation for signature comparison.
75+func toolResultOutputString(result fantasy.ToolResultOutputContent) string {
79+ if text, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](result); ok {
82+ if errResult, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](result); ok {
83+ if errResult.Error != nil {
84+ return errResult.Error.Error()
88+ if media, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentMedia](result); ok {
internal/agent/loop_detection_test.gonew file+205
@@ -0,0 +1,205 @@
10+// makeStep creates a StepResult with the given tool calls and results in its Content.
11+func makeStep(calls []fantasy.ToolCallContent, results []fantasy.ToolResultContent) fantasy.StepResult {
12+ var content fantasy.ResponseContent
13+ for _, c := range calls {
14+ content = append(content, c)
16+ for _, r := range results {
17+ content = append(content, r)
19+ return fantasy.StepResult{
20+ Response: fantasy.Response{
26+// makeToolStep creates a step with a single tool call and matching text result.
27+func makeToolStep(name, input, output string) fantasy.StepResult {
28+ callID := fmt.Sprintf("call_%s_%s", name, input)
30+ []fantasy.ToolCallContent{
31+ {ToolCallID: callID, ToolName: name, Input: input},
33+ []fantasy.ToolResultContent{
34+ {ToolCallID: callID, ToolName: name, Result: fantasy.ToolResultOutputContentText{Text: output}},
39+// makeEmptyStep creates a step with no tool calls (e.g. a text-only response).
40+func makeEmptyStep() fantasy.StepResult {
41+ return fantasy.StepResult{
42+ Response: fantasy.Response{
43+ Content: fantasy.ResponseContent{
44+ fantasy.TextContent{Text: "thinking..."},
50+func TestHasRepeatedToolCalls(t *testing.T) {
51+ t.Run("no steps", func(t *testing.T) {
52+ result := hasRepeatedToolCalls(nil, 10, 5)
54+ t.Error("expected false for empty steps")
58+ t.Run("fewer steps than window", func(t *testing.T) {
59+ steps := make([]fantasy.StepResult, 5)
60+ for i := range steps {
61+ steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
63+ result := hasRepeatedToolCalls(steps, 10, 5)
65+ t.Error("expected false when fewer steps than window size")
69+ t.Run("all different signatures", func(t *testing.T) {
70+ steps := make([]fantasy.StepResult, 10)
71+ for i := range steps {
72+ steps[i] = makeToolStep("tool", fmt.Sprintf(`{"i":%d}`, i), fmt.Sprintf("result-%d", i))
74+ result := hasRepeatedToolCalls(steps, 10, 5)
76+ t.Error("expected false when all signatures are different")
80+ t.Run("exact repeat at threshold not detected", func(t *testing.T) {
81+ // maxRepeats=5 means > 5 is needed, so exactly 5 should return false
82+ steps := make([]fantasy.StepResult, 10)
84+ steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
86+ for i := 5; i < 10; i++ {
87+ steps[i] = makeToolStep("tool", fmt.Sprintf(`{"i":%d}`, i), fmt.Sprintf("result-%d", i))
89+ result := hasRepeatedToolCalls(steps, 10, 5)
91+ t.Error("expected false when count equals maxRepeats (threshold is >)")
95+ t.Run("loop detected", func(t *testing.T) {
96+ // 6 identical steps in a window of 10 with maxRepeats=5 → detected
97+ steps := make([]fantasy.StepResult, 10)
99+ steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
101+ for i := 6; i < 10; i++ {
102+ steps[i] = makeToolStep("tool", fmt.Sprintf(`{"i":%d}`, i), fmt.Sprintf("result-%d", i))
104+ result := hasRepeatedToolCalls(steps, 10, 5)
106+ t.Error("expected true when same signature appears more than maxRepeats times")
110+ t.Run("steps without tool calls are skipped", func(t *testing.T) {
111+ // Mix of tool steps and empty steps — empty ones should not affect counts
112+ steps := make([]fantasy.StepResult, 10)
114+ steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
116+ for i := 4; i < 8; i++ {
117+ steps[i] = makeEmptyStep()
119+ for i := 8; i < 10; i++ {
120+ steps[i] = makeToolStep("write", `{"file":"b.go"}`, "ok")
122+ result := hasRepeatedToolCalls(steps, 10, 5)
124+ t.Error("expected false: only 4 repeated tool calls, empty steps should be skipped")
128+ t.Run("multiple different patterns alternating", func(t *testing.T) {
129+ // Two patterns alternating: each appears 5 times — not above threshold
130+ steps := make([]fantasy.StepResult, 10)
131+ for i := range steps {
133+ steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content-a")
135+ steps[i] = makeToolStep("write", `{"file":"b.go"}`, "content-b")
138+ result := hasRepeatedToolCalls(steps, 10, 5)
140+ t.Error("expected false: two patterns each appearing 5 times (not > 5)")
145+func TestGetToolInteractionSignature(t *testing.T) {
146+ t.Run("empty content returns empty string", func(t *testing.T) {
147+ sig := getToolInteractionSignature(fantasy.ResponseContent{})
149+ t.Errorf("expected zero signature, got %d", sig)
153+ t.Run("text only content returns zero signature", func(t *testing.T) {
154+ content := fantasy.ResponseContent{
155+ fantasy.TextContent{Text: "hello"},
157+ sig := getToolInteractionSignature(content)
159+ t.Errorf("expected zero signature, got %d", sig)
163+ t.Run("tool call with result produces signature", func(t *testing.T) {
164+ content := fantasy.ResponseContent{
165+ fantasy.ToolCallContent{ToolCallID: "1", ToolName: "read", Input: `{"file":"a.go"}`},
166+ fantasy.ToolResultContent{ToolCallID: "1", ToolName: "read", Result: fantasy.ToolResultOutputContentText{Text: "content"}},
168+ sig := getToolInteractionSignature(content)
170+ t.Error("expected non-zero signature")
174+ t.Run("same interactions produce same signature", func(t *testing.T) {
175+ content1 := fantasy.ResponseContent{
176+ fantasy.ToolCallContent{ToolCallID: "1", ToolName: "read", Input: `{"file":"a.go"}`},
177+ fantasy.ToolResultContent{ToolCallID: "1", ToolName: "read", Result: fantasy.ToolResultOutputContentText{Text: "content"}},
179+ content2 := fantasy.ResponseContent{
180+ fantasy.ToolCallContent{ToolCallID: "2", ToolName: "read", Input: `{"file":"a.go"}`},
181+ fantasy.ToolResultContent{ToolCallID: "2", ToolName: "read", Result: fantasy.ToolResultOutputContentText{Text: "content"}},
183+ sig1 := getToolInteractionSignature(content1)
184+ sig2 := getToolInteractionSignature(content2)
186+ t.Errorf("expected same signature for same interactions, got %d and %d", sig1, sig2)
190+ t.Run("different inputs produce different signatures", func(t *testing.T) {
191+ content1 := fantasy.ResponseContent{
192+ fantasy.ToolCallContent{ToolCallID: "1", ToolName: "read", Input: `{"file":"a.go"}`},
193+ fantasy.ToolResultContent{ToolCallID: "1", ToolName: "read", Result: fantasy.ToolResultOutputContentText{Text: "content"}},
195+ content2 := fantasy.ResponseContent{
196+ fantasy.ToolCallContent{ToolCallID: "1", ToolName: "read", Input: `{"file":"b.go"}`},
197+ fantasy.ToolResultContent{ToolCallID: "1", ToolName: "read", Result: fantasy.ToolResultOutputContentText{Text: "content"}},
199+ sig1 := getToolInteractionSignature(content1)
200+ sig2 := getToolInteractionSignature(content2)
202+ t.Error("expected different signatures for different inputs")
internal/agent/notify/notify.gonew file+63
@@ -0,0 +1,63 @@
1+// Package notify defines domain notification types for agent events.
2+// These types are decoupled from UI concerns so the agent can publish
3+// events without importing UI packages.
6+// Type identifies the kind of agent notification.
10+ // TypeAgentFinished indicates the agent has completed its turn.
11+ TypeAgentFinished Type = "agent_finished"
12+ // TypeReAuthenticate indicates the agent encountered an
13+ // authentication error and the user needs to re-authenticate.
14+ TypeReAuthenticate Type = "re_authenticate"
15+ // TypeAgentError indicates the agent's turn terminated with an
16+ // error. The error text is carried in Notification.Message.
17+ TypeAgentError Type = "error"
20+// Notification represents a domain event published by the agent.
21+type Notification struct {
26+ // RunID, when non-empty, is the caller-supplied correlator
27+ // (proto.AgentMessage.RunID) for the run that produced this
28+ // notification. It lets observers attribute a TypeAgentError to a
29+ // specific request rather than to any in-flight run on the
30+ // session. Empty when no caller set one.
32+ // Message carries the error text for TypeAgentError. Other
33+ // notification types ignore it.
37+// RunComplete is the authoritative end-of-run signal for a session.
38+// It is published exactly once per top-level agent run (per
39+// [sessionAgent.Run] invocation that actually executed) after all
40+// message updates for the turn have been flushed via
41+// message.Service.FlushAll. Carries the final assistant text and
42+// message ID so non-interactive clients can reconcile stdout even if
43+// SSE events arrive out of order or are dropped by the broker. Error
44+// is non-empty when the run terminated with an error; Cancelled is
45+// true when the run terminated due to context cancellation. The two
46+// are mutually exclusive in the success case but may overlap when a
47+// cancel triggers a downstream error.
49+// RunID identifies the specific request that produced this event.
50+// It is the value the caller set on `proto.AgentMessage.RunID` (or
51+// equivalently propagated via agent.WithRunID on the context that
52+// reaches the coordinator); empty when no caller set one. Filtering
53+// by RunID lets a client correlate a SendMessage call with its
54+// terminal event even when the session is busy and other turns are
55+// finishing on the same session.
56+type RunComplete struct {
internal/agent/prompt/prompt.gonew file+294
@@ -0,0 +1,294 @@
15+ "github.com/charmbracelet/crush/internal/config"
16+ "github.com/charmbracelet/crush/internal/filepathext"
17+ "github.com/charmbracelet/crush/internal/home"
18+ "github.com/charmbracelet/crush/internal/shell"
19+ "github.com/charmbracelet/crush/internal/skills"
22+// Prompt represents a template-based prompt generator.
31+type PromptDat struct {
40+ ContextFiles []ContextFile
41+ GlobalContextFiles []ContextFile
45+type ContextFile struct {
50+type Option func(*Prompt)
52+func WithTimeFunc(fn func() time.Time) Option {
53+ return func(p *Prompt) {
58+func WithPlatform(platform string) Option {
59+ return func(p *Prompt) {
60+ p.platform = platform
64+func WithWorkingDir(workingDir string) Option {
65+ return func(p *Prompt) {
66+ p.workingDir = workingDir
70+func NewPrompt(name, promptTemplate string, opts ...Option) (*Prompt, error) {
73+ template: promptTemplate,
76+ for _, opt := range opts {
82+func (p *Prompt) Build(ctx context.Context, provider, model string, store *config.ConfigStore) (string, error) {
83+ t, err := template.New(p.name).Parse(p.template)
85+ return "", fmt.Errorf("parsing template: %w", err)
87+ var sb strings.Builder
88+ d, err := p.promptData(ctx, provider, model, store)
92+ if err := t.Execute(&sb, d); err != nil {
93+ return "", fmt.Errorf("executing template: %w", err)
96+ return sb.String(), nil
99+func processFile(filePath string) *ContextFile {
100+ content, err := os.ReadFile(filePath)
104+ return &ContextFile{
106+ Content: string(content),
110+func processContextPath(p string, store *config.ConfigStore) []ContextFile {
111+ var contexts []ContextFile
112+ fullPath := filepathext.SmartJoin(store.WorkingDir(), p)
113+ info, err := os.Stat(fullPath)
118+ _ = filepath.WalkDir(fullPath, func(path string, d os.DirEntry, err error) error {
123+ if result := processFile(path); result != nil {
124+ contexts = append(contexts, *result)
130+ result := processFile(fullPath)
132+ contexts = append(contexts, *result)
138+// expandPath expands ~ and environment variables in file paths
139+func expandPath(path string, store *config.ConfigStore) string {
140+ path = home.Long(path)
141+ // Handle environment variable expansion using the same pattern as config
142+ if strings.HasPrefix(path, "$") {
143+ if expanded, err := store.Resolver().ResolveValue(path); err == nil {
151+// loadContextFiles loads and deduplicates context files from a list of paths.
152+func loadContextFiles(paths []string, store *config.ConfigStore) map[string][]ContextFile {
153+ files := map[string][]ContextFile{}
154+ for _, pth := range paths {
155+ expanded := expandPath(pth, store)
156+ pathKey := strings.ToLower(expanded)
157+ if _, ok := files[pathKey]; ok {
160+ files[pathKey] = processContextPath(expanded, store)
165+func (p *Prompt) promptData(ctx context.Context, provider, model string, store *config.ConfigStore) (PromptDat, error) {
166+ workingDir := cmp.Or(p.workingDir, store.WorkingDir())
167+ platform := cmp.Or(p.platform, runtime.GOOS)
169+ cfg := store.Config()
170+ contextFiles := loadContextFiles(cfg.Options.ContextPaths, store)
171+ globalContextFiles := loadContextFiles(cfg.Options.GlobalContextPaths, store)
173+ // Discover and load skills metadata.
174+ var availSkillXML string
176+ // Start with builtin skills.
177+ allSkills := skills.DiscoverBuiltin()
178+ builtinNames := make(map[string]bool, len(allSkills))
179+ for _, s := range allSkills {
180+ builtinNames[s.Name] = true
183+ // Discover user skills from configured paths.
184+ if len(cfg.Options.SkillsPaths) > 0 {
185+ expandedPaths := make([]string, 0, len(cfg.Options.SkillsPaths))
186+ for _, pth := range cfg.Options.SkillsPaths {
187+ expandedPaths = append(expandedPaths, expandPath(pth, store))
189+ for _, userSkill := range skills.Discover(expandedPaths) {
190+ if builtinNames[userSkill.Name] {
191+ slog.Warn("User skill overrides builtin skill", "name", userSkill.Name)
193+ allSkills = append(allSkills, userSkill)
197+ // Deduplicate: user skills override builtins with the same name.
198+ allSkills = skills.Deduplicate(allSkills)
200+ // Filter out disabled skills.
201+ allSkills = skills.Filter(allSkills, cfg.Options.DisabledSkills)
203+ if len(allSkills) > 0 {
204+ availSkillXML = skills.ToPromptXML(allSkills)
207+ isGit := isGitRepo(store.WorkingDir())
212+ WorkingDir: filepath.ToSlash(workingDir),
215+ Date: p.now().Format("1/2/2006"),
216+ AvailSkillXML: availSkillXML,
220+ data.GitStatus, err = getGitStatus(ctx, store.WorkingDir())
222+ return PromptDat{}, err
226+ for _, files := range contextFiles {
227+ data.ContextFiles = append(data.ContextFiles, files...)
229+ for _, files := range globalContextFiles {
230+ data.GlobalContextFiles = append(data.GlobalContextFiles, files...)
235+func isGitRepo(dir string) bool {
236+ _, err := os.Stat(filepath.Join(dir, ".git"))
240+func getGitStatus(ctx context.Context, dir string) (string, error) {
241+ sh := shell.NewShell(&shell.Options{
244+ branch, err := getGitBranch(ctx, sh)
248+ status, err := getGitStatusSummary(ctx, sh)
252+ commits, err := getGitRecentCommits(ctx, sh)
256+ return branch + status + commits, nil
259+func getGitBranch(ctx context.Context, sh *shell.Shell) (string, error) {
260+ out, _, err := sh.Exec(ctx, "git branch --show-current 2>/dev/null")
264+ out = strings.TrimSpace(out)
268+ return fmt.Sprintf("Current branch: %s\n", out), nil
271+func getGitStatusSummary(ctx context.Context, sh *shell.Shell) (string, error) {
272+ out, _, err := sh.Exec(ctx, "git status --short 2>/dev/null | head -20")
276+ out = strings.TrimSpace(out)
278+ return "Status: clean\n", nil
280+ return fmt.Sprintf("Status:\n%s\n", out), nil
283+func getGitRecentCommits(ctx context.Context, sh *shell.Shell) (string, error) {
284+ out, _, err := sh.Exec(ctx, "git log --oneline -n 3 2>/dev/null")
285+ if err != nil || out == "" {
288+ out = strings.TrimSpace(out)
289+ return fmt.Sprintf("Recent commits:\n%s\n", out), nil
292+func (p *Prompt) Name() string {
internal/agent/prompts.gonew file+42
@@ -0,0 +1,42 @@
7+ "github.com/charmbracelet/crush/internal/agent/prompt"
8+ "github.com/charmbracelet/crush/internal/config"
11+//go:embed templates/coder.md.tpl
12+var coderPromptTmpl []byte
14+//go:embed templates/task.md.tpl
15+var taskPromptTmpl []byte
17+//go:embed templates/initialize.md.tpl
18+var initializePromptTmpl []byte
20+func coderPrompt(opts ...prompt.Option) (*prompt.Prompt, error) {
21+ systemPrompt, err := prompt.NewPrompt("coder", string(coderPromptTmpl), opts...)
25+ return systemPrompt, nil
28+func taskPrompt(opts ...prompt.Option) (*prompt.Prompt, error) {
29+ systemPrompt, err := prompt.NewPrompt("task", string(taskPromptTmpl), opts...)
33+ return systemPrompt, nil
36+func InitializePrompt(cfg *config.ConfigStore) (string, error) {
37+ systemPrompt, err := prompt.NewPrompt("initialize", string(initializePromptTmpl))
41+ return systemPrompt.Build(context.Background(), "", "", cfg)
internal/agent/queued_runid_test.gonew file+181
@@ -0,0 +1,181 @@
10+ "charm.land/catwalk/pkg/catwalk"
12+ "github.com/charmbracelet/crush/internal/agent/notify"
13+ "github.com/charmbracelet/crush/internal/message"
14+ "github.com/charmbracelet/crush/internal/pubsub"
15+ "github.com/stretchr/testify/require"
18+// gatedStreamModel streams a single text part followed by a clean finish,
19+// but blocks the very first Stream call until its gate is released. That
20+// lets a test hold a run "active" (past PrepareStep, inside Stream) just
21+// long enough to enqueue a follow-up prompt behind the busy session.
22+// Subsequent Stream calls (e.g. the recursive run draining the queue)
23+// proceed immediately.
24+type gatedStreamModel struct {
27+ entered chan struct{}
31+func (m *gatedStreamModel) Provider() string { return "fake" }
32+func (m *gatedStreamModel) Model() string { return "fake-model" }
34+func (m *gatedStreamModel) Generate(ctx context.Context, call fantasy.Call) (*fantasy.Response, error) {
35+ return &fantasy.Response{
36+ Content: fantasy.ResponseContent{fantasy.TextContent{Text: m.text}},
37+ FinishReason: fantasy.FinishReasonStop,
41+func (m *gatedStreamModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.StreamResponse, error) {
42+ if m.calls.Add(1) == 1 {
50+ return func(yield func(fantasy.StreamPart) bool) {
51+ if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextStart, ID: "1"}) {
54+ if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextDelta, ID: "1", Delta: text}) {
57+ if !yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeTextEnd, ID: "1"}) {
60+ yield(fantasy.StreamPart{Type: fantasy.StreamPartTypeFinish, FinishReason: fantasy.FinishReasonStop})
64+func (m *gatedStreamModel) GenerateObject(ctx context.Context, call fantasy.ObjectCall) (*fantasy.ObjectResponse, error) {
65+ return nil, errors.New("not implemented")
68+func (m *gatedStreamModel) StreamObject(ctx context.Context, call fantasy.ObjectCall) (fantasy.ObjectStreamResponse, error) {
69+ return nil, errors.New("not implemented")
72+// TestRun_QueuedRunIDPromptRunsRecursivelyAndPublishesRunComplete is the
73+// end-to-end proof of fix 2: a prompt carrying a RunID that is queued
74+// behind a busy session must NOT be silently folded into the active turn.
75+// It runs as its own turn via the recursive run path and publishes its
76+// own terminal RunComplete, so a `crush run` caller blocking on that
77+// RunID does not hang. The active turn keeps its own RunComplete too.
78+func TestRun_QueuedRunIDPromptRunsRecursivelyAndPublishesRunComplete(t *testing.T) {
82+ broker := pubsub.NewBroker[notify.RunComplete]()
83+ t.Cleanup(broker.Shutdown)
85+ large := &gatedStreamModel{
87+ gate: make(chan struct{}),
88+ entered: make(chan struct{}),
90+ small := &finishStreamModel{text: "title"}
92+ sa := NewSessionAgent(SessionAgentOptions{
93+ LargeModel: Model{Model: large, CatwalkCfg: catwalk.Model{ContextWindow: 200000, DefaultMaxTokens: 10000}},
94+ SmallModel: Model{Model: small, CatwalkCfg: catwalk.Model{ContextWindow: 200000, DefaultMaxTokens: 10000}},
96+ Sessions: env.sessions,
97+ Messages: env.messages,
101+ sess, err := env.sessions.Create(t.Context(), "session")
102+ require.NoError(t, err)
104+ subCtx, subCancel := context.WithCancel(t.Context())
106+ ch := broker.Subscribe(subCtx)
108+ // Start the main turn; it blocks inside Stream once active.
109+ mainDone := make(chan error, 1)
111+ _, runErr := sa.Run(t.Context(), SessionAgentCall{
119+ // Wait until the main turn is active (inside Stream).
121+ case <-large.entered:
122+ case <-time.After(5 * time.Second):
123+ t.Fatal("main run never entered Stream")
125+ require.True(t, sa.IsSessionBusy(sess.ID), "main run must be active before enqueueing the follow-up")
127+ // Enqueue a RunID-bearing follow-up behind the busy session.
128+ res, err := sa.Run(t.Context(), SessionAgentCall{
130+ RunID: "run-follow",
133+ require.NoError(t, err)
134+ require.Nil(t, res, "a busy-session follow-up must enqueue and return (nil, nil)")
135+ require.Equal(t, 1, sa.QueuedPrompts(sess.ID), "the follow-up must be queued, not folded")
137+ // Release the main turn so it completes and hands off to the queue.
139+ require.NoError(t, <-mainDone)
141+ // Both turns must publish their own terminal RunComplete.
142+ got := map[string]notify.RunComplete{}
143+ deadline := time.After(5 * time.Second)
147+ got[ev.Payload.RunID] = ev.Payload
149+ t.Fatalf("timed out waiting for both RunCompletes; got %v", got)
153+ main, ok := got["run-main"]
154+ require.True(t, ok, "the active turn must publish its own RunComplete")
155+ require.Empty(t, main.Error)
156+ require.False(t, main.Cancelled)
158+ follow, ok := got["run-follow"]
160+ "the queued RunID prompt must publish its own RunComplete instead of being folded silently")
161+ require.Empty(t, follow.Error)
162+ require.False(t, follow.Cancelled)
163+ require.Equal(t, "done", follow.Text, "the queued prompt ran as its own turn")
165+ // Two distinct assistant turns prove the follow-up was not folded.
166+ msgs, err := env.messages.List(t.Context(), sess.ID)
167+ require.NoError(t, err)
168+ var assistants, follows int
169+ for _, m := range msgs {
171+ case message.Assistant:
174+ if m.Content().String() == "follow" {
179+ require.Equal(t, 2, assistants, "the active turn and the recursive turn each produce one assistant message")
180+ require.Equal(t, 1, follows, "the follow-up prompt is its own user turn")
internal/agent/run_complete_test.gonew file+322
@@ -0,0 +1,322 @@
8+ "github.com/charmbracelet/crush/internal/agent/notify"
9+ "github.com/charmbracelet/crush/internal/pubsub"
10+ "github.com/stretchr/testify/require"
13+// TestSessionAgentRun_QueueStripsOnComplete verifies that when a Run
14+// call is enqueued (because the session is already busy), the
15+// OnComplete hook is NOT propagated onto the queued copy. The hook
16+// belongs to the caller's retry/coalesce scope (typically
17+// coordinator.Run) which has already returned by the time the queue
18+// drains; carrying it forward would silently funnel the terminal
19+// event into a closure nobody reads, and subscribers (`crush run`)
20+// would hang waiting for a RunComplete that never publishes.
21+func TestSessionAgentRun_QueueStripsOnComplete(t *testing.T) {
25+ a := NewSessionAgent(SessionAgentOptions{
26+ Sessions: env.sessions,
27+ Messages: env.messages,
30+ const sessionID = "queued-session"
31+ // Mark the session as busy so Run takes the queue branch
32+ // without needing a real model.
33+ a.activeRequests.Set(sessionID, func() {})
36+ hook := func(notify.RunComplete) { called = true }
38+ res, err := a.Run(t.Context(), SessionAgentCall{
39+ SessionID: sessionID,
41+ Prompt: "queued prompt",
44+ require.NoError(t, err)
45+ require.Nil(t, res, "queued Run must return (nil, nil)")
46+ require.False(t, called,
47+ "OnComplete must not fire on the enqueue path; the caller's scope is still live")
49+ queued, ok := a.messageQueue.Get(sessionID)
51+ require.Len(t, queued, 1)
52+ require.Nil(t, queued[0].OnComplete,
53+ "queued SessionAgentCall must have OnComplete stripped so the drain falls back to the default broker publish")
54+ require.Equal(t, "queued prompt", queued[0].Prompt,
55+ "all other fields must be preserved on the queued copy")
56+ require.Equal(t, "run-xyz", queued[0].RunID,
57+ "RunID must be preserved on the queued copy so the drained turn's "+
58+ "RunComplete still correlates with the originating SendMessage")
61+// TestDrainQueueForStep_FiltersUnderDispatchLock verifies that the queue
62+// drain evaluates the per-session cancel mark while holding the dispatch
63+// mutex (canceledBySeq's documented precondition). Queued calls at or
64+// below the cancel high-water mark are dropped, calls queued after the
65+// cancel (higher seq) are folded, untracked enqueues (seq == 0) are
66+// dropped whenever any mark is present, and the queue is cleared. These
67+// calls carry no RunID, so all foldable survivors are returned for
68+// folding (the existing follow-up behavior).
69+func TestDrainQueueForStep_FiltersUnderDispatchLock(t *testing.T) {
73+ a := NewSessionAgent(SessionAgentOptions{
74+ Sessions: env.sessions,
75+ Messages: env.messages,
78+ const sessionID = "drain-session"
79+ a.messageQueue.Set(sessionID, []SessionAgentCall{
80+ {SessionID: sessionID, Prompt: "below", acceptSeq: 1},
81+ {SessionID: sessionID, Prompt: "at-mark", acceptSeq: 2},
82+ {SessionID: sessionID, Prompt: "after", acceptSeq: 3},
83+ {SessionID: sessionID, Prompt: "untracked", acceptSeq: 0},
85+ // Cancel high-water mark at seq 2: seq <= 2 and seq == 0 are covered.
86+ a.cancelMark.Set(sessionID, 2)
88+ fold, canceledWithRunID := a.drainQueueForStep(sessionID)
90+ require.Len(t, fold, 1,
91+ "only the follow-up queued after the cancel (seq > mark) must be folded")
92+ require.Equal(t, "after", fold[0].Prompt)
93+ require.Empty(t, canceledWithRunID,
94+ "no dropped call carried a RunID, so none need a terminal RunComplete")
96+ _, ok := a.messageQueue.Get(sessionID)
97+ require.False(t, ok, "drain must clear the session message queue when nothing is kept")
100+// TestDrainQueueForStep_NoMarkFoldsAllNonRunID verifies that with no
101+// cancel mark recorded, every queued call without a RunID is folded.
102+func TestDrainQueueForStep_NoMarkFoldsAllNonRunID(t *testing.T) {
106+ a := NewSessionAgent(SessionAgentOptions{
107+ Sessions: env.sessions,
108+ Messages: env.messages,
111+ const sessionID = "drain-nomark"
112+ a.messageQueue.Set(sessionID, []SessionAgentCall{
113+ {SessionID: sessionID, Prompt: "a", acceptSeq: 0},
114+ {SessionID: sessionID, Prompt: "b", acceptSeq: 5},
117+ fold, canceledWithRunID := a.drainQueueForStep(sessionID)
118+ require.Len(t, fold, 2, "no cancel mark means all non-RunID queued calls are folded")
119+ require.Empty(t, canceledWithRunID)
122+// TestDrainQueueForStep_KeepsRunIDPromptsQueued is the core of fix 2: a
123+// queued prompt that carries a RunID must NOT be folded into the active
124+// turn. Folding it would silently absorb it into another turn and never
125+// publish a RunComplete for its RunID, hanging a `crush run` caller that
126+// blocks on that event. Such prompts are left in the queue so the
127+// recursive run path gives each its own turn and its own RunComplete.
128+// Non-RunID prompts are still folded.
129+func TestDrainQueueForStep_KeepsRunIDPromptsQueued(t *testing.T) {
133+ a := NewSessionAgent(SessionAgentOptions{
134+ Sessions: env.sessions,
135+ Messages: env.messages,
138+ const sessionID = "drain-runid"
139+ a.messageQueue.Set(sessionID, []SessionAgentCall{
140+ {SessionID: sessionID, Prompt: "fold-me", acceptSeq: 1},
141+ {SessionID: sessionID, RunID: "run-a", Prompt: "keep-me", acceptSeq: 2},
142+ {SessionID: sessionID, RunID: "run-b", Prompt: "keep-me-too", acceptSeq: 3},
145+ fold, canceledWithRunID := a.drainQueueForStep(sessionID)
147+ require.Len(t, fold, 1, "only the non-RunID prompt is folded into the active turn")
148+ require.Equal(t, "fold-me", fold[0].Prompt)
149+ require.Empty(t, canceledWithRunID)
151+ kept, ok := a.messageQueue.Get(sessionID)
152+ require.True(t, ok, "RunID-bearing prompts must remain queued for the recursive run path")
153+ require.Len(t, kept, 2)
154+ require.Equal(t, "run-a", kept[0].RunID)
155+ require.Equal(t, "run-b", kept[1].RunID)
158+// TestDrainQueueForStep_ReportsCanceledRunIDDrops verifies that a queued
159+// prompt carrying a RunID that is dropped because a cancel covers it is
160+// reported in canceledWithRunID so the caller can publish its terminal
161+// cancelled RunComplete. A canceled prompt without a RunID is dropped
162+// silently as before.
163+func TestDrainQueueForStep_ReportsCanceledRunIDDrops(t *testing.T) {
167+ a := NewSessionAgent(SessionAgentOptions{
168+ Sessions: env.sessions,
169+ Messages: env.messages,
172+ const sessionID = "drain-cancel-runid"
173+ a.messageQueue.Set(sessionID, []SessionAgentCall{
174+ {SessionID: sessionID, RunID: "run-canceled", Prompt: "canceled", acceptSeq: 1},
175+ {SessionID: sessionID, Prompt: "canceled-no-runid", acceptSeq: 1},
176+ {SessionID: sessionID, RunID: "run-survives", Prompt: "survives", acceptSeq: 5},
178+ a.cancelMark.Set(sessionID, 2)
180+ fold, canceledWithRunID := a.drainQueueForStep(sessionID)
182+ require.Empty(t, fold, "no uncanceled non-RunID prompts to fold")
183+ require.Len(t, canceledWithRunID, 1,
184+ "only the dropped RunID-bearing prompt needs a terminal RunComplete")
185+ require.Equal(t, "run-canceled", canceledWithRunID[0].RunID)
187+ kept, ok := a.messageQueue.Get(sessionID)
189+ require.Len(t, kept, 1, "the uncanceled RunID prompt stays queued")
190+ require.Equal(t, "run-survives", kept[0].RunID)
193+// TestRunCompletePublisher_MustDeliverOverTakesPublish exercises the
194+// pubsub.Publisher interface change end-to-end: a Broker is the only
195+// concrete Publisher implementation and must satisfy both Publish and
196+// PublishMustDeliver. The coordinator's final RunComplete emit relies
197+// on PublishMustDeliver to apply bounded-blocking semantics so a
198+// momentarily-full subscriber buffer can't silently drop the
199+// authoritative end-of-run event.
200+func TestRunCompletePublisher_MustDeliverOverTakesPublish(t *testing.T) {
203+ broker := pubsub.NewBroker[notify.RunComplete]()
204+ t.Cleanup(broker.Shutdown)
206+ // Subscribe before publishing so the event is delivered.
207+ ctx, cancel := context.WithCancel(t.Context())
209+ ch := broker.Subscribe(ctx)
211+ rc := notify.RunComplete{SessionID: "S", MessageID: "m", Text: "ok"}
212+ var pub pubsub.Publisher[notify.RunComplete] = broker
213+ pub.PublishMustDeliver(t.Context(), pubsub.UpdatedEvent, rc)
217+ require.Equal(t, rc, got.Payload)
218+ case <-time.After(time.Second):
219+ t.Fatal("PublishMustDeliver did not deliver event")
223+// requireSingleCancelledRunComplete reads exactly one RunComplete from ch,
224+// asserts it is the cancelled terminal event for runID, and verifies no
225+// second event arrives. This observes the published pubsub event rather
226+// than internal bookkeeping, which is the contract a `crush run` caller
227+// blocking on the broker actually relies on.
228+func requireSingleCancelledRunComplete(t *testing.T, ch <-chan pubsub.Event[notify.RunComplete], sessionID, runID string) {
232+ require.Equal(t, runID, ev.Payload.RunID,
233+ "the published RunComplete must carry the dropped queued prompt's RunID")
234+ require.Equal(t, sessionID, ev.Payload.SessionID)
235+ require.True(t, ev.Payload.Cancelled,
236+ "a dropped queued prompt must publish a cancelled RunComplete")
237+ case <-time.After(5 * time.Second):
238+ t.Fatal("timed out waiting for the cancelled RunComplete")
242+ t.Fatalf("expected exactly one RunComplete, got a second: %+v", extra.Payload)
243+ case <-time.After(100 * time.Millisecond):
247+// TestCancel_QueuedRunIDPromptPublishesCancelledRunComplete proves the
248+// terminal-event behavior end-to-end: a RunID-bearing prompt sitting in
249+// the queue that is canceled while queued (via the public Cancel path,
250+// which routes through clearQueueAndNotify -> publishCanceledQueueDrops)
251+// must emit exactly one cancelled RunComplete on the broker for its
252+// RunID. A queued prompt without a RunID is dropped silently. This is the
253+// coverage the earlier drain test lacked: it asserted the returned
254+// bookkeeping slice, not the published event a `crush run` caller awaits.
255+func TestCancel_QueuedRunIDPromptPublishesCancelledRunComplete(t *testing.T) {
259+ broker := pubsub.NewBroker[notify.RunComplete]()
260+ t.Cleanup(broker.Shutdown)
262+ a := NewSessionAgent(SessionAgentOptions{
263+ Sessions: env.sessions,
264+ Messages: env.messages,
265+ RunComplete: broker,
268+ subCtx, subCancel := context.WithCancel(t.Context())
270+ ch := broker.Subscribe(subCtx)
272+ const sessionID = "cancel-queued-runid"
273+ a.messageQueue.Set(sessionID, []SessionAgentCall{
274+ {SessionID: sessionID, Prompt: "no-runid", acceptSeq: 1},
275+ {SessionID: sessionID, RunID: "run-queued", Prompt: "queued", acceptSeq: 2},
280+ requireSingleCancelledRunComplete(t, ch, sessionID, "run-queued")
282+ _, ok := a.messageQueue.Get(sessionID)
283+ require.False(t, ok, "Cancel must clear the queue")
286+// TestDrainQueueForStep_DroppedRunIDPublishesCancelledRunComplete drives
287+// the production drain sequence (drainQueueForStep then
288+// publishCanceledQueueDrops, mirroring the PrepareStep handoff) and
289+// asserts the dropped RunID-bearing prompt actually publishes exactly one
290+// cancelled RunComplete on the broker. The companion bookkeeping test
291+// covers the returned slice; this one covers the observable terminal
293+func TestDrainQueueForStep_DroppedRunIDPublishesCancelledRunComplete(t *testing.T) {
297+ broker := pubsub.NewBroker[notify.RunComplete]()
298+ t.Cleanup(broker.Shutdown)
300+ a := NewSessionAgent(SessionAgentOptions{
301+ Sessions: env.sessions,
302+ Messages: env.messages,
303+ RunComplete: broker,
306+ subCtx, subCancel := context.WithCancel(t.Context())
308+ ch := broker.Subscribe(subCtx)
310+ const sessionID = "drain-drop-runid"
311+ a.messageQueue.Set(sessionID, []SessionAgentCall{
312+ {SessionID: sessionID, RunID: "run-dropped", Prompt: "dropped", acceptSeq: 1},
313+ {SessionID: sessionID, Prompt: "dropped-no-runid", acceptSeq: 1},
315+ a.cancelMark.Set(sessionID, 2)
317+ _, canceledWithRunID := a.drainQueueForStep(sessionID)
318+ require.Len(t, canceledWithRunID, 1)
319+ a.publishCanceledQueueDrops(canceledWithRunID)
321+ requireSingleCancelledRunComplete(t, ch, sessionID, "run-dropped")
internal/agent/run_marker.gonew file+52
@@ -0,0 +1,52 @@
8+// runCompleteMarkerKey is the unexported context key carrying a
9+// [runCompleteMarker] from the dispatch boundary (backend.runAgent)
10+// down into the coordinator. It lets the dispatcher learn whether the
11+// coordinator already published the authoritative terminal
12+// notify.RunComplete for the run, so a fallback terminal event is only
13+// emitted when one is actually missing (e.g. an error returned before
14+// sessionAgent.Run ever executed). It avoids a breaking change to the
15+// Coordinator interface.
16+type runCompleteMarkerKey struct{}
18+// runCompleteMarker records whether a terminal RunComplete has been
19+// published for a run. It is shared by pointer through the context so
20+// a publish deep in the call stack is observable by the dispatcher
21+// after the call returns.
22+type runCompleteMarker struct {
23+ published atomic.Bool
26+// WithRunCompleteMarker returns ctx carrying a fresh marker the
27+// coordinator can flag via [MarkRunCompletePublished] once it emits the
28+// run's terminal RunComplete. Callers read the result with
29+// [RunCompletePublished]. Attaching the marker is optional: code paths
30+// without one simply skip the dedup signal.
31+func WithRunCompleteMarker(ctx context.Context) context.Context {
32+ return context.WithValue(ctx, runCompleteMarkerKey{}, &runCompleteMarker{})
35+// MarkRunCompletePublished records that the authoritative terminal
36+// RunComplete has been published for the run carried by ctx. It is a
37+// no-op when no marker is present (e.g. the in-process/local Run path,
38+// which is not dispatched through backend.runAgent).
39+func MarkRunCompletePublished(ctx context.Context) {
40+ if m, ok := ctx.Value(runCompleteMarkerKey{}).(*runCompleteMarker); ok {
41+ m.published.Store(true)
45+// RunCompletePublished reports whether [MarkRunCompletePublished] was
46+// called on ctx's marker. It returns false when no marker is present.
47+func RunCompletePublished(ctx context.Context) bool {
48+ if m, ok := ctx.Value(runCompleteMarkerKey{}).(*runCompleteMarker); ok {
49+ return m.published.Load()
internal/agent/runid.gonew file+33
@@ -0,0 +1,33 @@
5+// runIDContextKey is the unexported context key used to carry a
6+// caller-supplied RunID from the workspace HTTP boundary
7+// (backend.SendMessage) down into coordinator.Run without forcing a
8+// breaking change to the Coordinator.Run signature. The value is
9+// then copied onto SessionAgentCall.RunID by the coordinator so the
10+// agent's terminal RunComplete event can echo it back to the
11+// originating caller.
12+type runIDContextKey struct{}
14+// WithRunID returns ctx tagged with a per-request RunID. It is the
15+// boundary helper for callers that need their SendMessage→Run
16+// terminal event to be uniquely correlatable (e.g. `crush run`
17+// against a session that may be busy). Empty runIDs are stored
18+// as-is; downstream code treats an empty RunID as "caller did not
19+// supply one" and falls back to SessionID-only correlation.
20+func WithRunID(ctx context.Context, runID string) context.Context {
21+ return context.WithValue(ctx, runIDContextKey{}, runID)
24+// RunIDFromContext returns the RunID set by [WithRunID], or "" if
25+// none was set or the value is not a string. Exported because the
26+// coordinator and tests in other packages need to read it; safe to
27+// call on any context.
28+func RunIDFromContext(ctx context.Context) string {
29+ if v, ok := ctx.Value(runIDContextKey{}).(string); ok {
internal/agent/templates/agent_tool.mdnew file+1
@@ -0,0 +1 @@
1+Launch a new agent that has access to the following tools: glob, grep, ls, view. When you are searching for a keyword or file and are not confident that you will find the right match on the first try, use the agent tool to perform the search for you.
internal/agent/templates/agentic_fetch.mdnew file+1
@@ -0,0 +1 @@
1+Fetch a URL or search the web using an AI sub-agent that can extract, summarize, and answer questions. Slower and costlier than fetch; use fetch for raw content or API responses.
internal/agent/templates/agentic_fetch_prompt.md.tplnew file+76
@@ -0,0 +1,76 @@
1+You are a web content analysis agent for Crush. Your task is to analyze web content, search results, or web pages to extract the information requested by the user.
4+1. Be concise and direct in your responses
5+2. Focus only on the information requested in the user's prompt
6+3. If the content is provided in a file path, use the grep and view tools to efficiently search through it
7+4. When relevant, quote specific sections from the content to support your answer
8+5. If the requested information is not found, clearly state that
9+6. Any file paths you use MUST be absolute
10+7. **IMPORTANT**: If you need information from a linked page or search result, use the web_fetch tool to get that content
11+8. **IMPORTANT**: If you need to search for more information, use the web_search tool
12+9. After fetching a link, analyze the content yourself to extract what's needed
13+10. Don't hesitate to follow multiple links or perform multiple searches if necessary to get complete information
14+11. **CRITICAL**: At the end of your response, include a "Sources" section listing ALL URLs that were useful in answering the question
18+When searching for information:
20+1. **Break down complex questions** - If the user's question has multiple parts, search for each part separately
21+2. **Use specific, targeted queries** - Prefer multiple small searches over one broad search
22+ - Bad: "Python 3.12 new features performance improvements async changes"
23+ - Good: First "Python 3.12 new features", then "Python 3.12 performance improvements", then "Python 3.12 async changes"
24+3. **Iterate and refine** - If initial results aren't helpful, try different search terms or more specific queries
25+4. **Search for different aspects** - For comprehensive answers, search for different angles of the topic
26+5. **Follow up on promising results** - When you find a good source, fetch it and look for links to related information
28+Example workflow for "What are the pros and cons of using Rust vs Go for web services?":
29+- Search 1: "Rust web services advantages"
30+- Search 2: "Go web services advantages"
31+- Search 3: "Rust vs Go performance comparison"
32+- Search 4: "Rust vs Go developer experience"
33+- Then fetch the most relevant results from each search
37+Your response should be structured as follows:
39+[Your answer to the user's question]
42+- [URL 1 that was useful]
43+- [URL 2 that was useful]
44+- [URL 3 that was useful]
47+Only include URLs that actually contributed information to your answer. Include the main URL or search results that were helpful. Add any additional URLs you fetched that provided relevant information.
51+Working directory: {{.WorkingDir}}
52+Platform: {{.Platform}}
53+Today's date: {{.Date}}
57+You have access to a web_search tool that allows you to search the web:
58+- Provide a search query and optionally max_results (default: 10)
59+- The tool returns search results with titles, URLs, and snippets
60+- After getting search results, use web_fetch to get full content from relevant URLs
61+- **Prefer multiple focused searches over single broad searches**
62+- Keep queries short and specific (3-6 words is often ideal)
63+- If results aren't relevant, try rephrasing with different keywords
64+- Don't be afraid to do 3-5+ searches to thoroughly answer a complex question
68+You have access to a web_fetch tool that allows you to fetch web pages:
69+- Use it when you need to follow links from search results or the current page
70+- Provide just the URL (no prompt parameter)
71+- The tool will fetch and return the content (or save to a file if large)
72+- YOU must then analyze that content to answer the user's question
73+- **Use this liberally** - if a link seems relevant to answering the question, fetch it!
74+- You can fetch multiple pages in sequence to gather all needed information
75+- Remember to include any fetched URLs in your Sources section if they were helpful
internal/agent/templates/coder.md.tplnew file+420
@@ -0,0 +1,420 @@
1+You are Crush, a powerful AI Assistant that runs in the CLI.
4+These rules override everything else. Follow them strictly:
6+1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.
7+2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.
8+3. **TEST AFTER CHANGES**: Run tests immediately after each modification.
9+4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.
10+5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.
11+6. **NEVER COMMIT**: Unless user explicitly says "commit". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.
12+7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.
13+8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.
14+9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.
15+10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.
16+11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.
17+12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.
18+13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.
19+14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.
20+15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.
24+Keep responses minimal:
25+- ALWAYS think and respond in the same spoken language the prompt was written in.
26+- Under 4 lines of text (tool use doesn't count)
27+- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.
28+- No preamble ("Here's...", "I'll...")
29+- No postamble ("Let me know...", "Hope this helps...")
30+- One-word answers when possible
32+- No explanations unless user asks
33+- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.
34+- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.
40+user: list files in src/
41+assistant: [uses ls tool]
44+user: which file has the foo implementation?
47+user: add error handling to the login function
48+assistant: [searches for login, reads file, edits with exact match, runs tests]
51+user: Where are errors from the client handled?
52+assistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.
53+</communication_style>
56+When referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:
57+- Example: "The error is handled in src/main.go:45"
58+- Example: "See the implementation in pkg/utils/helper.go:123-145"
62+For every task, follow this sequence internally (don't narrate it):
65+- Search codebase for relevant files
66+- Read files to understand current state
67+- Check memory for stored commands
68+- Identify what needs to change
69+- Use `git log` and `git blame` for additional context when needed
72+- Read entire file before editing it
73+- Before editing: verify exact whitespace and indentation from View output
74+- Use exact text for find/replace (include whitespace)
75+- Make one logical change at a time
76+- After each change: run tests
77+- If tests fail: fix immediately
78+- If edit fails: read more context, don't guess - the text must match exactly
79+- Keep going until query is completely resolved before yielding to user
80+- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points
83+- Verify ENTIRE query is resolved (not just first step)
84+- All described next steps must be completed
85+- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.
86+- Run lint/typecheck if in memory
87+- Verify all changes work
88+- Keep response under 4 lines
91+- Use find_references before changing shared code
92+- Follow existing patterns (check similar files)
93+- If stuck, try different approach (don't repeat failures)
94+- Make decisions yourself (search first, don't ask)
95+- Fix problems at root cause, not surface-level patches
96+- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)
100+**Make decisions autonomously** - don't ask when you can:
101+- Search to find the answer
102+- Read files to see patterns
105+- Try most likely approach
106+- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.
108+**Only stop/ask user if**:
109+- Truly ambiguous business requirement
110+- Multiple valid approaches with big tradeoffs
111+- Could cause data loss
112+- Exhausted all attempts and hit actual blocking errors
114+**When requesting information/access**:
115+- Exhaust all available tools, searches, and reasonable assumptions first.
116+- Never say "Need more info" without detail.
117+- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.
118+- State exactly what you will do once the information arrives so the user knows the next step.
120+When you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.
123+- Task seems too large (break it down)
124+- Multiple files to change (change them)
125+- Concerns about "session limits" (no such limits exist)
126+- Work will take many steps (do all the steps)
128+Examples of autonomous decisions:
129+- File location → search for similar files
130+- Test command → check package.json/memory
131+- Code style → read existing code
132+- Library choice → check what's used
133+- Naming → follow existing names
137+**Available edit tools:**
138+- `edit` - Single find/replace in a file
139+- `multiedit` - Multiple find/replace operations in one file
140+- `write` - Create/overwrite entire file
142+Never use `apply_patch` or similar - those tools don't exist.
144+Critical: ALWAYS read the relevant context of files before editing them in this conversation.
146+When using edit tools:
147+1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)
148+2. Copy the exact text including ALL whitespace, newlines, and indentation
149+3. Include 3-5 lines of context before and after the target
150+4. Verify your old_string would appear exactly once in the file
151+5. If uncertain about whitespace, include more surrounding context
152+6. Verify edit succeeded
155+**Whitespace matters**:
156+- Count spaces/tabs carefully (use View tool line numbers as reference)
157+- Include blank lines if they exist
158+- Match line endings exactly
159+- When in doubt, include MORE context rather than less
162+- Don't re-read files after successful edits (tool will fail if it didn't work)
163+- Same applies for making folders, deleting files, etc.
165+Common mistakes to avoid:
166+- Editing without reading first
167+- Approximate text matches
168+- Wrong indentation (spaces vs tabs, wrong count)
169+- Missing or extra blank lines
170+- Not enough context (text appears multiple times)
171+- Trimming whitespace that exists in the original
172+- Not testing after changes
175+<whitespace_and_exact_matching>
176+The Edit tool is extremely literal. "Close enough" will fail.
178+**Before every edit**:
179+1. View the file and locate the exact lines to change
180+2. Copy the text EXACTLY including:
181+ - Every space and tab
183+ - Opening/closing braces position
184+ - Comment formatting
185+3. Include enough surrounding lines (3-5) to make it unique
186+4. Double-check indentation level matches
189+- `func foo() {` vs `func foo(){` (space before brace)
190+- Tab vs 4 spaces vs 2 spaces
191+- Missing blank line before/after
192+- `// comment` vs `//comment` (space after //)
193+- Different number of spaces in indentation
196+- View the file again at the specific location
197+- Copy even more context
198+- Check for tabs vs spaces
199+- Verify line endings
200+- Try including the entire function/block if needed
201+- Never retry with guessed changes - get the exact text first
202+</whitespace_and_exact_matching>
205+Ensure every task is implemented completely, not partially or sketched.
207+1. **Think before acting** (for non-trivial tasks)
208+ - Identify all components that need changes (models, logic, routes, config, tests, docs)
209+ - Consider edge cases and error paths upfront
210+ - Form a mental checklist of requirements before making the first edit
211+ - This planning happens internally - don't narrate it to the user
213+2. **Implement end-to-end**
214+ - Treat every request as complete work: if adding a feature, wire it fully
215+ - Update all affected files (callers, configs, tests, docs)
216+ - Don't leave TODOs or "you'll also need to..." - do it yourself
217+ - No task is too large - break it down and complete all parts
218+ - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.
220+3. **Verify before finishing**
221+ - Re-read the original request and verify each requirement is met
222+ - Check for missing error handling, edge cases, or unwired code
223+ - Run tests to confirm the implementation works
224+ - Only say "Done" when truly done - never stop mid-task
229+1. Read complete error message
230+2. Understand root cause (isolate with debug logs or minimal reproduction if needed)
231+3. Try different approach (don't repeat same action)
232+4. Search for similar code that works
235+7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.
238+- Import/Module → check paths, spelling, what exists
239+- Syntax → check brackets, indentation, typos
240+- Tests fail → read test, see what it expects
241+- File not found → use ls, check exact path
243+**Edit tool "old_string not found"**:
244+- View the file again at the target location
245+- Copy the EXACT text including all whitespace
246+- Include more surrounding context (full function if needed)
247+- Check for tabs vs spaces, extra/missing blank lines
248+- Count indentation spaces carefully
249+- Don't retry with approximate matches - get the exact text
252+<memory_instructions>
253+Memory files store commands, preferences, and codebase info. Update them when you discover:
254+- Build/test/lint commands
255+- Code style preferences
256+- Important codebase patterns
257+- Useful project information
258+</memory_instructions>
262+1. Check if library exists (look at imports, package.json)
263+2. Read similar code for patterns
264+3. Match existing style
265+4. Use same libraries/frameworks
266+5. Follow security best practices (never log secrets)
267+6. Don't use one-letter variable names unless requested
269+Never assume libraries are available - verify first.
271+**Ambition vs. precision**:
272+- New projects → be creative and ambitious with implementation
273+- Existing codebases → be surgical and precise, respect surrounding code
274+- Don't change filenames or variables unnecessarily
275+- Don't add formatters/linters/tests to codebases that don't have them
279+After significant changes:
280+- Start testing as specific as possible to code changed, then broaden to build confidence
281+- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions
282+- Run relevant test suite
283+- If tests fail, fix before continuing
284+- Check memory for test commands
285+- Run lint/typecheck if available (on precise targets when possible)
286+- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue
287+- Suggest adding commands to memory if not found
288+- Don't fix unrelated bugs or test failures (not your responsibility)
292+- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.
293+- Search before assuming
294+- Read files before editing
295+- Always use absolute paths for file operations (editing, reading, writing)
296+- Use Agent tool for complex searches
297+- Run tools in parallel when safe (no dependencies)
298+- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution
299+- Summarize tool output for user (they don't see it)
300+- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.
301+- Only use the tools you know exist.
304+**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.
306+When running non-trivial bash commands (especially those that modify the system):
307+- Briefly explain what the command does and why you're running it
308+- This ensures the user understands potentially dangerous operations
309+- Simple read-only commands (ls, cat, etc.) don't need explanation
310+- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)
311+- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)
312+- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)
317+Balance autonomy with user intent:
318+- When asked to do something → do it fully (including ALL follow-ups and "next steps")
319+- Never describe what you'll do next - just do it
320+- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.
321+- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.
322+- When asked how to approach → explain first, don't auto-implement
323+- After completing work → stop, don't explain (unless asked)
324+- Don't surprise user with unexpected actions
328+Adapt verbosity to match the work completed:
330+**Default (under 4 lines)**:
331+- Simple questions or single-file changes
332+- Casual conversation, greetings, acknowledgements
333+- One-word answers when possible
335+**More detail allowed (up to 10-15 lines)**:
336+- Large multi-file changes that need walkthrough
337+- Complex refactoring where rationale adds value
338+- Tasks where understanding the approach is important
339+- When mentioning unrelated bugs/issues found
340+- Suggesting logical next steps user might want
341+- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.
343+**What to include in verbose answers**:
344+- Brief summary of what was done and why
345+- Key files/functions changed (with `file:line` references)
346+- Any important decisions or tradeoffs made
347+- Next steps or things user should verify
348+- Issues found but not fixed
351+- Don't show full file contents unless explicitly asked
352+- Don't explain how to save files or copy code (user has access to your work)
353+- Don't use "Here's what I did" or "Let me know if..." style preambles/postambles
354+- Keep tone direct and factual, like handing off work to a teammate
358+Working directory: {{.WorkingDir}}
359+Is directory a git repo: {{if .IsGitRepo}}yes{{else}}no{{end}}
360+Platform: {{.Platform}}
361+Today's date: {{.Date}}
364+Git status (snapshot at conversation start - may be outdated):
369+{{if gt (len .Config.LSP) 0}}
371+Diagnostics (lint/typecheck) included in tool output.
372+- Fix issues in files you changed
373+- Ignore issues in files you didn't touch (unless user asks)
376+{{- if .AvailSkillXML}}
381+The `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.
383+MANDATORY activation flow:
384+1. Scan `<available_skills>` against the current user task.
385+2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.
386+3. Read the entire SKILL.md and follow its instructions.
387+4. Only then execute the task, using the skill's prescribed commands/tools.
389+Do NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.
391+Builtin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The "crush://" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.
393+Do not use MCP tools (including read_mcp_resource) to load skills.
394+If a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).
399+# Project-Specific Context
400+Make sure to follow the instructions in the context below.
402+{{range .ContextFiles}}
403+<file path="{{.Path}}">
409+{{if .GlobalContextFiles}}
412+The following is personal content added by the user that they'd like you to follow no matter what project you're working in.
414+{{range .GlobalContextFiles}}
415+<file path="{{.Path}}">
internal/agent/templates/initialize.md.tplnew file+29
@@ -0,0 +1,29 @@
1+Analyze this codebase and create/update **{{.Config.Options.InitializeAs}}** to help future agents work effectively in this repository.
3+**First**: Check if directory is empty or contains only config files. If so, stop and say "Directory appears empty or only contains config. Add source code first, then run this command to generate {{.Config.Options.InitializeAs}}."
5+**Goal**: Document what an agent needs to know to work in this codebase - commands, patterns, conventions, gotchas, overall architecture, how components fit together
9+1. Check directory contents with `ls`
10+2. Look for existing rule files (`.cursor/rules/*.md`, `.cursorrules`, `.github/copilot-instructions.md`, `claude.md`, `agents.md`) - only read if they exist
11+3. Identify project type from config files and directory structure
12+4. Find build/test/lint commands from config files, scripts, Makefiles, or CI configs
13+5. Read representative source files to understand code patterns, architecture, control/data flow
14+6. If {{.Config.Options.InitializeAs}} exists, read and improve it
16+**Content to include**:
18+- Essential commands (build, test, run, deploy, etc.) - whatever is relevant for this project
19+- Code organization and structure, application architecture and control/data flow
20+- Naming conventions and style patterns
21+- Testing approach and patterns
22+- Important gotchas or non-obvious patterns
23+- Any project-specific context from existing rule files
25+**Note:** LLM agents learn and adapt to their context as they obtain it, so mentioning obvious details they would immediately pick up from reading a file or two is actively detrimental. Keep the principles of progressive disclosure in mind and focus primarily on non-obvious knowledge that saves the agent from trial-and-error discovery: gotchas, implicit conventions, commands with surprising flags, and context that isn't self-evident from the code in a single file.
27+**Format**: Clear markdown sections. Use your judgment on structure based on what you find. Aim for completeness over brevity - include everything an agent would need to know.
29+**Critical**: Only document what you actually observe. Never invent commands, patterns, or conventions. If you can't find something, don't include it.
internal/agent/templates/summary.mdnew file+48
@@ -0,0 +1,48 @@
1+You are summarizing a conversation to preserve context for continuing work later.
3+**Critical**: This summary will be the ONLY context available when the conversation resumes. Assume all previous messages will be lost. Be thorough.
9+- What task is being worked on (exact user request)
10+- Current progress and what's been completed
11+- What's being worked on right now (incomplete work)
12+- What remains to be done (specific next steps, not vague)
16+- Files that were modified (with brief description of changes)
17+- Files that were read/analyzed (why they're relevant)
18+- Key files not yet touched but will need changes
19+- File paths and line numbers for important code locations
23+- Architecture decisions made and why
24+- Patterns being followed (with examples)
25+- Libraries/frameworks being used
26+- Commands that worked (exact commands with context)
27+- Commands that failed (what was tried and why it didn't work)
28+- Environment details (language versions, dependencies, etc.)
30+## Strategy & Approach
32+- Overall approach being taken
33+- Why this approach was chosen over alternatives
34+- Key insights or gotchas discovered
36+- Any blockers or risks identified
40+Be specific. Don't write "implement authentication" - write:
42+1. Add JWT middleware to src/middleware/auth.js:15
43+2. Update login handler in src/routes/user.js:45 to return token
44+3. Test with: npm test -- auth.test.js
46+**Tone**: Write as if briefing a teammate taking over mid-task. Include everything they'd need to continue without asking questions. No emojis ever.
48+**Length**: No limit. Err on the side of too much detail rather than too little. Critical context is worth the tokens.
internal/agent/templates/task.md.tplnew file+15
@@ -0,0 +1,15 @@
1+You are an agent for Crush. Given the user's prompt, you should use the tools available to you to answer the user's question.
4+1. You should be concise, direct, and to the point, since your responses will be displayed on a command line interface. Answer the user's question directly, without elaboration, explanation, or details. One word answers are best. Avoid introductions, conclusions, and explanations. You MUST avoid text before/after your response, such as "The answer is <answer>.", "Here is the content of the file..." or "Based on the information provided, the answer is..." or "Here is what I will do next...".
5+2. When relevant, share file names and code snippets relevant to the query
6+3. Any file paths you return in your final response MUST be absolute. DO NOT use relative paths.
10+Working directory: {{.WorkingDir}}
11+Is directory a git repo: {{if .IsGitRepo}} yes {{else}} no {{end}}
12+Platform: {{.Platform}}
13+Today's date: {{.Date}}
internal/agent/templates/title.mdnew file+11
@@ -0,0 +1,11 @@
1+You will generate a short title based on the first message a user begins a conversation with.
4+- Keep the title in the same language that the user wrote their message in.
5+- Ensure it is not more than 50 characters long.
6+- The title should be a summary of the user's message.
7+- It should be one line long.
8+- Do not use quotes or colons.
9+- The entire text you return will be used as the title.
10+- Never return anything that is more than one sentence (one line) long.
internal/agent/testdata/TestCoderAgent/glm-5.1/bash_tool.yamlnew file+425
@@ -0,0 +1,425 @@
11+ body: '{"messages":[{"content":"You will generate a short title based on the first message a user begins a conversation with.\n\n<rules>\n- Keep the title in the same language that the user wrote their message in.\n- Ensure it is not more than 50 characters long.\n- The title should be a summary of the user''s message.\n- It should be one line long.\n- Do not use quotes or colons.\n- The entire text you return will be used as the title.\n- Never return anything that is more than one sentence (one line) long.\n</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse bash to create a file named test.txt with content ''hello bash''. do not print its timestamp\n <think>\n\n</think>","role":"user"}],"model":"gpt-oss-120b","max_completion_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
18+ - Charm-Crush/devel (https://charm.land/crush)
19+ url: https://hyper.charm.land/v1/chat/completions
28+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
30+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"We"},"finish_reason":null}]}
32+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" need"},"finish_reason":null}]}
34+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
36+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" generate"},"finish_reason":null}]}
38+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
40+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" short"},"finish_reason":null}]}
42+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
44+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" based"},"finish_reason":null}]}
46+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" on"},"finish_reason":null}]}
48+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
50+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" user's"},"finish_reason":null}]}
52+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" first"},"finish_reason":null}]}
54+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" message"},"finish_reason":null}]}
56+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
58+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" The"},"finish_reason":null}]}
60+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
62+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" wrote"},"finish_reason":null}]}
64+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
66+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" English"},"finish_reason":null}]}
68+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
70+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Title"},"finish_reason":null}]}
72+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" must"},"finish_reason":null}]}
74+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" be"},"finish_reason":null}]}
76+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \u003c="},"finish_reason":null}]}
78+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
80+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
82+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
84+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
86+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" quotes"},"finish_reason":null}]}
88+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"/"},"finish_reason":null}]}
90+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"col"},"finish_reason":null}]}
92+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ons"},"finish_reason":null}]}
94+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
96+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
98+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" line"},"finish_reason":null}]}
100+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
102+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
104+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" more"},"finish_reason":null}]}
106+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" than"},"finish_reason":null}]}
108+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
110+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" sentence"},"finish_reason":null}]}
112+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
114+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Summ"},"finish_reason":null}]}
116+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ar"},"finish_reason":null}]}
118+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ize"},"finish_reason":null}]}
120+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
122+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
124+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"bash"},"finish_reason":null}]}
126+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" create"},"finish_reason":null}]}
128+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" test"},"finish_reason":null}]}
130+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
132+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
134+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" hello"},"finish_reason":null}]}
136+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" bash"},"finish_reason":null}]}
138+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" without"},"finish_reason":null}]}
140+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" timestamp"},"finish_reason":null}]}
142+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
144+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Let's"},"finish_reason":null}]}
146+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" craft"},"finish_reason":null}]}
148+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
150+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
152+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Create"},"finish_reason":null}]}
154+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" test"},"finish_reason":null}]}
156+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
158+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
160+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" hello"},"finish_reason":null}]}
162+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" bash"},"finish_reason":null}]}
164+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" using"},"finish_reason":null}]}
166+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Bash"},"finish_reason":null}]}
168+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
170+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" That's"},"finish_reason":null}]}
172+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" under"},"finish_reason":null}]}
174+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
176+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
178+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
180+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
182+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
184+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
186+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Create"},"finish_reason":null}]}
188+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" test"},"finish_reason":null}]}
190+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
192+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
194+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" hello"},"finish_reason":null}]}
196+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" bash"},"finish_reason":null}]}
198+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" using"},"finish_reason":null}]}
200+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Bash"},"finish_reason":null}]}
202+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\""},"finish_reason":null}]}
204+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
206+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
208+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"38"},"finish_reason":null}]}
210+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
212+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
214+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" No"},"finish_reason":null}]}
216+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" quotes"},"finish_reason":null}]}
218+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
220+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Good"},"finish_reason":null}]}
222+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
224+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"Create"},"finish_reason":null}]}
226+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" test"},"finish_reason":null}]}
228+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":".txt"},"finish_reason":null}]}
230+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" with"},"finish_reason":null}]}
232+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" hello"},"finish_reason":null}]}
234+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" bash"},"finish_reason":null}]}
236+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" using"},"finish_reason":null}]}
238+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" Bash"},"finish_reason":null}]}
240+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
242+ data: {"id":"chatcmpl-9b4429c7811fb2c7070cc503","object":"chat.completion.chunk","created":1782413792,"model":"gpt-oss-120b","choices":[],"usage":{"prompt_tokens":224,"completion_tokens":115,"total_tokens":339,"completion_tokens_details":{"reasoning_tokens":98},"cost":{"usd":0.00015733800000000003,"hypercredits":0.0031467600000000006},"remaining":{"hypercredits":0}}}
251+ duration: 700.546792ms
257+ content_length: 35672
259+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/bash_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use bash to create a file named test.txt with content 'hello bash'. do not print its timestamp\",\"role\":\"user\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
266+ - Charm-Crush/devel (https://charm.land/crush)
267+ url: https://hyper.charm.land/v1/chat/completions
276+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
278+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"The"},"finish_reason":null}]}
280+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
282+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" wants"},"finish_reason":null}]}
284+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" me"},"finish_reason":null}]}
286+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
288+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" create"},"finish_reason":null}]}
290+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
292+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" file"},"finish_reason":null}]}
294+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" named"},"finish_reason":null}]}
296+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" test"},"finish_reason":null}]}
298+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
300+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
302+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" content"},"finish_reason":null}]}
304+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
306+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"hello"},"finish_reason":null}]}
308+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" bash"},"finish_reason":null}]}
310+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
312+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" using"},"finish_reason":null}]}
314+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
316+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" bash"},"finish_reason":null}]}
318+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" tool"},"finish_reason":null}]}
320+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
322+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" and"},"finish_reason":null}]}
324+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" not"},"finish_reason":null}]}
326+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" print"},"finish_reason":null}]}
328+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" its"},"finish_reason":null}]}
330+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" timestamp"},"finish_reason":null}]}
332+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
334+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_51c682620b31061c","type":"function","index":0,"function":{"name":"bash","arguments":""}}]},"finish_reason":null}]}
336+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"command\": \""}}]},"finish_reason":null}]}
338+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"echo"}}]},"finish_reason":null}]}
340+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" '"}}]},"finish_reason":null}]}
342+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"hello"}}]},"finish_reason":null}]}
344+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" bash"}}]},"finish_reason":null}]}
346+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"'"}}]},"finish_reason":null}]}
348+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" \u003e"}}]},"finish_reason":null}]}
350+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" test"}}]},"finish_reason":null}]}
352+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".txt"}}]},"finish_reason":null}]}
354+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
356+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":", \"description\": \""}}]},"finish_reason":null}]}
358+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Create"}}]},"finish_reason":null}]}
360+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" test"}}]},"finish_reason":null}]}
362+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".txt"}}]},"finish_reason":null}]}
364+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" with"}}]},"finish_reason":null}]}
366+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" content"}}]},"finish_reason":null}]}
368+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
370+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"finish_reason":null}]}
372+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
374+ data: {"id":"chatcmpl-5baef5f0d9ce99f46bc74840","object":"chat.completion.chunk","created":1782413793,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":686,"completion_tokens":56,"total_tokens":8221,"prompt_tokens_details":{"cached_tokens":7479},"completion_tokens_details":{"reasoning_tokens":32},"cost":{"usd":0.0013476,"hypercredits":0.026952},"remaining":{"hypercredits":0}}}
383+ duration: 1.461643167s
389+ content_length: 36122
391+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/bash_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use bash to create a file named test.txt with content 'hello bash'. do not print its timestamp\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_51c682620b31061c\",\"function\":{\"arguments\":\"{\\\"command\\\": \\\"echo 'hello bash' > test.txt\\\", \\\"description\\\": \\\"Create test.txt with content\\\"}\",\"name\":\"bash\"},\"type\":\"function\"}],\"role\":\"assistant\",\"reasoning_content\":\"The user wants me to create a file named test.txt with content 'hello bash' using the bash tool, and not print its timestamp.\"},{\"content\":\"no output\",\"tool_call_id\":\"call_51c682620b31061c\",\"role\":\"tool\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
398+ - Charm-Crush/devel (https://charm.land/crush)
399+ url: https://hyper.charm.land/v1/chat/completions
408+ data: {"id":"chatcmpl-985f3df336cbf13a5d358129","object":"chat.completion.chunk","created":1782413794,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
410+ data: {"id":"chatcmpl-985f3df336cbf13a5d358129","object":"chat.completion.chunk","created":1782413794,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"Done"},"finish_reason":null}]}
412+ data: {"id":"chatcmpl-985f3df336cbf13a5d358129","object":"chat.completion.chunk","created":1782413794,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"."},"finish_reason":null}]}
414+ data: {"id":"chatcmpl-985f3df336cbf13a5d358129","object":"chat.completion.chunk","created":1782413794,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
416+ data: {"id":"chatcmpl-985f3df336cbf13a5d358129","object":"chat.completion.chunk","created":1782413794,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":720,"completion_tokens":4,"total_tokens":8203,"prompt_tokens_details":{"cached_tokens":7479},"cost":{"usd":0.0010255999999999998,"hypercredits":0.020511999999999996},"remaining":{"hypercredits":0}}}
425+ duration: 1.122182833s
internal/agent/testdata/TestCoderAgent/glm-5.1/download_tool.yamlnew file+483
@@ -0,0 +1,483 @@
11+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/download_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"download the file from https://example-files.online-convert.com/document/txt/example.txt and save it as example.txt\",\"role\":\"user\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
18+ - Charm-Crush/devel (https://charm.land/crush)
19+ url: https://hyper.charm.land/v1/chat/completions
28+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
30+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"The"},"finish_reason":null}]}
32+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
34+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" wants"},"finish_reason":null}]}
36+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
38+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" download"},"finish_reason":null}]}
40+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
42+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" file"},"finish_reason":null}]}
44+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" from"},"finish_reason":null}]}
46+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
48+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" URL"},"finish_reason":null}]}
50+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" and"},"finish_reason":null}]}
52+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" save"},"finish_reason":null}]}
54+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" it"},"finish_reason":null}]}
56+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" as"},"finish_reason":null}]}
58+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
60+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
62+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
64+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_4cbf337c01e5b47c","type":"function","index":0,"function":{"name":"download","arguments":""}}]},"finish_reason":null}]}
66+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"file_path\": \""}}]},"finish_reason":null}]}
68+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/tmp"}}]},"finish_reason":null}]}
70+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/c"}}]},"finish_reason":null}]}
72+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"rush"}}]},"finish_reason":null}]}
74+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-test"}}]},"finish_reason":null}]}
76+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/Test"}}]},"finish_reason":null}]}
78+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Coder"}}]},"finish_reason":null}]}
80+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Agent"}}]},"finish_reason":null}]}
82+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/g"}}]},"finish_reason":null}]}
84+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"lm"}}]},"finish_reason":null}]}
86+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-"}}]},"finish_reason":null}]}
88+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"5"}}]},"finish_reason":null}]}
90+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"."}}]},"finish_reason":null}]}
92+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"1"}}]},"finish_reason":null}]}
94+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/download"}}]},"finish_reason":null}]}
96+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"_tool"}}]},"finish_reason":null}]}
98+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/example"}}]},"finish_reason":null}]}
100+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".txt"}}]},"finish_reason":null}]}
102+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
104+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":", \"url\": \""}}]},"finish_reason":null}]}
106+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"https"}}]},"finish_reason":null}]}
108+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"://"}}]},"finish_reason":null}]}
110+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"example"}}]},"finish_reason":null}]}
112+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-files"}}]},"finish_reason":null}]}
114+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".online"}}]},"finish_reason":null}]}
116+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-"}}]},"finish_reason":null}]}
118+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"convert"}}]},"finish_reason":null}]}
120+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".com"}}]},"finish_reason":null}]}
122+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/document"}}]},"finish_reason":null}]}
124+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/t"}}]},"finish_reason":null}]}
126+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"xt"}}]},"finish_reason":null}]}
128+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/example"}}]},"finish_reason":null}]}
130+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".txt"}}]},"finish_reason":null}]}
132+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
134+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"finish_reason":null}]}
136+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
138+ data: {"id":"chatcmpl-cc0c9ef25b702fedc808d605","object":"chat.completion.chunk","created":1782413796,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":689,"completion_tokens":63,"total_tokens":8231,"prompt_tokens_details":{"cached_tokens":7479},"completion_tokens_details":{"reasoning_tokens":18},"cost":{"usd":0.001321,"hypercredits":0.026419999999999996},"remaining":{"hypercredits":0}}}
147+ duration: 936.027666ms
155+ body: '{"messages":[{"content":"You will generate a short title based on the first message a user begins a conversation with.\n\n<rules>\n- Keep the title in the same language that the user wrote their message in.\n- Ensure it is not more than 50 characters long.\n- The title should be a summary of the user''s message.\n- It should be one line long.\n- Do not use quotes or colons.\n- The entire text you return will be used as the title.\n- Never return anything that is more than one sentence (one line) long.\n</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\ndownload the file from https://example-files.online-convert.com/document/txt/example.txt and save it as example.txt\n <think>\n\n</think>","role":"user"}],"model":"gpt-oss-120b","max_completion_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
162+ - Charm-Crush/devel (https://charm.land/crush)
163+ url: https://hyper.charm.land/v1/chat/completions
172+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
174+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"The"},"finish_reason":null}]}
176+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
178+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" asks"},"finish_reason":null}]}
180+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
182+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
184+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Generate"},"finish_reason":null}]}
186+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
188+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" concise"},"finish_reason":null}]}
190+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
192+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
194+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
196+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" following"},"finish_reason":null}]}
198+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" content"},"finish_reason":null}]}
200+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
202+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" download"},"finish_reason":null}]}
204+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
206+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" file"},"finish_reason":null}]}
208+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" from"},"finish_reason":null}]}
210+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" https"},"finish_reason":null}]}
212+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"://"},"finish_reason":null}]}
214+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"example"},"finish_reason":null}]}
216+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"-files"},"finish_reason":null}]}
218+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".online"},"finish_reason":null}]}
220+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"-con"},"finish_reason":null}]}
222+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"vert"},"finish_reason":null}]}
224+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".com"},"finish_reason":null}]}
226+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"/document"},"finish_reason":null}]}
228+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"/t"},"finish_reason":null}]}
230+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"xt"},"finish_reason":null}]}
232+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"/example"},"finish_reason":null}]}
234+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
236+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" and"},"finish_reason":null}]}
238+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" save"},"finish_reason":null}]}
240+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" it"},"finish_reason":null}]}
242+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" as"},"finish_reason":null}]}
244+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
246+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
248+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
250+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Need"},"finish_reason":null}]}
252+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
254+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" short"},"finish_reason":null}]}
256+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
258+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
260+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" same"},"finish_reason":null}]}
262+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" language"},"finish_reason":null}]}
264+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
266+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"English"},"finish_reason":null}]}
268+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"),"},"finish_reason":null}]}
270+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \u003c="},"finish_reason":null}]}
272+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
274+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" chars"},"finish_reason":null}]}
276+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
278+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
280+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" line"},"finish_reason":null}]}
282+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
284+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
286+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" quotes"},"finish_reason":null}]}
288+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
290+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
292+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" colon"},"finish_reason":null}]}
294+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
296+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Something"},"finish_reason":null}]}
298+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" like"},"finish_reason":null}]}
300+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
302+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Download"},"finish_reason":null}]}
304+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" and"},"finish_reason":null}]}
306+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Save"},"finish_reason":null}]}
308+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
310+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
312+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" from"},"finish_reason":null}]}
314+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" URL"},"finish_reason":null}]}
316+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
318+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
320+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
322+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
324+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
326+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Download"},"finish_reason":null}]}
328+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" and"},"finish_reason":null}]}
330+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Save"},"finish_reason":null}]}
332+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
334+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".txt"},"finish_reason":null}]}
336+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" from"},"finish_reason":null}]}
338+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" URL"},"finish_reason":null}]}
340+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\""},"finish_reason":null}]}
342+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
344+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
346+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"38"},"finish_reason":null}]}
348+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
350+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
352+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Good"},"finish_reason":null}]}
354+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
356+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"Download"},"finish_reason":null}]}
358+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" and"},"finish_reason":null}]}
360+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" Save"},"finish_reason":null}]}
362+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" example"},"finish_reason":null}]}
364+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":".txt"},"finish_reason":null}]}
366+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" from"},"finish_reason":null}]}
368+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" URL"},"finish_reason":null}]}
370+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
372+ data: {"id":"chatcmpl-cacd42b690dbfa0c757a15f0","object":"chat.completion.chunk","created":1782413796,"model":"gpt-oss-120b","choices":[],"usage":{"prompt_tokens":160,"completion_tokens":108,"total_tokens":336,"prompt_tokens_details":{"cached_tokens":68},"completion_tokens_details":{"reasoning_tokens":103},"cost":{"usd":0.000145462,"hypercredits":0.00290924},"remaining":{"hypercredits":0}}}
381+ duration: 1.326897958s
388+ host: example-files.online-convert.com
392+ url: https://example-files.online-convert.com/document/txt/example.txt
402+ Purpose: Provide example of this file type
403+ Document file type: TXT
408+ The names "John Doe" for males, "Jane Doe" or "Jane Roe" for females, or "Jonnie Doe" and "Janie Doe" for children, or just "Doe" non-gender-specifically are used as placeholder names for a party whose true identity is unknown or must be withheld in a legal action, case, or discussion. The names are also used to refer to acorpse or hospital patient whose identity is unknown. This practice is widely used in the United States and Canada, but is rarely used in other English-speaking countries including the United Kingdom itself, from where the use of "John Doe" in a legal context originates. The names Joe Bloggs or John Smith are used in the UK instead, as well as in Australia and New Zealand.
410+ John Doe is sometimes used to refer to a typical male in other contexts as well, in a similar manner to John Q. Public, known in Great Britain as Joe Public, John Smith or Joe Bloggs. For example, the first name listed on a form is often John Doe, along with a fictional address or other fictional information to provide an example of how to fill in the form. The name is also used frequently in popular culture, for example in the Frank Capra film Meet John Doe. John Doe was also the name of a 2002 American television series.
412+ Similarly, a child or baby whose identity is unknown may be referred to as Baby Doe. A notorious murder case in Kansas City, Missouri, referred to the baby victim as Precious Doe. Other unidentified female murder victims are Cali Doe and Princess Doe. Additional persons may be called James Doe, Judy Doe, etc. However, to avoid possible confusion, if two anonymous or unknown parties are cited in a specific case or action, the surnames Doe and Roe may be used simultaneously; for example, "John Doe v. Jane Roe". If several anonymous parties are referenced, they may simply be labelled John Doe #1, John Doe #2, etc. (the U.S. Operation Delego cited 21 (numbered) "John Doe"s) or labelled with other variants of Doe / Roe / Poe / etc. Other early alternatives such as John Stiles and Richard Miles are now rarely used, and Mary Major has been used in some American federal cases.
416+ File created by https://www.online-convert.com
417+ More example files: https://www.online-convert.com/file-type
418+ Text of Example content: Wikipedia (https://en.wikipedia.org/wiki/John_Doe)
419+ License: Attribution-ShareAlike 4.0 (https://creativecommons.org/licenses/by-sa/4.0/)
421+ Feel free to use and share the file according to the license above.
424+ - text/plain; charset=UTF-8
427+ duration: 893.137459ms
433+ content_length: 36247
435+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/download_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"download the file from https://example-files.online-convert.com/document/txt/example.txt and save it as example.txt\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_4cbf337c01e5b47c\",\"function\":{\"arguments\":\"{\\\"file_path\\\": \\\"/tmp/crush-test/TestCoderAgent/glm-5.1/download_tool/example.txt\\\", \\\"url\\\": \\\"https://example-files.online-convert.com/document/txt/example.txt\\\"}\",\"name\":\"download\"},\"type\":\"function\"}],\"role\":\"assistant\",\"reasoning_content\":\"The user wants to download a file from a URL and save it as example.txt.\"},{\"content\":\"Successfully downloaded 2574 bytes to example.txt (Content-Type: text/plain; charset=UTF-8)\",\"tool_call_id\":\"call_4cbf337c01e5b47c\",\"role\":\"tool\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
442+ - Charm-Crush/devel (https://charm.land/crush)
443+ url: https://hyper.charm.land/v1/chat/completions
452+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
454+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"Download"},"finish_reason":null}]}
456+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"ed"},"finish_reason":null}]}
458+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" and"},"finish_reason":null}]}
460+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" saved"},"finish_reason":null}]}
462+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" as"},"finish_reason":null}]}
464+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `"},"finish_reason":null}]}
466+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"example"},"finish_reason":null}]}
468+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":".txt"},"finish_reason":null}]}
470+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`."},"finish_reason":null}]}
472+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
474+ data: {"id":"chatcmpl-4bda680be45220e2a1b071f0","object":"chat.completion.chunk","created":1782413799,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":73,"completion_tokens":11,"total_tokens":8251,"prompt_tokens_details":{"cached_tokens":8167},"cost":{"usd":0.0001506,"hypercredits":0.003012},"remaining":{"hypercredits":0}}}
483+ duration: 1.486211917s
internal/agent/testdata/TestCoderAgent/glm-5.1/fetch_tool.yamlnew file+650
@@ -0,0 +1,650 @@
11+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/fetch_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"fetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word 'John Doe'\",\"role\":\"user\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
18+ - Charm-Crush/devel (https://charm.land/crush)
19+ url: https://hyper.charm.land/v1/chat/completions
28+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
30+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"The"},"finish_reason":null}]}
32+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
34+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" wants"},"finish_reason":null}]}
36+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" me"},"finish_reason":null}]}
38+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
40+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" fetch"},"finish_reason":null}]}
42+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" content"},"finish_reason":null}]}
44+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" from"},"finish_reason":null}]}
46+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
48+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" URL"},"finish_reason":null}]}
50+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" and"},"finish_reason":null}]}
52+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" check"},"finish_reason":null}]}
54+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" if"},"finish_reason":null}]}
56+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" it"},"finish_reason":null}]}
58+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" contains"},"finish_reason":null}]}
60+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
62+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" word"},"finish_reason":null}]}
64+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
66+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"John"},"finish_reason":null}]}
68+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":" Doe"},"finish_reason":null}]}
70+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"reasoning_content":"'."},"finish_reason":null}]}
72+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_60557666b1c79950","type":"function","index":0,"function":{"name":"fetch","arguments":""}}]},"finish_reason":null}]}
74+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"format\": \""}}]},"finish_reason":null}]}
76+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"text"}}]},"finish_reason":null}]}
78+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
80+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":", \"url\": \""}}]},"finish_reason":null}]}
82+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"https"}}]},"finish_reason":null}]}
84+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"://"}}]},"finish_reason":null}]}
86+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"example"}}]},"finish_reason":null}]}
88+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-files"}}]},"finish_reason":null}]}
90+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".online"}}]},"finish_reason":null}]}
92+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"-"}}]},"finish_reason":null}]}
94+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"convert"}}]},"finish_reason":null}]}
96+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".com"}}]},"finish_reason":null}]}
98+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/"}}]},"finish_reason":null}]}
100+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"website"}}]},"finish_reason":null}]}
102+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/html"}}]},"finish_reason":null}]}
104+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/example"}}]},"finish_reason":null}]}
106+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":".html"}}]},"finish_reason":null}]}
108+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
110+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"finish_reason":null}]}
112+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
114+ data: {"id":"chatcmpl-adf239d098d5e63d542c1773","object":"chat.completion.chunk","created":1782413801,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":696,"completion_tokens":50,"total_tokens":8225,"prompt_tokens_details":{"cached_tokens":7479},"completion_tokens_details":{"reasoning_tokens":23},"cost":{"usd":0.0012956,"hypercredits":0.025912},"remaining":{"hypercredits":0}}}
123+ duration: 2.230852292s
131+ body: '{"messages":[{"content":"You will generate a short title based on the first message a user begins a conversation with.\n\n<rules>\n- Keep the title in the same language that the user wrote their message in.\n- Ensure it is not more than 50 characters long.\n- The title should be a summary of the user''s message.\n- It should be one line long.\n- Do not use quotes or colons.\n- The entire text you return will be used as the title.\n- Never return anything that is more than one sentence (one line) long.\n</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\nfetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word ''John Doe''\n <think>\n\n</think>","role":"user"}],"model":"gpt-oss-120b","max_completion_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
138+ - Charm-Crush/devel (https://charm.land/crush)
139+ url: https://hyper.charm.land/v1/chat/completions
148+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
150+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" wants"},"finish_reason":null}]}
152+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
154+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" short"},"finish_reason":null}]}
156+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
158+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
160+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" their"},"finish_reason":null}]}
162+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" request"},"finish_reason":null}]}
164+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" content"},"finish_reason":null}]}
166+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
168+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Title"},"finish_reason":null}]}
170+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
172+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" English"},"finish_reason":null}]}
174+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
176+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Summ"},"finish_reason":null}]}
178+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ar"},"finish_reason":null}]}
180+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ize"},"finish_reason":null}]}
182+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
184+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
186+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Check"},"finish_reason":null}]}
188+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
190+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".html"},"finish_reason":null}]}
192+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
194+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" word"},"finish_reason":null}]}
196+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
198+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"John"},"finish_reason":null}]}
200+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Doe"},"finish_reason":null}]}
202+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
204+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
206+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Must"},"finish_reason":null}]}
208+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" be"},"finish_reason":null}]}
210+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \u003c="},"finish_reason":null}]}
212+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
214+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" chars"},"finish_reason":null}]}
216+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
218+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Let's"},"finish_reason":null}]}
220+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" craft"},"finish_reason":null}]}
222+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
224+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
226+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Check"},"finish_reason":null}]}
228+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" if"},"finish_reason":null}]}
230+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
232+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".html"},"finish_reason":null}]}
234+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" contains"},"finish_reason":null}]}
236+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
238+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"John"},"finish_reason":null}]}
240+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Doe"},"finish_reason":null}]}
242+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
244+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
246+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
248+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
250+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
252+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
254+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
256+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
258+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Check"},"finish_reason":null}]}
260+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" if"},"finish_reason":null}]}
262+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" example"},"finish_reason":null}]}
264+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".html"},"finish_reason":null}]}
266+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" contains"},"finish_reason":null}]}
268+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
270+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"John"},"finish_reason":null}]}
272+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Doe"},"finish_reason":null}]}
274+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'\""},"finish_reason":null}]}
276+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" that's"},"finish_reason":null}]}
278+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
280+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"41"},"finish_reason":null}]}
282+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" maybe"},"finish_reason":null}]}
284+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
286+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Let's"},"finish_reason":null}]}
288+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" count"},"finish_reason":null}]}
290+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
292+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" C"},"finish_reason":null}]}
294+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
296+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
298+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
300+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"h"},"finish_reason":null}]}
302+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
304+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"e"},"finish_reason":null}]}
306+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"3"},"finish_reason":null}]}
308+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"c"},"finish_reason":null}]}
310+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
312+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"k"},"finish_reason":null}]}
314+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
316+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
318+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"6"},"finish_reason":null}]}
320+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" i"},"finish_reason":null}]}
322+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
324+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"f"},"finish_reason":null}]}
326+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"8"},"finish_reason":null}]}
328+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
330+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"9"},"finish_reason":null}]}
332+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" e"},"finish_reason":null}]}
334+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"10"},"finish_reason":null}]}
336+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"x"},"finish_reason":null}]}
338+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"11"},"finish_reason":null}]}
340+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"a"},"finish_reason":null}]}
342+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"12"},"finish_reason":null}]}
344+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"m"},"finish_reason":null}]}
346+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"13"},"finish_reason":null}]}
348+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"p"},"finish_reason":null}]}
350+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"14"},"finish_reason":null}]}
352+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"l"},"finish_reason":null}]}
354+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"15"},"finish_reason":null}]}
356+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"e"},"finish_reason":null}]}
358+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"16"},"finish_reason":null}]}
360+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
362+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"17"},"finish_reason":null}]}
364+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"h"},"finish_reason":null}]}
366+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"18"},"finish_reason":null}]}
368+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"t"},"finish_reason":null}]}
370+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"19"},"finish_reason":null}]}
372+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"m"},"finish_reason":null}]}
374+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"20"},"finish_reason":null}]}
376+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"l"},"finish_reason":null}]}
378+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"21"},"finish_reason":null}]}
380+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
382+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"22"},"finish_reason":null}]}
384+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" c"},"finish_reason":null}]}
386+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"23"},"finish_reason":null}]}
388+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"o"},"finish_reason":null}]}
390+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"24"},"finish_reason":null}]}
392+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"n"},"finish_reason":null}]}
394+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"25"},"finish_reason":null}]}
396+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"t"},"finish_reason":null}]}
398+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"26"},"finish_reason":null}]}
400+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"a"},"finish_reason":null}]}
402+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"27"},"finish_reason":null}]}
404+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"i"},"finish_reason":null}]}
406+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"28"},"finish_reason":null}]}
408+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"n"},"finish_reason":null}]}
410+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"29"},"finish_reason":null}]}
412+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"s"},"finish_reason":null}]}
414+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"30"},"finish_reason":null}]}
416+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
418+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"31"},"finish_reason":null}]}
420+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
422+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"32"},"finish_reason":null}]}
424+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"J"},"finish_reason":null}]}
426+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"33"},"finish_reason":null}]}
428+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"o"},"finish_reason":null}]}
430+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"34"},"finish_reason":null}]}
432+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"h"},"finish_reason":null}]}
434+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"35"},"finish_reason":null}]}
436+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"n"},"finish_reason":null}]}
438+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"36"},"finish_reason":null}]}
440+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
442+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"37"},"finish_reason":null}]}
444+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"D"},"finish_reason":null}]}
446+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"38"},"finish_reason":null}]}
448+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"o"},"finish_reason":null}]}
450+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"39"},"finish_reason":null}]}
452+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"e"},"finish_reason":null}]}
454+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"40"},"finish_reason":null}]}
456+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
458+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"41"},"finish_reason":null}]}
460+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
462+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" That's"},"finish_reason":null}]}
464+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
466+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"41"},"finish_reason":null}]}
468+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
470+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
472+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" within"},"finish_reason":null}]}
474+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
476+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
478+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
480+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Good"},"finish_reason":null}]}
482+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
484+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"Check"},"finish_reason":null}]}
486+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" if"},"finish_reason":null}]}
488+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" example"},"finish_reason":null}]}
490+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":".html"},"finish_reason":null}]}
492+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" contains"},"finish_reason":null}]}
494+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" '"},"finish_reason":null}]}
496+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"John"},"finish_reason":null}]}
498+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" Doe"},"finish_reason":null}]}
500+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"'"},"finish_reason":null}]}
502+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
504+ data: {"id":"chatcmpl-2422745116026947d8ea8426","object":"chat.completion.chunk","created":1782413800,"model":"gpt-oss-120b","choices":[],"usage":{"prompt_tokens":173,"completion_tokens":183,"total_tokens":420,"prompt_tokens_details":{"cached_tokens":64},"cost":{"usd":0.00013191,"hypercredits":0.0026382},"remaining":{"hypercredits":0}}}
513+ duration: 1.005238292s
520+ host: example-files.online-convert.com
524+ url: https://example-files.online-convert.com/website/html/example.html
538+ <h1>HTML test file</h1>
540+ <p>Purpose: Provide example of this file type<br>
541+ Document file type: HTML<br>
545+ <p><img align="right" style="height:5.0551cm;width:7.62cm;" src="data:image/*;base64,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"/>
558+ Example content:<br>
559+ The names "<b>John Doe</b>" for males, "<b>Jane Doe</b>" or "<b>Jane Roe</b>" for females, or "<b>Jonnie Doe</b>" and "<b>Janie Doe</b>" for children, or just "<b>Doe</b>" non-gender-specifically are used as placeholder names for a party whose true identity is unknown or must be withheld in a legal action, case, or discussion. The names are also used to refer to acorpse or hospital patient whose identity is unknown. This practice is widely used in the United States and Canada, but is rarely used in other English-speaking countries including the United Kingdom itself, from where the use of "John Doe" in a legal context originates. The names Joe Bloggs or John Smith are used in the UK instead, as well as in Australia and New Zealand.</p>
561+ <p>John Doe is sometimes used to refer to a typical male in other contexts as well, in a similar manner to John Q. Public, known in Great Britain as Joe Public, John Smith or Joe Bloggs. For example, the first name listed on a form is often John Doe, along with a fictional address or other fictional information to provide an example of how to fill in the form. The name is also used frequently in popular culture, for example in the Frank Capra film <i>Meet John Doe</i>. John Doe was also the name of a 2002 American television series.</p>
563+ <p>Similarly, a child or baby whose identity is unknown may be referred to as <b>Baby Doe</b>. A notorious murder case in Kansas City, Missouri, referred to the baby victim as <b>Precious Doe</b>. Other unidentified female murder victims are Cali Doe and Princess Doe. Additional persons may be called James Doe, Judy Doe, etc. However, to avoid possible confusion, if two anonymous or unknown parties are cited in a specific case or action, the surnames Doe and Roe may be used simultaneously; for example, "John Doe v. Jane Roe". If several anonymous parties are referenced, they may simply be labelled John Doe #1, John Doe #2, etc. (the U.S. Operation Delego cited 21 (numbered) "John Doe"s) or labelled with other variants of Doe / Roe / Poe / etc. Other early alternatives such as <b>John Stiles</b> and <b>Richard Miles</b> are now rarely used, and <b>Mary Major</b> has been used in some American federal cases.</p>
565+ <p><img style="height:1.6881cm;width:1.6881cm;" align="left" src="data:image/*;base64,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"/>
568+ File created by <a href="https://www.online-convert.com" target="_blank">https://www.online-convert.com</a><br>
569+ More example files: <a href="https://www.online-convert.com/file-type" target="_blank">https://www.online-convert.com/file-type</a><br>
570+ Text of "Example content": <a href="https://en.wikipedia.org/wiki/John_Doe" target="_blank">Wikipedia</a><br>
571+ License: <a href="https://creativecommons.org/licenses/by-sa/3.0/" target="_blank">Attribution-ShareAlike 3.0 Unported</a>
573+ <img style="height:0.6949cm;width:1.9741cm;" align="right" src="data:image/*;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAYAAABjyArgAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAEZ0FNQQAAsY58+1GTAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAj2SURBVHja7FpLbBvHGf72IaMyInZ9SgKqiHQTdfH6eUossmlTuI7tZS27dtzUpA8NGqMgldpy2kiiKFupo9qh2MIx2iYS4/QaaP0CGqcwV2qAWpRtUnAA6kYGkFDnJIVKAVvc3elhd4e7FPWgHkHj+BeGOzuPf3e/+eaff/4RQwhxMQzzFZ7ImgshhGEAEAC4cfM6WJYFy7LgOA4sy4FjWbCceWVZMAwLlmHAMAzAMJYWEBAQnUAnOnTdSJqmGVddg6bp0HWN1ulEp+0JIdbL0PzjIAf3HwIAMACIBS7HcUZiuVKe44w6ljNBZsAwrB1fExwTWN0AU9PMZM9rTpB1XafA2oF+nEDmATjB5XjwjquRrl25jmQyiVQqhdnCrENRnasOO3fuhO+HPuzd9zI0nQPLqsaAaCwYMOZY2qaPToyZAHMOMYuDe28sDfljGdls1lHu8XggHZCwdceWVYGxXvoZAOSTW/8Az/MUVJ7njcTxGFZG0HeuD1NTU8tS6Ha70f67drS07IKqadA0FapqJk2FqmqU4ZWYXM7iB//5EhfjFzGRnQAAeL1eiKIIAMhkMlAUBQDQ5GnCidAJPPPs01UBsJ76D+4/ZAD8z+FPwXN8CVi+BjU8j0hnN+QhmXYQBAGSJKGhoQEtLS0AgOHhYeTzeciyjJmZGdpW8ks42f5b1G6shaqqKKoqVLUIVVWdJsMCWDdtuQ3orwtfI3QijEKhAEmSEIvF0NDQ4PiIfD6PtrY2yLIMl8uF3r7eZYOw3vopwLf+dQs1FrA1PGr4Gge4giAgHA4jFApBEIQFFSYSCbS1tVGgmzxNeH/gb/hebS1UtYhisUiZXBHkMnvc+WYXJrITCAQCGBwcLE0707TYmZ5IJBAMBtHkacKZcz3LAqCS/snJSUxNThqzsb4e9fX1K9Z/cP8hsADAmTaY5zjwnJO5oiginU4jEoksCi4ABAIB5HI5OsUmshM433fBYctZ6pEwpWT+2QG8N5bGRHYCkiSh/dSpJT8mEAhAkiRMZCdwbyy9LJtbrv/vly/D+/wLOHr4CI4ePgLv8y/g05s3V6TfEhYAWMst4zgMKyMOcJPJ5Lxps5gIgoBkMklBlodkDA+PgOP4yiCzltsHB8jyx8Y7xGIxeJqby/3LigtiLBZz9F1MyvWP3r6N7q4I6p95Fl6vDwdaWwEAv/7Va/hTf3/V+h0AGww2WNx3ro8CNTg4uCRrFwPZ6tv3hz7TlzbBZUyfmjU9DAYlkM3pn81m4fV65w1uMBikzA8Gg466hoYGeL3eeZ5AJbHrLxQKyKbvAwD2Sz/D+4kBvHP+j3irq9MwDwODVet3Mtj8+GtXrlNvIRwOUxauRARBoCM+NTWFa1ev0w2LAfLCJsKSSs9PJBIV84v1WUjsbXvfNYj11w8/oGU/fuklAEChUMCXDx5UrZ8CbLEpmUxScEKhEG2kKAr8fj98Ph98Ph+i0eiCdf3mdLLslsXi5K2kjb0l08AwlU3ENykulwvxeBwbXXW4dOlSxTYPHz5akW5jo8EwYBkGqVTKcLEkiQKjKAp8Pp+jk6IoUBQFoVAIfr9/Xt34+DhdlSVJQiKRQCqVMnaANmCBErglr7ykK5PJVFzMLOYGAoF59ZX6LCT2tjU8j/aTJ7GxtpaWjd6+TfPPNTxXtX4bg40PtXZomzdvpg3a2tqo/cnlcnTRO3bsGGWyKIrI5XIYGhpy+MgAaH62MFsyB/Rq4TrfRHg8HiiKgnw+7yi3u2v2vOWzKooCj8ez5IeX65+cnER3VwSv/PwwenvOoLfnDLo6OgAAp06frlq/A2D74lJuZ6wRCwQC1MjncjkEAgFaZ20+JEmidfaFp+R+0Z8lX0w6IDkGeDlitbX6VqM/ePw4gsePGwM3MIDBgQE8evgIe/a+jCNHX6lav8NE/D/K1h1b0ORpgizLCAaD89haCVxZltHkaVpW3KCS/re6OvGT3bvxxRcGq5ubm6mLWK1+J4OJc1dktzMWmxOJBGZmZpDJZNDY2IhoNFrydc1tsr3OPm1L/iv9WdbLnf59O1wuFxKJBPx+P9Vl94Pz+Tz8fj/6+/vhcrlwInRi2R9fSf/2HdtxoLUVB1pb4WluXpV+ymDrhetcdZgtzGJ8fJw2iEQi9OGbNm1yAGfVZTKZeXWWWLrqXHUgxLYdBoE1pubdvJd7yvUU4hf78c7bfZBlGbIsQxRFiKIIQRCgKAolw0qCMeutn67bo3dHsWHDBkS7opCHZAiCgOnpaYdnEI/HaYzB6/UiEolQ9sbjcdrWXgcAjY2NyOfzePFHL+JC7Dwezc2hWJxDUS2iWFShWXEJXYOu6TQIX75T+zaGK2mw5/adf6OmZgM+G/kMod+E6LYwHA6v6qWtAAkAnH37LH66ZzfminOYKxahFosoqmUAVwj4fNsD7iwAeqTj9bXA7XYDAKLR6DwXqRqZmZmhq67b7TYD8VZoUodu2mLLXDyuwgKATnRomnGOdqa3hwLk9/sdMd5qwPX5fLRv+5vtZoBdK4FsC1HSRZY8XkdGdHEHQDoiHWTsXopk7qfJq7981VrqiSiKJJ1Ok+VKLpcjoijS/pJfIpn7aTJ2L0V6ento+XcolW7Cb4TInfQYyXyeIZJfouWCIJDu7m4yPT29ILDT09Oku7ubCIJA++3YuYOMf54hdzJjpCPS8V0ElzDlTmlnpAP7/RJ4nseFvgv46PJHKz4yip7phqqqGB1N4fXXXl/5FLOZDftphn33WX6/Vs+w36/KRNhTZ6TDYPL9NBlIfEDcbveyR8ztdpP4n+Mkcz9N7mTGyHt/eW/VLCCELJq3l61W/1LPXDWDLQm/EcLRXxylpxBKchhXr1xd9Nh+n7QPXm8LPWu7cuUqzkbPrn6RqMCutWJu+TMqnfethsXMYvvWrdu2oDPShfofuG2nEfZwIxx+q/WPJ1OTk3j3fAwjwyNrswrbQFxr07DQsxZ75poBbMmull3Ys3cPtm3fhu+7XM4YrulafVUo4O6du7hx7caaAftNMXgpG7/uAD+RlQtDCNnIMMx/n0CxDhsMQpj/DQDwRbusfJXB0QAAAABJRU5ErkJggg=="/></p>
575+ <p>Feel free to use and share the file according to license above.</p>
581+ - text/html; charset=UTF-8
584+ duration: 147.645375ms
590+ content_length: 36231
592+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/fetch_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"fetch the content from https://example-files.online-convert.com/website/html/example.html and tell me if it contains the word 'John Doe'\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_60557666b1c79950\",\"function\":{\"arguments\":\"{\\\"format\\\": \\\"text\\\", \\\"url\\\": \\\"https://example-files.online-convert.com/website/html/example.html\\\"}\",\"name\":\"fetch\"},\"type\":\"function\"}],\"role\":\"assistant\",\"reasoning_content\":\"The user wants me to fetch content from a URL and check if it contains the word 'John Doe'.\"},{\"content\":\"HTML test file Purpose: Provide example of this file type Document file type: HTML Version: 1.0 Remark:\",\"tool_call_id\":\"call_60557666b1c79950\",\"role\":\"tool\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
599+ - Charm-Crush/devel (https://charm.land/crush)
600+ url: https://hyper.charm.land/v1/chat/completions
609+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
611+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"No"},"finish_reason":null}]}
613+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":","},"finish_reason":null}]}
615+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" the"},"finish_reason":null}]}
617+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" fetched"},"finish_reason":null}]}
619+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" content"},"finish_reason":null}]}
621+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" does"},"finish_reason":null}]}
623+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" not"},"finish_reason":null}]}
625+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" contain"},"finish_reason":null}]}
627+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" the"},"finish_reason":null}]}
629+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" word"},"finish_reason":null}]}
631+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" \""},"finish_reason":null}]}
633+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"John"},"finish_reason":null}]}
635+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" Doe"},"finish_reason":null}]}
637+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"\"."},"finish_reason":null}]}
639+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
641+ data: {"id":"chatcmpl-cd7a3a1eb813288fd5e12324","object":"chat.completion.chunk","created":1782413803,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":753,"completion_tokens":16,"total_tokens":8248,"prompt_tokens_details":{"cached_tokens":7479},"cost":{"usd":0.0011246000000000001,"hypercredits":0.022492},"remaining":{"hypercredits":0}}}
650+ duration: 977.248916ms
internal/agent/testdata/TestCoderAgent/glm-5.1/glob_tool.yamlnew file+737
@@ -0,0 +1,737 @@
11+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/glob_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use glob to find all .go files in the current directory\",\"role\":\"user\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
18+ - Charm-Crush/devel (https://charm.land/crush)
19+ url: https://hyper.charm.land/v1/chat/completions
28+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
30+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_ad74b69d4b477328","type":"function","index":0,"function":{"name":"glob","arguments":""}}]},"finish_reason":null}]}
32+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"pattern\": \""}}]},"finish_reason":null}]}
34+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"**"}}]},"finish_reason":null}]}
36+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"/*."}}]},"finish_reason":null}]}
38+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"go"}}]},"finish_reason":null}]}
40+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
42+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"finish_reason":null}]}
44+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
46+ data: {"id":"chatcmpl-680977ab8e48dc961b5a65b4","object":"chat.completion.chunk","created":1782413805,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":679,"completion_tokens":13,"total_tokens":8171,"prompt_tokens_details":{"cached_tokens":7479},"cost":{"usd":0.0010077999999999999,"hypercredits":0.020155999999999997},"remaining":{"hypercredits":0}}}
55+ duration: 2.191829958s
61+ content_length: 35910
63+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/glob_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use glob to find all .go files in the current directory\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_ad74b69d4b477328\",\"function\":{\"arguments\":\"{\\\"pattern\\\": \\\"**/*.go\\\"}\",\"name\":\"glob\"},\"type\":\"function\"}],\"role\":\"assistant\"},{\"content\":\"/tmp/crush-test/TestCoderAgent/glm-5.1/glob_tool/main.go\",\"tool_call_id\":\"call_ad74b69d4b477328\",\"role\":\"tool\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
70+ - Charm-Crush/devel (https://charm.land/crush)
71+ url: https://hyper.charm.land/v1/chat/completions
80+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
82+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"Found"},"finish_reason":null}]}
84+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" "},"finish_reason":null}]}
86+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"1"},"finish_reason":null}]}
88+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `."},"finish_reason":null}]}
90+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"go"},"finish_reason":null}]}
92+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`"},"finish_reason":null}]}
94+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" file"},"finish_reason":null}]}
96+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":":"},"finish_reason":null}]}
98+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `"},"finish_reason":null}]}
100+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"main"},"finish_reason":null}]}
102+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":".go"},"finish_reason":null}]}
104+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`"},"finish_reason":null}]}
106+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
108+ data: {"id":"chatcmpl-85e120b7a3fdf21599aee1ba","object":"chat.completion.chunk","created":1782413807,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":36,"completion_tokens":14,"total_tokens":8207,"prompt_tokens_details":{"cached_tokens":8157},"cost":{"usd":0.00011200000000000001,"hypercredits":0.0022400000000000002},"remaining":{"hypercredits":0}}}
117+ duration: 1.449032542s
125+ body: '{"messages":[{"content":"You will generate a short title based on the first message a user begins a conversation with.\n\n<rules>\n- Keep the title in the same language that the user wrote their message in.\n- Ensure it is not more than 50 characters long.\n- The title should be a summary of the user''s message.\n- It should be one line long.\n- Do not use quotes or colons.\n- The entire text you return will be used as the title.\n- Never return anything that is more than one sentence (one line) long.\n</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse glob to find all .go files in the current directory\n <think>\n\n</think>","role":"user"}],"model":"gpt-oss-120b","max_completion_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
132+ - Charm-Crush/devel (https://charm.land/crush)
133+ url: https://hyper.charm.land/v1/chat/completions
142+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
144+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
146+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" wants"},"finish_reason":null}]}
148+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
150+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" concise"},"finish_reason":null}]}
152+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
154+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
156+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
158+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" content"},"finish_reason":null}]}
160+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
162+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
164+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"use"},"finish_reason":null}]}
166+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" glob"},"finish_reason":null}]}
168+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
170+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" find"},"finish_reason":null}]}
172+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" all"},"finish_reason":null}]}
174+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ."},"finish_reason":null}]}
176+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"go"},"finish_reason":null}]}
178+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
180+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
182+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
184+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" current"},"finish_reason":null}]}
186+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" directory"},"finish_reason":null}]}
188+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
190+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Title"},"finish_reason":null}]}
192+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
194+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" English"},"finish_reason":null}]}
196+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
198+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \u003c="},"finish_reason":null}]}
200+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
202+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
204+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
206+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
208+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" line"},"finish_reason":null}]}
210+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
212+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
214+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" quotes"},"finish_reason":null}]}
216+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" or"},"finish_reason":null}]}
218+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" col"},"finish_reason":null}]}
220+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ons"},"finish_reason":null}]}
222+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
224+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Something"},"finish_reason":null}]}
226+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" like"},"finish_reason":null}]}
228+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
230+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Finding"},"finish_reason":null}]}
232+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ."},"finish_reason":null}]}
234+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"go"},"finish_reason":null}]}
236+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Files"},"finish_reason":null}]}
238+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
240+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Glob"},"finish_reason":null}]}
242+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
244+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Current"},"finish_reason":null}]}
246+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Directory"},"finish_reason":null}]}
248+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
250+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" That's"},"finish_reason":null}]}
252+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" under"},"finish_reason":null}]}
254+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
256+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
258+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
260+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
262+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
264+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
266+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
268+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Finding"},"finish_reason":null}]}
270+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ."},"finish_reason":null}]}
272+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"go"},"finish_reason":null}]}
274+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Files"},"finish_reason":null}]}
276+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
278+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Glob"},"finish_reason":null}]}
280+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
282+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Current"},"finish_reason":null}]}
284+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Directory"},"finish_reason":null}]}
286+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\""},"finish_reason":null}]}
288+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
290+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" let's"},"finish_reason":null}]}
292+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" count"},"finish_reason":null}]}
294+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
296+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Finding"},"finish_reason":null}]}
298+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
300+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
302+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
304+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" +"},"finish_reason":null}]}
306+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
308+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
310+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
312+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
314+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
316+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"8"},"finish_reason":null}]}
318+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
320+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ."},"finish_reason":null}]}
322+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"go"},"finish_reason":null}]}
324+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
326+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"3"},"finish_reason":null}]}
328+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
330+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" =\u003e"},"finish_reason":null}]}
332+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" total"},"finish_reason":null}]}
334+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
336+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"11"},"finish_reason":null}]}
338+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
340+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
342+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
344+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"12"},"finish_reason":null}]}
346+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
348+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Files"},"finish_reason":null}]}
350+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
352+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
354+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
356+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"17"},"finish_reason":null}]}
358+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
360+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
362+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
364+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"18"},"finish_reason":null}]}
366+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
368+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" with"},"finish_reason":null}]}
370+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
372+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
374+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
376+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"22"},"finish_reason":null}]}
378+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
380+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
382+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
384+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"23"},"finish_reason":null}]}
386+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
388+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Glob"},"finish_reason":null}]}
390+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
392+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
394+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
396+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"27"},"finish_reason":null}]}
398+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
400+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
402+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
404+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"28"},"finish_reason":null}]}
406+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
408+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
410+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
412+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
414+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
416+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"30"},"finish_reason":null}]}
418+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
420+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
422+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
424+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"31"},"finish_reason":null}]}
426+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
428+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Current"},"finish_reason":null}]}
430+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
432+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
434+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
436+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"38"},"finish_reason":null}]}
438+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
440+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
442+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
444+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"39"},"finish_reason":null}]}
446+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
448+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Directory"},"finish_reason":null}]}
450+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
452+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"9"},"finish_reason":null}]}
454+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
456+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"48"},"finish_reason":null}]}
458+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
460+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" So"},"finish_reason":null}]}
462+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
464+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"48"},"finish_reason":null}]}
466+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
468+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
470+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" okay"},"finish_reason":null}]}
472+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
474+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Or"},"finish_reason":null}]}
476+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
478+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Use"},"finish_reason":null}]}
480+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" glob"},"finish_reason":null}]}
482+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
484+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" locate"},"finish_reason":null}]}
486+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ."},"finish_reason":null}]}
488+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"go"},"finish_reason":null}]}
490+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
492+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
494+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" current"},"finish_reason":null}]}
496+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" dir"},"finish_reason":null}]}
498+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
500+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Let's"},"finish_reason":null}]}
502+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" count"},"finish_reason":null}]}
504+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
506+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Use"},"finish_reason":null}]}
508+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
510+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"3"},"finish_reason":null}]}
512+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")+"},"finish_reason":null}]}
514+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"space"},"finish_reason":null}]}
516+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
518+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
520+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
522+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" glob"},"finish_reason":null}]}
524+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
526+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
528+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
530+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"8"},"finish_reason":null}]}
532+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
534+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
536+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
538+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"9"},"finish_reason":null}]}
540+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
542+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
544+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
546+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
548+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
550+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"11"},"finish_reason":null}]}
552+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
554+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
556+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
558+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"12"},"finish_reason":null}]}
560+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
562+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" locate"},"finish_reason":null}]}
564+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
566+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"6"},"finish_reason":null}]}
568+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
570+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"18"},"finish_reason":null}]}
572+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
574+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
576+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
578+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"19"},"finish_reason":null}]}
580+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
582+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ."},"finish_reason":null}]}
584+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"go"},"finish_reason":null}]}
586+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
588+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"3"},"finish_reason":null}]}
590+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
592+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"22"},"finish_reason":null}]}
594+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
596+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
598+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
600+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"23"},"finish_reason":null}]}
602+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
604+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
606+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
608+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
610+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
612+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"28"},"finish_reason":null}]}
614+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
616+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
618+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
620+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"29"},"finish_reason":null}]}
622+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
624+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
626+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
628+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
630+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
632+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"31"},"finish_reason":null}]}
634+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
636+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
638+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
640+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"32"},"finish_reason":null}]}
642+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
644+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" current"},"finish_reason":null}]}
646+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
648+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
650+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
652+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"39"},"finish_reason":null}]}
654+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
656+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
658+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"="},"finish_reason":null}]}
660+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"40"},"finish_reason":null}]}
662+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
664+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" dir"},"finish_reason":null}]}
666+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
668+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"3"},"finish_reason":null}]}
670+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")="},"finish_reason":null}]}
672+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"43"},"finish_reason":null}]}
674+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
676+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" That's"},"finish_reason":null}]}
678+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
680+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"43"},"finish_reason":null}]}
682+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
684+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Both"},"finish_reason":null}]}
686+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" fine"},"finish_reason":null}]}
688+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
690+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Let's"},"finish_reason":null}]}
692+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" output"},"finish_reason":null}]}
694+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
696+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" line"},"finish_reason":null}]}
698+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
700+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
702+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" quotes"},"finish_reason":null}]}
704+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
706+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"Use"},"finish_reason":null}]}
708+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" glob"},"finish_reason":null}]}
710+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" to"},"finish_reason":null}]}
712+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" locate"},"finish_reason":null}]}
714+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" ."},"finish_reason":null}]}
716+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"go"},"finish_reason":null}]}
718+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" files"},"finish_reason":null}]}
720+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" in"},"finish_reason":null}]}
722+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" current"},"finish_reason":null}]}
724+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" directory"},"finish_reason":null}]}
726+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
728+ data: {"id":"chatcmpl-eb1b020a610e9fa7da88e894","object":"chat.completion.chunk","created":1782413804,"model":"gpt-oss-120b","choices":[],"usage":{"prompt_tokens":157,"completion_tokens":298,"total_tokens":519,"prompt_tokens_details":{"cached_tokens":64},"cost":{"usd":0.00019385200000000003,"hypercredits":0.0038770400000000004},"remaining":{"hypercredits":0}}}
737+ duration: 648.718041ms
internal/agent/testdata/TestCoderAgent/glm-5.1/grep_tool.yamlnew file+499
@@ -0,0 +1,499 @@
11+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/grep_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use grep to search for the word 'package' in go files\",\"role\":\"user\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
18+ - Charm-Crush/devel (https://charm.land/crush)
19+ url: https://hyper.charm.land/v1/chat/completions
28+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
30+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_a57bfe141bf85225","type":"function","index":0,"function":{"name":"grep","arguments":""}}]},"finish_reason":null}]}
32+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"include\": \""}}]},"finish_reason":null}]}
34+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"*."}}]},"finish_reason":null}]}
36+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"go"}}]},"finish_reason":null}]}
38+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
40+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":", \"pattern\": \""}}]},"finish_reason":null}]}
42+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"package"}}]},"finish_reason":null}]}
44+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\""}}]},"finish_reason":null}]}
46+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}"}}]},"finish_reason":null}]}
48+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
50+ data: {"id":"chatcmpl-8110189342807f502f916f95","object":"chat.completion.chunk","created":1782413815,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":680,"completion_tokens":18,"total_tokens":8177,"prompt_tokens_details":{"cached_tokens":7479},"cost":{"usd":0.0010312,"hypercredits":0.020623999999999997},"remaining":{"hypercredits":0}}}
67+ body: '{"messages":[{"content":"You will generate a short title based on the first message a user begins a conversation with.\n\n<rules>\n- Keep the title in the same language that the user wrote their message in.\n- Ensure it is not more than 50 characters long.\n- The title should be a summary of the user''s message.\n- It should be one line long.\n- Do not use quotes or colons.\n- The entire text you return will be used as the title.\n- Never return anything that is more than one sentence (one line) long.\n</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse grep to search for the word ''package'' in go files\n <think>\n\n</think>","role":"user"}],"model":"gpt-oss-120b","max_completion_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
74+ - Charm-Crush/devel (https://charm.land/crush)
75+ url: https://hyper.charm.land/v1/chat/completions
84+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
86+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"The"},"finish_reason":null}]}
88+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
90+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" wants"},"finish_reason":null}]}
92+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
94+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" concise"},"finish_reason":null}]}
96+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
98+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
100+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" They"},"finish_reason":null}]}
102+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" gave"},"finish_reason":null}]}
104+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
106+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" phrase"},"finish_reason":null}]}
108+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
110+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
112+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"use"},"finish_reason":null}]}
114+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" grep"},"finish_reason":null}]}
116+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
118+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" search"},"finish_reason":null}]}
120+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
122+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
124+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" word"},"finish_reason":null}]}
126+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
128+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"package"},"finish_reason":null}]}
130+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
132+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
134+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" go"},"finish_reason":null}]}
136+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
138+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
140+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Need"},"finish_reason":null}]}
142+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
144+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" produce"},"finish_reason":null}]}
146+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
148+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
150+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
152+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" same"},"finish_reason":null}]}
154+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" language"},"finish_reason":null}]}
156+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
158+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"English"},"finish_reason":null}]}
160+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")."},"finish_reason":null}]}
162+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Under"},"finish_reason":null}]}
164+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
166+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
168+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" chars"},"finish_reason":null}]}
170+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
172+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
174+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" line"},"finish_reason":null}]}
176+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
178+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Something"},"finish_reason":null}]}
180+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" like"},"finish_reason":null}]}
182+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
184+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
186+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"G"},"finish_reason":null}]}
188+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"rep"},"finish_reason":null}]}
190+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
192+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
194+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"package"},"finish_reason":null}]}
196+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
198+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
200+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Go"},"finish_reason":null}]}
202+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
204+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
206+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" That's"},"finish_reason":null}]}
208+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" within"},"finish_reason":null}]}
210+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" limit"},"finish_reason":null}]}
212+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
214+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Title"},"finish_reason":null}]}
216+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" length"},"finish_reason":null}]}
218+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"?"},"finish_reason":null}]}
220+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
222+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
224+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
226+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
228+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"G"},"finish_reason":null}]}
230+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"rep"},"finish_reason":null}]}
232+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
234+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
236+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"package"},"finish_reason":null}]}
238+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"'"},"finish_reason":null}]}
240+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
242+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Go"},"finish_reason":null}]}
244+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
246+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\""},"finish_reason":null}]}
248+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
250+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" let's"},"finish_reason":null}]}
252+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" count"},"finish_reason":null}]}
254+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
256+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" G"},"finish_reason":null}]}
258+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"("},"finish_reason":null}]}
260+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
262+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
264+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" r"},"finish_reason":null}]}
266+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
268+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" e"},"finish_reason":null}]}
270+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"3"},"finish_reason":null}]}
272+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" p"},"finish_reason":null}]}
274+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
276+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
278+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
280+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" f"},"finish_reason":null}]}
282+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"6"},"finish_reason":null}]}
284+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" o"},"finish_reason":null}]}
286+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
288+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" r"},"finish_reason":null}]}
290+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"8"},"finish_reason":null}]}
292+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
294+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"9"},"finish_reason":null}]}
296+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
298+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"10"},"finish_reason":null}]}
300+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" p"},"finish_reason":null}]}
302+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"11"},"finish_reason":null}]}
304+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
306+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"12"},"finish_reason":null}]}
308+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" c"},"finish_reason":null}]}
310+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"13"},"finish_reason":null}]}
312+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" k"},"finish_reason":null}]}
314+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"14"},"finish_reason":null}]}
316+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
318+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"15"},"finish_reason":null}]}
320+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" g"},"finish_reason":null}]}
322+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"16"},"finish_reason":null}]}
324+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" e"},"finish_reason":null}]}
326+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"17"},"finish_reason":null}]}
328+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" '"},"finish_reason":null}]}
330+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"18"},"finish_reason":null}]}
332+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
334+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"19"},"finish_reason":null}]}
336+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" i"},"finish_reason":null}]}
338+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"20"},"finish_reason":null}]}
340+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" n"},"finish_reason":null}]}
342+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"21"},"finish_reason":null}]}
344+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
346+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"22"},"finish_reason":null}]}
348+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" G"},"finish_reason":null}]}
350+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"23"},"finish_reason":null}]}
352+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" o"},"finish_reason":null}]}
354+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"24"},"finish_reason":null}]}
356+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
358+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"25"},"finish_reason":null}]}
360+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" f"},"finish_reason":null}]}
362+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"26"},"finish_reason":null}]}
364+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" i"},"finish_reason":null}]}
366+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"27"},"finish_reason":null}]}
368+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" l"},"finish_reason":null}]}
370+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"28"},"finish_reason":null}]}
372+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" e"},"finish_reason":null}]}
374+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"29"},"finish_reason":null}]}
376+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" s"},"finish_reason":null}]}
378+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"30"},"finish_reason":null}]}
380+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
382+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" So"},"finish_reason":null}]}
384+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
386+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"30"},"finish_reason":null}]}
388+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
390+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
392+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" under"},"finish_reason":null}]}
394+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
396+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
398+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
400+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Provide"},"finish_reason":null}]}
402+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" that"},"finish_reason":null}]}
404+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
406+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"G"},"finish_reason":null}]}
408+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"rep"},"finish_reason":null}]}
410+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" for"},"finish_reason":null}]}
412+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" '"},"finish_reason":null}]}
414+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"package"},"finish_reason":null}]}
416+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"'"},"finish_reason":null}]}
418+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" in"},"finish_reason":null}]}
420+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
422+ data: {"id":"chatcmpl-249484b499306e8f4f6345cf","object":"chat.completion.chunk","created":1782413814,"model":"gpt-oss-120b","choices":[],"usage":{"prompt_tokens":201,"completion_tokens":179,"total_tokens":380,"completion_tokens_details":{"reasoning_tokens":129},"cost":{"usd":0.00020686400000000002,"hypercredits":0.00413728},"remaining":{"hypercredits":0}}}
431+ duration: 541.974834ms
437+ content_length: 35983
439+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/grep_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use grep to search for the word 'package' in go files\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_a57bfe141bf85225\",\"function\":{\"arguments\":\"{\\\"include\\\": \\\"*.go\\\", \\\"pattern\\\": \\\"package\\\"}\",\"name\":\"grep\"},\"type\":\"function\"}],\"role\":\"assistant\"},{\"content\":\"Found 1 matches\\n/tmp/crush-test/TestCoderAgent/glm-5.1/grep_tool/main.go:\\n Line 1, Char 1: package main\\n\",\"tool_call_id\":\"call_a57bfe141bf85225\",\"role\":\"tool\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
446+ - Charm-Crush/devel (https://charm.land/crush)
447+ url: https://hyper.charm.land/v1/chat/completions
456+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
458+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"1"},"finish_reason":null}]}
460+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" match"},"finish_reason":null}]}
462+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" found"},"finish_reason":null}]}
464+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":":"},"finish_reason":null}]}
466+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `"},"finish_reason":null}]}
468+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"main"},"finish_reason":null}]}
470+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":".go"},"finish_reason":null}]}
472+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":":"},"finish_reason":null}]}
474+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"1"},"finish_reason":null}]}
476+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`"},"finish_reason":null}]}
478+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" —"},"finish_reason":null}]}
480+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `"},"finish_reason":null}]}
482+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"package"},"finish_reason":null}]}
484+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" main"},"finish_reason":null}]}
486+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`"},"finish_reason":null}]}
488+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
490+ data: {"id":"chatcmpl-09dddfb926db7fdea7e49d0d","object":"chat.completion.chunk","created":1782413816,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":59,"completion_tokens":17,"total_tokens":8234,"prompt_tokens_details":{"cached_tokens":8158},"cost":{"usd":0.0001574,"hypercredits":0.0031479999999999998},"remaining":{"hypercredits":0}}}
internal/agent/testdata/TestCoderAgent/glm-5.1/ls_tool.yamlnew file+485
@@ -0,0 +1,485 @@
11+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/ls_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use ls to list the files in the current directory\",\"role\":\"user\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
18+ - Charm-Crush/devel (https://charm.land/crush)
19+ url: https://hyper.charm.land/v1/chat/completions
28+ data: {"id":"chatcmpl-edc9f684f6145a18378c95dd","object":"chat.completion.chunk","created":1782413818,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
30+ data: {"id":"chatcmpl-edc9f684f6145a18378c95dd","object":"chat.completion.chunk","created":1782413818,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_9fc14d4b22da05b9","type":"function","index":0,"function":{"name":"ls","arguments":""}}]},"finish_reason":null}]}
32+ data: {"id":"chatcmpl-edc9f684f6145a18378c95dd","object":"chat.completion.chunk","created":1782413818,"model":"glm-5.1","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{}"}}]},"finish_reason":null}]}
34+ data: {"id":"chatcmpl-edc9f684f6145a18378c95dd","object":"chat.completion.chunk","created":1782413818,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
36+ data: {"id":"chatcmpl-edc9f684f6145a18378c95dd","object":"chat.completion.chunk","created":1782413818,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":677,"completion_tokens":5,"total_tokens":8161,"prompt_tokens_details":{"cached_tokens":7479},"cost":{"usd":0.0009697999999999999,"hypercredits":0.019395999999999997},"remaining":{"hypercredits":0}}}
53+ body: '{"messages":[{"content":"You will generate a short title based on the first message a user begins a conversation with.\n\n<rules>\n- Keep the title in the same language that the user wrote their message in.\n- Ensure it is not more than 50 characters long.\n- The title should be a summary of the user''s message.\n- It should be one line long.\n- Do not use quotes or colons.\n- The entire text you return will be used as the title.\n- Never return anything that is more than one sentence (one line) long.\n</rules>\n\n /no_think","role":"system"},{"content":"Generate a concise title for the following content:\n\nuse ls to list the files in the current directory\n <think>\n\n</think>","role":"user"}],"model":"gpt-oss-120b","max_completion_tokens":40,"stream_options":{"include_usage":true},"stream":true}'
60+ - Charm-Crush/devel (https://charm.land/crush)
61+ url: https://hyper.charm.land/v1/chat/completions
70+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
72+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" user"},"finish_reason":null}]}
74+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" asks"},"finish_reason":null}]}
76+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
78+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
80+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Generate"},"finish_reason":null}]}
82+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
84+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" concise"},"finish_reason":null}]}
86+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
88+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" for"},"finish_reason":null}]}
90+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
92+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" following"},"finish_reason":null}]}
94+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" content"},"finish_reason":null}]}
96+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":\n\n"},"finish_reason":null}]}
98+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"use"},"finish_reason":null}]}
100+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ls"},"finish_reason":null}]}
102+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" to"},"finish_reason":null}]}
104+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" list"},"finish_reason":null}]}
106+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
108+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
110+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
112+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" the"},"finish_reason":null}]}
114+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" current"},"finish_reason":null}]}
116+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" directory"},"finish_reason":null}]}
118+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"\n\n"},"finish_reason":null}]}
120+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"We"},"finish_reason":null}]}
122+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" need"},"finish_reason":null}]}
124+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" a"},"finish_reason":null}]}
126+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" short"},"finish_reason":null}]}
128+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" title"},"finish_reason":null}]}
130+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
132+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" same"},"finish_reason":null}]}
134+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" language"},"finish_reason":null}]}
136+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
138+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"English"},"finish_reason":null}]}
140+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"),"},"finish_reason":null}]}
142+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" max"},"finish_reason":null}]}
144+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
146+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
148+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
150+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
152+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" one"},"finish_reason":null}]}
154+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" line"},"finish_reason":null}]}
156+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":","},"finish_reason":null}]}
158+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" no"},"finish_reason":null}]}
160+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" quotes"},"finish_reason":null}]}
162+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" or"},"finish_reason":null}]}
164+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" col"},"finish_reason":null}]}
166+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"ons"},"finish_reason":null}]}
168+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
170+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Something"},"finish_reason":null}]}
172+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" like"},"finish_reason":null}]}
174+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" \""},"finish_reason":null}]}
176+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"List"},"finish_reason":null}]}
178+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
180+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
182+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" current"},"finish_reason":null}]}
184+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" directory"},"finish_reason":null}]}
186+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" using"},"finish_reason":null}]}
188+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ls"},"finish_reason":null}]}
190+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"\"."},"finish_reason":null}]}
192+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" That's"},"finish_reason":null}]}
194+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" within"},"finish_reason":null}]}
196+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
198+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"50"},"finish_reason":null}]}
200+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" chars"},"finish_reason":null}]}
202+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"?"},"finish_reason":null}]}
204+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" Count"},"finish_reason":null}]}
206+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":":"},"finish_reason":null}]}
208+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" List"},"finish_reason":null}]}
210+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
212+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
214+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
216+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
218+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
220+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
222+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
224+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" files"},"finish_reason":null}]}
226+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
228+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
230+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
232+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
234+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
236+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
238+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
240+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" in"},"finish_reason":null}]}
242+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
244+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
246+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
248+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
250+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
252+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
254+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
256+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" current"},"finish_reason":null}]}
258+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
260+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
262+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
264+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
266+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
268+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
270+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
272+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" directory"},"finish_reason":null}]}
274+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
276+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"9"},"finish_reason":null}]}
278+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
280+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
282+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
284+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
286+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
288+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" using"},"finish_reason":null}]}
290+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
292+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
294+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
296+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" space"},"finish_reason":null}]}
298+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
300+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
302+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
304+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ls"},"finish_reason":null}]}
306+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ("},"finish_reason":null}]}
308+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
310+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":")"},"finish_reason":null}]}
312+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
314+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" total"},"finish_reason":null}]}
316+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
318+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"4"},"finish_reason":null}]}
320+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
322+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
324+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
326+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
328+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
330+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
332+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
334+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
336+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
338+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
340+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
342+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"7"},"finish_reason":null}]}
344+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
346+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
348+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
350+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"9"},"finish_reason":null}]}
352+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
354+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
356+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
358+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"5"},"finish_reason":null}]}
360+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
362+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"1"},"finish_reason":null}]}
364+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"+"},"finish_reason":null}]}
366+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"2"},"finish_reason":null}]}
368+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" ="},"finish_reason":null}]}
370+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" "},"finish_reason":null}]}
372+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"41"},"finish_reason":null}]}
374+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" characters"},"finish_reason":null}]}
376+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
378+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" OK"},"finish_reason":null}]}
380+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":".\n\n"},"finish_reason":null}]}
382+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"Return"},"finish_reason":null}]}
384+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":" that"},"finish_reason":null}]}
386+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"reasoning_content":"."},"finish_reason":null}]}
388+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":"List"},"finish_reason":null}]}
390+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" files"},"finish_reason":null}]}
392+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" in"},"finish_reason":null}]}
394+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" current"},"finish_reason":null}]}
396+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" directory"},"finish_reason":null}]}
398+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" using"},"finish_reason":null}]}
400+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{"content":" ls"},"finish_reason":null}]}
402+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
404+ data: {"id":"chatcmpl-a1787c3e58fc5f4d633cd7f2","object":"chat.completion.chunk","created":1782413817,"model":"gpt-oss-120b","choices":[],"usage":{"prompt_tokens":155,"completion_tokens":172,"total_tokens":391,"prompt_tokens_details":{"cached_tokens":64},"cost":{"usd":0.000122704,"hypercredits":0.00245408},"remaining":{"hypercredits":0}}}
413+ duration: 531.140917ms
419+ content_length: 35898
421+ body: "{\"messages\":[{\"content\":\"You are Crush, a powerful AI Assistant that runs in the CLI.\\n\\n<critical_rules>\\nThese rules override everything else. Follow them strictly:\\n\\n1. **READ THE RELEVANT CONTEXT BEFORE EDITING**: Never edit a file you haven't already read the relevant context for in this conversation. Once read, you don't need to re-read unless it changed. Pay close attention to exact formatting, indentation, and whitespace - these must match exactly in your edits.\\n2. **BE AUTONOMOUS**: Don't ask questions - search, read, think, decide, act. Break complex tasks into steps and complete them all. Systematically try alternative strategies (different commands, search terms, tools, refactors, or scopes) until either the task is complete or you hit a hard external limit (missing credentials, permissions, files, or network access you cannot change). Only stop for actual blocking errors, not perceived difficulty.\\n3. **TEST AFTER CHANGES**: Run tests immediately after each modification.\\n4. **BE CONCISE**: Keep output concise (default <4 lines), unless explaining complex changes or asked for detail. Conciseness applies to output only, not to thoroughness of work.\\n5. **USE EXACT MATCHES**: When editing, match text exactly including whitespace, indentation, and line breaks.\\n6. **NEVER COMMIT**: Unless user explicitly says \\\"commit\\\". When committing, follow the `<git_commits>` format from the bash tool description exactly, including any configured attribution lines.\\n7. **FOLLOW MEMORY FILE INSTRUCTIONS**: If memory files contain specific instructions, preferences, or commands, you MUST follow them.\\n8. **NEVER ADD COMMENTS**: Only add comments if the user asked you to do so. Focus on *why* not *what*. NEVER communicate with the user through code comments.\\n9. **SECURITY FIRST**: Only assist with defensive security tasks. Refuse to create, modify, or improve code that may be used maliciously.\\n10. **NO URL GUESSING**: Only use URLs provided by the user or found in local files.\\n11. **NEVER PUSH TO REMOTE**: Don't push changes to remote repositories unless explicitly asked.\\n12. **DON'T REVERT CHANGES**: Don't revert changes unless they caused errors or the user explicitly asks.\\n13. **TOOL CONSTRAINTS**: Only use documented tools. Never attempt 'apply_patch' or 'apply_diff' - they don't exist. Use 'edit' or 'multiedit' instead.\\n14. **LOAD MATCHING SKILLS**: If any entry in `<available_skills>` matches the current task, you MUST call `view` on its `<location>` before taking any other action for that task. The `<description>` is only a trigger — the actual procedure, scripts, and references live in SKILL.md. Do NOT infer a skill's behavior from its description or skip loading it because you think you already know how to do the task.\\n15. **LIMIT FILE READS**: Avoid reading entire files, as they can be very large. Read only the sections you need using 'offset' and 'limit' parameters.\\n</critical_rules>\\n\\n<communication_style>\\nKeep responses minimal:\\n- ALWAYS think and respond in the same spoken language the prompt was written in.\\n- Under 4 lines of text (tool use doesn't count)\\n- Conciseness is about **text only**: always fully implement the requested feature, tests, and wiring even if that requires many tool calls.\\n- No preamble (\\\"Here's...\\\", \\\"I'll...\\\")\\n- No postamble (\\\"Let me know...\\\", \\\"Hope this helps...\\\")\\n- One-word answers when possible\\n- No emojis ever\\n- No explanations unless user asks\\n- Never send acknowledgement-only responses; after receiving new context or instructions, immediately continue the task or state the concrete next action you will take.\\n- Use rich Markdown formatting (headings, bullet lists, tables, code fences) for any multi-sentence or explanatory answer; only use plain unformatted text if the user explicitly asks.\\n\\nExamples:\\nuser: what is 2+2?\\nassistant: 4\\n\\nuser: list files in src/\\nassistant: [uses ls tool]\\nfoo.c, bar.c, baz.c\\n\\nuser: which file has the foo implementation?\\nassistant: src/foo.c\\n\\nuser: add error handling to the login function\\nassistant: [searches for login, reads file, edits with exact match, runs tests]\\nDone\\n\\nuser: Where are errors from the client handled?\\nassistant: Clients are marked as failed in the `connectToServer` function in src/services/process.go:712.\\n</communication_style>\\n\\n<code_references>\\nWhen referencing specific functions or code locations, use the pattern `file_path:line_number` to help users navigate:\\n- Example: \\\"The error is handled in src/main.go:45\\\"\\n- Example: \\\"See the implementation in pkg/utils/helper.go:123-145\\\"\\n</code_references>\\n\\n<workflow>\\nFor every task, follow this sequence internally (don't narrate it):\\n\\n**Before acting**:\\n- Search codebase for relevant files\\n- Read files to understand current state\\n- Check memory for stored commands\\n- Identify what needs to change\\n- Use `git log` and `git blame` for additional context when needed\\n\\n**While acting**:\\n- Read entire file before editing it\\n- Before editing: verify exact whitespace and indentation from View output\\n- Use exact text for find/replace (include whitespace)\\n- Make one logical change at a time\\n- After each change: run tests\\n- If tests fail: fix immediately\\n- If edit fails: read more context, don't guess - the text must match exactly\\n- Keep going until query is completely resolved before yielding to user\\n- For longer tasks, send brief progress updates (under 10 words) BUT IMMEDIATELY CONTINUE WORKING - progress updates are not stopping points\\n\\n**Before finishing**:\\n- Verify ENTIRE query is resolved (not just first step)\\n- All described next steps must be completed\\n- Cross-check the original prompt and your own mental checklist; if any feasible part remains undone, continue working instead of responding.\\n- Run lint/typecheck if in memory\\n- Verify all changes work\\n- Keep response under 4 lines\\n\\n**Key behaviors**:\\n- Use find_references before changing shared code\\n- Follow existing patterns (check similar files)\\n- If stuck, try different approach (don't repeat failures)\\n- Make decisions yourself (search first, don't ask)\\n- Fix problems at root cause, not surface-level patches\\n- Don't fix unrelated bugs or broken tests (mention them in final message if relevant)\\n</workflow>\\n\\n<decision_making>\\n**Make decisions autonomously** - don't ask when you can:\\n- Search to find the answer\\n- Read files to see patterns\\n- Check similar code\\n- Infer from context\\n- Try most likely approach\\n- When requirements are underspecified but not obviously dangerous, make the most reasonable assumptions based on project patterns and memory files, briefly state them if needed, and proceed instead of waiting for clarification.\\n\\n**Only stop/ask user if**:\\n- Truly ambiguous business requirement\\n- Multiple valid approaches with big tradeoffs\\n- Could cause data loss\\n- Exhausted all attempts and hit actual blocking errors\\n\\n**When requesting information/access**:\\n- Exhaust all available tools, searches, and reasonable assumptions first.\\n- Never say \\\"Need more info\\\" without detail.\\n- In the same message, list each missing item, why it is required, acceptable substitutes, and what you already attempted.\\n- State exactly what you will do once the information arrives so the user knows the next step.\\n\\nWhen you must stop, first finish all unblocked parts of the request, then clearly report: (a) what you tried, (b) exactly why you are blocked, and (c) the minimal external action required. Don't stop just because one path failed—exhaust multiple plausible approaches first.\\n\\n**Never stop for**:\\n- Task seems too large (break it down)\\n- Multiple files to change (change them)\\n- Concerns about \\\"session limits\\\" (no such limits exist)\\n- Work will take many steps (do all the steps)\\n\\nExamples of autonomous decisions:\\n- File location → search for similar files\\n- Test command → check package.json/memory\\n- Code style → read existing code\\n- Library choice → check what's used\\n- Naming → follow existing names\\n</decision_making>\\n\\n<editing_files>\\n**Available edit tools:**\\n- `edit` - Single find/replace in a file\\n- `multiedit` - Multiple find/replace operations in one file\\n- `write` - Create/overwrite entire file\\n\\nNever use `apply_patch` or similar - those tools don't exist.\\n\\nCritical: ALWAYS read the relevant context of files before editing them in this conversation.\\n\\nWhen using edit tools:\\n1. Read the relevant context first - note the EXACT indentation (spaces vs tabs, count)\\n2. Copy the exact text including ALL whitespace, newlines, and indentation\\n3. Include 3-5 lines of context before and after the target\\n4. Verify your old_string would appear exactly once in the file\\n5. If uncertain about whitespace, include more surrounding context\\n6. Verify edit succeeded\\n7. Run tests\\n\\n**Whitespace matters**:\\n- Count spaces/tabs carefully (use View tool line numbers as reference)\\n- Include blank lines if they exist\\n- Match line endings exactly\\n- When in doubt, include MORE context rather than less\\n\\nEfficiency tips:\\n- Don't re-read files after successful edits (tool will fail if it didn't work)\\n- Same applies for making folders, deleting files, etc.\\n\\nCommon mistakes to avoid:\\n- Editing without reading first\\n- Approximate text matches\\n- Wrong indentation (spaces vs tabs, wrong count)\\n- Missing or extra blank lines\\n- Not enough context (text appears multiple times)\\n- Trimming whitespace that exists in the original\\n- Not testing after changes\\n</editing_files>\\n\\n<whitespace_and_exact_matching>\\nThe Edit tool is extremely literal. \\\"Close enough\\\" will fail.\\n\\n**Before every edit**:\\n1. View the file and locate the exact lines to change\\n2. Copy the text EXACTLY including:\\n - Every space and tab\\n - Every blank line\\n - Opening/closing braces position\\n - Comment formatting\\n3. Include enough surrounding lines (3-5) to make it unique\\n4. Double-check indentation level matches\\n\\n**Common failures**:\\n- `func foo() {` vs `func foo(){` (space before brace)\\n- Tab vs 4 spaces vs 2 spaces\\n- Missing blank line before/after\\n- `// comment` vs `//comment` (space after //)\\n- Different number of spaces in indentation\\n\\n**If edit fails**:\\n- View the file again at the specific location\\n- Copy even more context\\n- Check for tabs vs spaces\\n- Verify line endings\\n- Try including the entire function/block if needed\\n- Never retry with guessed changes - get the exact text first\\n</whitespace_and_exact_matching>\\n\\n<task_completion>\\nEnsure every task is implemented completely, not partially or sketched.\\n\\n1. **Think before acting** (for non-trivial tasks)\\n - Identify all components that need changes (models, logic, routes, config, tests, docs)\\n - Consider edge cases and error paths upfront\\n - Form a mental checklist of requirements before making the first edit\\n - This planning happens internally - don't narrate it to the user\\n\\n2. **Implement end-to-end**\\n - Treat every request as complete work: if adding a feature, wire it fully\\n - Update all affected files (callers, configs, tests, docs)\\n - Don't leave TODOs or \\\"you'll also need to...\\\" - do it yourself\\n - No task is too large - break it down and complete all parts\\n - For multi-part prompts, treat each bullet/question as a checklist item and ensure every item is implemented or answered. Partial completion is not an acceptable final state.\\n\\n3. **Verify before finishing**\\n - Re-read the original request and verify each requirement is met\\n - Check for missing error handling, edge cases, or unwired code\\n - Run tests to confirm the implementation works\\n - Only say \\\"Done\\\" when truly done - never stop mid-task\\n</task_completion>\\n\\n<error_handling>\\nWhen errors occur:\\n1. Read complete error message\\n2. Understand root cause (isolate with debug logs or minimal reproduction if needed)\\n3. Try different approach (don't repeat same action)\\n4. Search for similar code that works\\n5. Make targeted fix\\n6. Test to verify\\n7. For each error, attempt at least two or three distinct remediation strategies (search similar code, adjust commands, narrow or widen scope, change approach) before concluding the problem is externally blocked.\\n\\nCommon errors:\\n- Import/Module → check paths, spelling, what exists\\n- Syntax → check brackets, indentation, typos\\n- Tests fail → read test, see what it expects\\n- File not found → use ls, check exact path\\n\\n**Edit tool \\\"old_string not found\\\"**:\\n- View the file again at the target location\\n- Copy the EXACT text including all whitespace\\n- Include more surrounding context (full function if needed)\\n- Check for tabs vs spaces, extra/missing blank lines\\n- Count indentation spaces carefully\\n- Don't retry with approximate matches - get the exact text\\n</error_handling>\\n\\n<memory_instructions>\\nMemory files store commands, preferences, and codebase info. Update them when you discover:\\n- Build/test/lint commands\\n- Code style preferences\\n- Important codebase patterns\\n- Useful project information\\n</memory_instructions>\\n\\n<code_conventions>\\nBefore writing code:\\n1. Check if library exists (look at imports, package.json)\\n2. Read similar code for patterns\\n3. Match existing style\\n4. Use same libraries/frameworks\\n5. Follow security best practices (never log secrets)\\n6. Don't use one-letter variable names unless requested\\n\\nNever assume libraries are available - verify first.\\n\\n**Ambition vs. precision**:\\n- New projects → be creative and ambitious with implementation\\n- Existing codebases → be surgical and precise, respect surrounding code\\n- Don't change filenames or variables unnecessarily\\n- Don't add formatters/linters/tests to codebases that don't have them\\n</code_conventions>\\n\\n<testing>\\nAfter significant changes:\\n- Start testing as specific as possible to code changed, then broaden to build confidence\\n- Use self-verification: write unit tests, add output logs, or use debug statements to verify your solutions\\n- Run relevant test suite\\n- If tests fail, fix before continuing\\n- Check memory for test commands\\n- Run lint/typecheck if available (on precise targets when possible)\\n- For formatters: iterate max 3 times to get it right; if still failing, present correct solution and note formatting issue\\n- Suggest adding commands to memory if not found\\n- Don't fix unrelated bugs or test failures (not your responsibility)\\n</testing>\\n\\n<tool_usage>\\n- Default to using tools (ls, grep, view, agent, tests, web_fetch, etc.) rather than speculation whenever they can reduce uncertainty or unlock progress, even if it takes multiple tool calls.\\n- Search before assuming\\n- Read files before editing\\n- Always use absolute paths for file operations (editing, reading, writing)\\n- Use Agent tool for complex searches\\n- Run tools in parallel when safe (no dependencies)\\n- When making multiple independent bash calls, send them in a single message with multiple tool calls for parallel execution\\n- Summarize tool output for user (they don't see it)\\n- Never use `curl` through the bash tool it is not allowed use the fetch tool instead.\\n- Only use the tools you know exist.\\n\\n<bash_commands>\\n**CRITICAL**: The `description` parameter is REQUIRED for all bash tool calls. Always provide it.\\n\\nWhen running non-trivial bash commands (especially those that modify the system):\\n- Briefly explain what the command does and why you're running it\\n- This ensures the user understands potentially dangerous operations\\n- Simple read-only commands (ls, cat, etc.) don't need explanation\\n- Use `&` for background processes that won't stop on their own (e.g., `node server.js &`)\\n- Avoid interactive commands - use non-interactive versions (e.g., `npm init -y` not `npm init`)\\n- Combine related commands to save time (e.g., `git status && git diff HEAD && git log -n 3`)\\n</bash_commands>\\n</tool_usage>\\n\\n<proactiveness>\\nBalance autonomy with user intent:\\n- When asked to do something → do it fully (including ALL follow-ups and \\\"next steps\\\")\\n- Never describe what you'll do next - just do it\\n- When the user provides new information or clarification, incorporate it immediately and keep executing instead of stopping with an acknowledgement.\\n- Responding with only a plan, outline, or TODO list (or any other purely verbal response) is failure; you must execute the plan via tools whenever execution is possible.\\n- When asked how to approach → explain first, don't auto-implement\\n- After completing work → stop, don't explain (unless asked)\\n- Don't surprise user with unexpected actions\\n</proactiveness>\\n\\n<final_answers>\\nAdapt verbosity to match the work completed:\\n\\n**Default (under 4 lines)**:\\n- Simple questions or single-file changes\\n- Casual conversation, greetings, acknowledgements\\n- One-word answers when possible\\n\\n**More detail allowed (up to 10-15 lines)**:\\n- Large multi-file changes that need walkthrough\\n- Complex refactoring where rationale adds value\\n- Tasks where understanding the approach is important\\n- When mentioning unrelated bugs/issues found\\n- Suggesting logical next steps user might want\\n- Structure longer answers with Markdown sections and lists, and put all code, commands, and config in fenced code blocks.\\n\\n**What to include in verbose answers**:\\n- Brief summary of what was done and why\\n- Key files/functions changed (with `file:line` references)\\n- Any important decisions or tradeoffs made\\n- Next steps or things user should verify\\n- Issues found but not fixed\\n\\n**What to avoid**:\\n- Don't show full file contents unless explicitly asked\\n- Don't explain how to save files or copy code (user has access to your work)\\n- Don't use \\\"Here's what I did\\\" or \\\"Let me know if...\\\" style preambles/postambles\\n- Keep tone direct and factual, like handing off work to a teammate\\n</final_answers>\\n\\n<env>\\nWorking directory: /tmp/crush-test/TestCoderAgent/glm-5.1/ls_tool\\nIs directory a git repo: no\\nPlatform: linux\\nToday's date: 1/1/2025\\n\\n</env>\\n\\n\\n\\n<available_skills>\\n <skill>\\n <name>crush-hooks</name>\\n <description>Use when the user wants to add, write, debug, or configure a Crush hook — gating or blocking tool calls, approving or rewriting tool input before execution, injecting context into tool results, or troubleshooting hook behavior in crush.json.</description>\\n <location>crush://skills/crush-hooks/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n <skill>\\n <name>jq</name>\\n <description>Use when the user needs to query, filter, reshape, extract, create, or construct JSON data — including API responses, config files, log output, or any structured data — or when helping the user write or debug JSON transformations.</description>\\n <location>crush://skills/jq/SKILL.md</location>\\n <type>builtin</type>\\n </skill>\\n</available_skills>\\n\\n<skills_usage>\\nThe `<description>` of each skill is a TRIGGER — it tells you *when* a skill applies. It is NOT a specification of what the skill does or how to do it. The procedure, scripts, commands, references, and required flags live only in the SKILL.md body. You do not know what a skill actually does until you have read its SKILL.md.\\n\\nMANDATORY activation flow:\\n1. Scan `<available_skills>` against the current user task.\\n2. If any skill's `<description>` matches, call the View tool with its `<location>` EXACTLY as shown — before any other tool call that performs the task.\\n3. Read the entire SKILL.md and follow its instructions.\\n4. Only then execute the task, using the skill's prescribed commands/tools.\\n\\nDo NOT skip step 2 because you think you already know how to do the task. Do NOT infer a skill's behavior from its name or description. If you find yourself about to run `bash`, `edit`, or any task-doing tool for a skill-eligible request without having just viewed the SKILL.md, stop and load the skill first.\\n\\nBuiltin skills (type=builtin) use virtual `crush://skills/...` location identifiers. The \\\"crush://\\\" prefix is NOT a URL, network address, or MCP resource — it is a special internal identifier the View tool understands natively. Pass the `<location>` verbatim to View.\\n\\nDo not use MCP tools (including read_mcp_resource) to load skills.\\nIf a skill mentions scripts, references, or assets, they live in the same folder as the skill itself (e.g., scripts/, references/, assets/ subdirectories within the skill's folder).\\n</skills_usage>\\n\\n\\n\\n\\n\",\"role\":\"system\"},{\"content\":\"<system_reminder>This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware.\\nIf you are working on tasks that would benefit from a todo list please use the \\\"todos\\\" tool to create one.\\nIf not, please feel free to ignore. Again do not mention this message to the user.</system_reminder>\",\"role\":\"user\"},{\"content\":\"use ls to list the files in the current directory\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_9fc14d4b22da05b9\",\"function\":{\"arguments\":\"{}\",\"name\":\"ls\"},\"type\":\"function\"}],\"role\":\"assistant\"},{\"content\":\"\\n- /tmp/crush-test/TestCoderAgent/glm-5.1/ls_tool/\\n - go.mod\\n - main.go\\n\",\"tool_call_id\":\"call_9fc14d4b22da05b9\",\"role\":\"tool\"}],\"model\":\"glm-5.1\",\"max_tokens\":10000,\"stream_options\":{\"include_usage\":true},\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"bash\",\"strict\":false,\"description\":\"Execute shell commands; long-running commands automatically move to background and return a shell ID.\\n\\n<cross_platform>\\nUses mvdan/sh interpreter (Bash-compatible on all platforms including Windows).\\nUse forward slashes for paths: \\\"ls C:/foo/bar\\\" not \\\"ls C:\\\\foo\\\\bar\\\".\\nCommon shell builtins and core utils available on Windows.\\n</cross_platform>\\n\\n<execution_steps>\\n1. Directory Verification: If creating directories/files, use LS tool to verify parent exists\\n2. Security Check: Banned commands (alias, aria2c, axel, chrome, curl, curlie, firefox, http-prompt, httpie, links, lynx, nc, safari, scp, ssh, telnet, w3m, wget, xh, doas, su, sudo, apk, apt, apt-cache, apt-get, dnf, dpkg, emerge, home-manager, makepkg, opkg, pacman, paru, pkg, pkg_add, pkg_delete, portage, rpm, yay, yum, zypper, at, batch, chkconfig, crontab, fdisk, mkfs, mount, parted, service, systemctl, umount, firewall-cmd, ifconfig, ip, iptables, netstat, pfctl, route, ufw) return error - explain to user. Safe read-only commands execute without prompts\\n3. Command Execution: Execute with proper quoting, capture output\\n4. Auto-Background: Commands exceeding 1 minute (default, configurable via `auto_background_after`) automatically move to background and return shell ID\\n5. Output Processing: Truncate if exceeds 30000 characters\\n6. Return Result: Include errors, metadata with <cwd></cwd> tags\\n</execution_steps>\\n\\n<usage_notes>\\n- Command required, working_dir optional (defaults to current directory)\\n- IMPORTANT: Use Grep/Glob/Agent tools instead of 'find'/'grep'. Use View/LS tools instead of 'cat'/'head'/'tail'/'ls'\\n- Chain with ';' or '&&', avoid newlines except in quoted strings\\n- Each command runs in independent shell (no state persistence between calls)\\n- Prefer absolute paths over 'cd' (use 'cd' only if user explicitly requests)\\n</usage_notes>\\n\\n<background_execution>\\n- Set run_in_background=true to run commands in a separate background shell\\n- Returns a shell ID for managing the background process\\n- Use job_output tool to view current output from background shell\\n- Use job_kill tool to terminate a background shell\\n- IMPORTANT: NEVER use `&` at the end of commands to run in background - use run_in_background parameter instead\\n- Commands that should run in background:\\n * Long-running servers (e.g., `npm start`, `python -m http.server`, `node server.js`)\\n * Watch/monitoring tasks (e.g., `npm run watch`, `tail -f logfile`)\\n * Continuous processes that don't exit on their own\\n * Any command expected to run indefinitely\\n- Commands that should NOT run in background:\\n * Build commands (e.g., `npm run build`, `go build`)\\n * Test suites (e.g., `npm test`, `pytest`)\\n * Git operations\\n * File operations\\n * Short-lived scripts\\n</background_execution>\\n\\n<git_message_quality>\\nThese rules apply whenever creating or updating commit messages, PR titles, or PR bodies:\\n\\n- Messages MUST be understandable to someone unfamiliar with the codebase.\\n- Before creating or updating a message, verify this litmus test: a new contributor reading only the commit message or PR title/body should understand what problem this solves, why it matters, and the impact without opening files, reading the diff, or knowing internal code names.\\n- Avoid code identifiers, filenames, function names, and implementation details unless they are necessary for understanding the user-facing impact.\\n- Bad: \\\"Add NameFromHex with sync.Once lazy init\\\"\\n- Good: \\\"Improve color name lookup performance while keeping startup fast\\\"\\n</git_message_quality>\\n\\n<commit_messages>\\nCommit messages are for future readers scanning history. Before committing:\\n\\n- Follow <git_message_quality>.\\n- Draft a concise 1-2 sentence message focusing on why the change exists and what outcome it enables, not a list of files or implementation details.\\n- Use clear, accurate verbs (\\\"add\\\"=new capability, \\\"update\\\"=enhancement, \\\"fix\\\"=bug fix) and avoid generic messages.\\n- The first line MUST be under 72 characters.\\n- Add a body only when it is needed to explain the reasoning, tradeoffs, or important context; wrap body lines at 72 characters.\\n- If the change is internal-only, still describe the benefit or maintenance outcome rather than naming private code.\\n- Bad: \\\"fix: nil pointer in session.go\\\"\\n- Good: \\\"fix: prevent session loading from crashing on missing metadata\\\"\\n- Bad: \\\"refactor: move PromptBuilder into internal/agent\\\"\\n- Good: \\\"refactor: make prompt assembly easier to maintain\\\"\\n</commit_messages>\\n\\n<git_commits>\\nWhen user asks to create git commit:\\n\\n1. Single message with three tool_use blocks (IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - git log (recent commit message style)\\n\\n2. Add relevant untracked files to staging. Don't commit files already modified at conversation start unless relevant.\\n\\n3. Analyze staged changes in <commit_analysis> tags:\\n - List changed/added files, summarize nature (feature/enhancement/bug fix/refactoring/test/docs)\\n - Brainstorm purpose/motivation, assess project impact, check for sensitive info\\n - Don't use tools beyond the context of git\\n\\n4. Draft a commit message:\\n - Follow <commit_messages>\\n - Review draft against the litmus test before committing\\n\\n5. Create commit with attribution using HEREDOC:\\n git commit -m \\\"$(cat <<'EOF'\\nCommit message here.\\n\\n\\n\U0001F498 Generated with Crush\\n\\n\\n\\nCo-Authored-By: Crush <crush@charm.land>\\n\\nEOF\\n)\\\"\\n\\n6. If pre-commit hook fails, retry ONCE. If fails again, hook preventing commit. If succeeds but files modified, MUST amend.\\n\\n7. Run git status to verify.\\n\\nNotes: Use \\\"git commit -am\\\" when possible, don't stage unrelated files, NEVER update config, don't push, no -i flags, no empty commits, return empty response, when rebasing always use -m.\\n</git_commits>\\n\\n<pull_requests>\\n\\n\\nWhen user asks you to create or update a PR:\\n\\n1. Single message with multiple tool_use blocks (VERY IMPORTANT for speed):\\n - git status (untracked files)\\n - git diff (staged/unstaged changes)\\n - Check if branch tracks remote and is up to date\\n - git log and 'git diff main...HEAD' (full commit history from main divergence)\\n\\n2. Create new branch if needed\\n\\n3. Commit changes if needed\\n\\n4. Push to remote with -u flag if needed\\n\\n5. Analyze changes in <pr_analysis> tags:\\n - List commits since diverging from main\\n - Summarize nature of changes\\n - Brainstorm purpose/motivation\\n - Assess project impact\\n - Don't use tools beyond git context\\n - Check for sensitive information\\n\\n6. Draft a PR message:\\n - Follow <git_message_quality>\\n - Draft concise (1-2 bullet points) PR summary focusing on \\\"why\\\"\\n - Ensure summary reflects ALL changes since main divergence\\n - Use clear, concise language\\n - Provide an accurate reflection of changes and purpose\\n - Avoid generic summaries; messages should be thoughtful\\n - Review draft against the litmus test before creating or updating the PR\\n\\n7. Create PR with gh pr create using HEREDOC:\\n gh pr create --title \\\"title\\\" --body \\\"$(cat <<'EOF'\\n\\n<summary>\\n\\n\U0001F498 Generated with Crush\\n\\nEOF\\n)\\\"\\n\\nImportant:\\n\\n- Return empty response - user sees gh output\\n- Never update git config\\n</pull_requests>\\n\\n<examples>\\nGood: pytest /foo/bar/tests\\nBad: cd /foo/bar && pytest tests\\n</examples>\\n\",\"parameters\":{\"properties\":{\"auto_background_after\":{\"description\":\"Seconds to wait before automatically moving the command to a background job (default: 60)\",\"type\":\"integer\"},\"command\":{\"description\":\"The command to execute\",\"type\":\"string\"},\"description\":{\"description\":\"A brief description of what the command does, try to keep it under 30 characters or so\",\"type\":\"string\"},\"run_in_background\":{\"description\":\"Set to true (boolean) to run this command in the background. Use job_output to read the output later.\",\"type\":\"boolean\"},\"working_dir\":{\"description\":\"The working directory to execute the command in (defaults to current directory)\",\"type\":\"string\"}},\"required\":[\"description\",\"command\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"download\",\"strict\":false,\"description\":\"Download a URL directly to a local file (binary-safe, streaming, max 600s timeout); overwrites without warning. For reading content into context use fetch.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The local file path where the downloaded content should be saved\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 600)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to download from\",\"type\":\"string\"}},\"required\":[\"url\",\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"edit\",\"strict\":false,\"description\":\"Edit a file by exact find-and-replace; can also create or delete content. For renames/moves use bash. For large edits use write.\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"},\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false)\",\"type\":\"boolean\"}},\"required\":[\"file_path\",\"old_string\",\"new_string\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"multiedit\",\"strict\":false,\"description\":\"Apply multiple find-and-replace edits to a single file in one operation; edits run sequentially. Prefer over edit for multiple changes to the same file. Same exact-match rules as edit apply.\",\"parameters\":{\"properties\":{\"edits\":{\"description\":\"Array of edit operations to perform sequentially on the file\",\"items\":{\"properties\":{\"new_string\":{\"description\":\"The text to replace it with\",\"type\":\"string\"},\"old_string\":{\"description\":\"The text to replace\",\"type\":\"string\"},\"replace_all\":{\"description\":\"Replace all occurrences of old_string (default false).\",\"type\":\"boolean\"}},\"required\":[\"old_string\",\"new_string\"],\"type\":\"object\"},\"type\":\"array\"},\"file_path\":{\"description\":\"The absolute path to the file to modify\",\"type\":\"string\"}},\"required\":[\"file_path\",\"edits\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"fetch\",\"strict\":false,\"description\":\"Fetch raw content from a URL as text, markdown, or html (max 100KB); no AI processing. For analysis or extraction use agentic_fetch.\\n\",\"parameters\":{\"properties\":{\"format\":{\"description\":\"The format to return the content in (text, markdown, or html)\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"},\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\"}},\"required\":[\"url\",\"format\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"glob\",\"strict\":false,\"description\":\"Find files by name/pattern (glob syntax), sorted by modification time; max 100 results; skips hidden files. Use grep to search file contents.\\n\",\"parameters\":{\"properties\":{\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The glob pattern to match files against\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"grep\",\"strict\":false,\"description\":\"Search file contents by regex or literal text; returns matching file paths sorted by modification time (max 100); respects .gitignore. Use glob to filter by filename, not contents.\\n\",\"parameters\":{\"properties\":{\"include\":{\"description\":\"File pattern to include in the search (e.g. \\\"*.js\\\", \\\"*.{ts,tsx}\\\")\",\"type\":\"string\"},\"literal_text\":{\"description\":\"If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.\",\"type\":\"boolean\"},\"path\":{\"description\":\"The directory to search in. Defaults to the current working directory.\",\"type\":\"string\"},\"pattern\":{\"description\":\"The regex pattern to search for in file contents\",\"type\":\"string\"}},\"required\":[\"pattern\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"ls\",\"strict\":false,\"description\":\"List files and directories as a tree; skips hidden files and common system dirs; max 1000 files. Use glob to find files by pattern, grep to search contents.\\n\",\"parameters\":{\"properties\":{\"depth\":{\"description\":\"The maximum depth to traverse\",\"type\":\"integer\"},\"ignore\":{\"description\":\"List of glob patterns to ignore\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"path\":{\"description\":\"The path to the directory to list (defaults to current working directory)\",\"type\":\"string\"}},\"required\":[],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"sourcegraph\",\"strict\":false,\"description\":\"Search code across public GitHub repositories via Sourcegraph; supports regex, language/repo/file filters, and symbol search (max 20 results). Only searches public repos.\\n\",\"parameters\":{\"properties\":{\"context_window\":{\"description\":\"The context around the match to return (default: 10 lines)\",\"type\":\"integer\"},\"count\":{\"description\":\"Optional number of results to return (default: 10, max: 20)\",\"type\":\"integer\"},\"query\":{\"description\":\"The Sourcegraph search query\",\"type\":\"string\"},\"timeout\":{\"description\":\"Optional timeout in seconds (max 120)\",\"type\":\"integer\"}},\"required\":[\"query\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"view\",\"strict\":false,\"description\":\"Read a file by path with line numbers; supports offset and line limit (default 200, max 200KB returned file content section); renders images (PNG, JPEG, GIF, WebP); use ls for directories.\\n\",\"parameters\":{\"properties\":{\"file_path\":{\"description\":\"The path to the file to read\",\"type\":\"string\"},\"limit\":{\"description\":\"The number of lines to read (defaults to 200)\",\"type\":\"integer\"},\"offset\":{\"description\":\"The line number to start reading from (0-based)\",\"type\":\"integer\"}},\"required\":[\"file_path\"],\"type\":\"object\"}},\"type\":\"function\"},{\"function\":{\"name\":\"write\",\"strict\":false,\"description\":\"Create or overwrite a file with given content; auto-creates parent dirs. Cannot append. Read the file first to avoid conflicts. For surgical changes use edit or multiedit.\",\"parameters\":{\"properties\":{\"content\":{\"description\":\"The content to write to the file\",\"type\":\"string\"},\"file_path\":{\"description\":\"The path to the file to write\",\"type\":\"string\"}},\"required\":[\"file_path\",\"content\"],\"type\":\"object\"}},\"type\":\"function\"}],\"stream\":true}"
428+ - Charm-Crush/devel (https://charm.land/crush)
429+ url: https://hyper.charm.land/v1/chat/completions
438+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
440+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"Two"},"finish_reason":null}]}
442+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" files"},"finish_reason":null}]}
444+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" in"},"finish_reason":null}]}
446+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" the"},"finish_reason":null}]}
448+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" current"},"finish_reason":null}]}
450+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" directory"},"finish_reason":null}]}
452+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":":\n"},"finish_reason":null}]}
454+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"-"},"finish_reason":null}]}
456+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `"},"finish_reason":null}]}
458+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"go"},"finish_reason":null}]}
460+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":".mod"},"finish_reason":null}]}
462+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`\n"},"finish_reason":null}]}
464+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"-"},"finish_reason":null}]}
466+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":" `"},"finish_reason":null}]}
468+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"main"},"finish_reason":null}]}
470+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":".go"},"finish_reason":null}]}
472+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{"content":"`"},"finish_reason":null}]}
474+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
476+ data: {"id":"chatcmpl-0df4ed5d1b2533d9447fa033","object":"chat.completion.chunk","created":1782413819,"model":"glm-5.1","choices":[],"usage":{"prompt_tokens":8195,"completion_tokens":19,"total_tokens":8214,"cost":{"usd":0.0115566,"hypercredits":0.231132},"remaining":{"hypercredits":0}}}
485+ duration: 1.065962584s
internal/agent/testdata/TestCoderAgent/glm-5.1/multiedit_tool.yamlnew file+1439
This diff is too big to show here.
internal/agent/testdata/TestCoderAgent/glm-5.1/parallel_tool_calls.yamlnew file+685
This diff is too big to show here.
internal/agent/testdata/TestCoderAgent/glm-5.1/read_a_file.yamlnew file+413
This diff is too big to show here.
internal/agent/testdata/TestCoderAgent/glm-5.1/simple_test.yamlnew file+277
This diff is too big to show here.
internal/agent/testdata/TestCoderAgent/glm-5.1/sourcegraph_tool.yamlnew file+1479
This diff is too big to show here.
internal/agent/testdata/TestCoderAgent/glm-5.1/update_a_file.yamlnew file+747
This diff is too big to show here.
internal/agent/testdata/TestCoderAgent/glm-5.1/write_tool.yamlnew file+547
This diff is too big to show here.
internal/agent/tools/bash.gonew file+437
This diff is too big to show here.
internal/agent/tools/bash.md.tplnew file+173
This diff is too big to show here.
internal/agent/tools/bash_test.gonew file+213
This diff is too big to show here.
internal/agent/tools/context_test.gonew file+233
This diff is too big to show here.
internal/agent/tools/crush_info.gonew file+487
This diff is too big to show here.
internal/agent/tools/crush_info.mdnew file+19
This diff is too big to show here.
internal/agent/tools/crush_info_test.gonew file+505
This diff is too big to show here.
internal/agent/tools/crush_logs.gonew file+514
This diff is too big to show here.
internal/agent/tools/crush_logs.md.tplnew file+13
This diff is too big to show here.
internal/agent/tools/crush_logs_test.gonew file+529
This diff is too big to show here.
internal/agent/tools/diagnostics.gonew file+265
This diff is too big to show here.
internal/agent/tools/diagnostics.mdnew file+1
This diff is too big to show here.
internal/agent/tools/download.gonew file+166
This diff is too big to show here.
internal/agent/tools/download.md.tplnew file+1
This diff is too big to show here.
internal/agent/tools/edit.gonew file+482
This diff is too big to show here.
internal/agent/tools/edit.mdnew file+1
This diff is too big to show here.
internal/agent/tools/fetch.gonew file+213
This diff is too big to show here.
internal/agent/tools/fetch.md.tplnew file+2
This diff is too big to show here.
internal/agent/tools/fetch_helpers.gonew file+175
This diff is too big to show here.
internal/agent/tools/fetch_types.gonew file+50
This diff is too big to show here.
internal/agent/tools/glob.gonew file+195
This diff is too big to show here.
internal/agent/tools/glob.md.tplnew file+1
This diff is too big to show here.
internal/agent/tools/glob_test.gonew file+74
This diff is too big to show here.
internal/agent/tools/grep.gonew file+443
This diff is too big to show here.
internal/agent/tools/grep.md.tplnew file+1
This diff is too big to show here.
internal/agent/tools/grep_test.gonew file+421
This diff is too big to show here.
internal/agent/tools/job_kill.gonew file+60
This diff is too big to show here.
internal/agent/tools/job_kill.mdnew file+18
This diff is too big to show here.
internal/agent/tools/job_output.gonew file+92
This diff is too big to show here.
internal/agent/tools/job_output.mdnew file+1
This diff is too big to show here.
internal/agent/tools/job_test.gonew file+334
This diff is too big to show here.
internal/agent/tools/list_mcp_resources.gonew file+100
This diff is too big to show here.
internal/agent/tools/list_mcp_resources.mdnew file+1
This diff is too big to show here.
internal/agent/tools/ls.gonew file+267
This diff is too big to show here.
internal/agent/tools/ls.md.tplnew file+1
This diff is too big to show here.
internal/agent/tools/lsp_restart.gonew file+80
This diff is too big to show here.
internal/agent/tools/lsp_restart.mdnew file+1
This diff is too big to show here.
internal/agent/tools/mcp-tools.gonew file+151
This diff is too big to show here.
internal/agent/tools/mcp/init.gonew file+554
This diff is too big to show here.
internal/agent/tools/mcp/init_test.gonew file+526
This diff is too big to show here.
internal/agent/tools/mcp/prompts.gonew file+88
This diff is too big to show here.
internal/agent/tools/mcp/resources.gonew file+109
This diff is too big to show here.
internal/agent/tools/mcp/tools.gonew file+248
This diff is too big to show here.
internal/agent/tools/mcp/tools_test.gonew file+117
This diff is too big to show here.
internal/agent/tools/multiedit.gonew file+451
This diff is too big to show here.
internal/agent/tools/multiedit.mdnew file+1
This diff is too big to show here.
internal/agent/tools/multiedit_test.gonew file+214
This diff is too big to show here.
internal/agent/tools/read_mcp_resource.gonew file+103
This diff is too big to show here.
internal/agent/tools/read_mcp_resource.mdnew file+1
This diff is too big to show here.
internal/agent/tools/references.gonew file+186
This diff is too big to show here.
internal/agent/tools/references.mdnew file+1
This diff is too big to show here.
internal/agent/tools/rg.gonew file+62
This diff is too big to show here.
internal/agent/tools/safe.gonew file+163
This diff is too big to show here.
internal/agent/tools/safe_test.gonew file+74
This diff is too big to show here.
internal/agent/tools/search.gonew file+219
This diff is too big to show here.
internal/agent/tools/sourcegraph.gonew file+285
This diff is too big to show here.
internal/agent/tools/sourcegraph.md.tplnew file+1
This diff is too big to show here.
internal/agent/tools/testdata/grep.txtnew file+3
This diff is too big to show here.
internal/agent/tools/todos.gonew file+135
This diff is too big to show here.
internal/agent/tools/todos.mdnew file+1
This diff is too big to show here.
internal/agent/tools/tools.gonew file+105
This diff is too big to show here.
internal/agent/tools/view.gonew file+496
This diff is too big to show here.
internal/agent/tools/view.md.tplnew file+1
This diff is too big to show here.
internal/agent/tools/view_test.gonew file+356
This diff is too big to show here.
internal/agent/tools/web_fetch.gonew file+80
This diff is too big to show here.
internal/agent/tools/web_fetch.md.tplnew file+2
This diff is too big to show here.
internal/agent/tools/web_search.gonew file+62
This diff is too big to show here.
internal/agent/tools/web_search.md.tplnew file+2
This diff is too big to show here.
internal/agent/tools/write.gonew file+182
This diff is too big to show here.
internal/agent/tools/write.mdnew file+1
This diff is too big to show here.
internal/agent/tools/write_test.gonew file+49
This diff is too big to show here.
internal/agent/usage_fallback.gonew file+167
This diff is too big to show here.
internal/agent/usage_fallback_test.gonew file+339
This diff is too big to show here.
internal/app/app.go+568−124
This diff is too big to show here.
internal/app/app_test.gonew file+183
This diff is too big to show here.
internal/app/lsp.godeleted−118
This diff is too big to show here.
internal/app/lsp_events.gonew file+100
This diff is too big to show here.
internal/app/provider.gonew file+95
This diff is too big to show here.
internal/app/provider_test.gonew file+210
This diff is too big to show here.
internal/app/resolve_session_test.gonew file+174
This diff is too big to show here.
internal/app/testing.gonew file+72
This diff is too big to show here.
internal/backend/accepted_run_integration_test.gonew file+131
This diff is too big to show here.
internal/backend/agent.gonew file+273
This diff is too big to show here.
internal/backend/agent_runcomplete_test.gonew file+163
This diff is too big to show here.
internal/backend/agent_test.gonew file+164
This diff is too big to show here.
internal/backend/backend.gonew file+792
This diff is too big to show here.
internal/backend/backend_skills_test.gonew file+167
This diff is too big to show here.
internal/backend/backend_test.gonew file+1241
This diff is too big to show here.
internal/backend/config.gonew file+307
This diff is too big to show here.
internal/backend/config_test.gonew file+205
This diff is too big to show here.
internal/backend/events.gonew file+109
This diff is too big to show here.
internal/backend/filetracker.gonew file+37
This diff is too big to show here.
internal/backend/permission.gonew file+60
This diff is too big to show here.
internal/backend/race_off_test.gonew file+5
This diff is too big to show here.
internal/backend/race_on_test.gonew file+5
This diff is too big to show here.
internal/backend/session.gonew file+132
This diff is too big to show here.
internal/backend/shell_command_test.gonew file+54
This diff is too big to show here.
internal/backend/testing.gonew file+69
This diff is too big to show here.
internal/backend/util.gonew file+22
This diff is too big to show here.
internal/client/client.gonew file+213
This diff is too big to show here.
internal/client/config.gonew file+345
This diff is too big to show here.
internal/client/config_test.gonew file+101
This diff is too big to show here.
internal/client/dial_other.gonew file+13
This diff is too big to show here.
internal/client/dial_windows.gonew file+15
This diff is too big to show here.
internal/client/proto.gonew file+861
This diff is too big to show here.
internal/client/proto_test.gonew file+178
This diff is too big to show here.
internal/clipboard/clipboard.gonew file+44
This diff is too big to show here.
internal/clipboard/clipboard_not_supported.gonew file+13
This diff is too big to show here.
internal/clipboard/clipboard_supported.gonew file+30
This diff is too big to show here.
internal/cmd/clientserverrace/race_test.gonew file+361
This diff is too big to show here.
internal/cmd/dirs.gonew file+91
This diff is too big to show here.
internal/cmd/gitignore/defaultnew file+4
This diff is too big to show here.
internal/cmd/gitignore/oldnew file+1
This diff is too big to show here.
internal/cmd/login.gonew file+229
This diff is too big to show here.
internal/cmd/login_test.gonew file+21
This diff is too big to show here.
internal/cmd/logout.gonew file+182
This diff is too big to show here.
internal/cmd/logout_test.gonew file+41
This diff is too big to show here.
internal/cmd/logs.go+18−9
This diff is too big to show here.
internal/cmd/models.gonew file+155
This diff is too big to show here.
internal/cmd/projects.gonew file+77
This diff is too big to show here.
internal/cmd/projects_test.gonew file+56
This diff is too big to show here.
internal/cmd/root.go+724−88
This diff is too big to show here.
internal/cmd/root_other.gonew file+15
This diff is too big to show here.
internal/cmd/root_windows.gonew file+18
This diff is too big to show here.
internal/cmd/run.gonew file+664
This diff is too big to show here.
internal/cmd/run_stream_test.gonew file+417
This diff is too big to show here.
internal/cmd/schema.go+33−3
This diff is too big to show here.
internal/cmd/schema_test.gonew file+59
This diff is too big to show here.
internal/cmd/server.gonew file+99
This diff is too big to show here.
internal/cmd/server_other.gonew file+12
This diff is too big to show here.
internal/cmd/server_windows.gonew file+10
This diff is too big to show here.
internal/cmd/session.gonew file+728
This diff is too big to show here.
internal/cmd/stats.gonew file+390
This diff is too big to show here.
internal/cmd/stats/AGENTS.mdnew file+3
This diff is too big to show here.
internal/cmd/stats/footer.svgnew file+838
This diff is too big to show here.
internal/cmd/stats/header.svgnew file+673
This diff is too big to show here.
internal/cmd/stats/heartbit.svgnew file+43
This diff is too big to show here.
internal/cmd/stats/index.cssnew file+270
This diff is too big to show here.
internal/cmd/stats/index.htmlnew file+136
This diff is too big to show here.
internal/cmd/stats/index.jsnew file+356
This diff is too big to show here.
internal/cmd/update_providers.gonew file+82
This diff is too big to show here.
internal/commands/commands.gonew file+239
This diff is too big to show here.
internal/commands/commands_test.gonew file+114
This diff is too big to show here.
internal/config/agent_id_test.gonew file+29
This diff is too big to show here.
internal/config/atomicwrite.gonew file+38
This diff is too big to show here.
internal/config/atomicwrite_test.gonew file+43
This diff is too big to show here.
internal/config/attribution_migration_test.gonew file+93
This diff is too big to show here.
internal/config/catwalk.gonew file+82
This diff is too big to show here.
internal/config/catwalk_test.gonew file+221
This diff is too big to show here.
internal/config/clone_test.gonew file+46
This diff is too big to show here.
internal/config/config.go+620−175
This diff is too big to show here.
internal/config/copilot.gonew file+1
This diff is too big to show here.
internal/config/docker_mcp.gonew file+141
This diff is too big to show here.
internal/config/docker_mcp_test.gonew file+195
This diff is too big to show here.
internal/config/hyper.gonew file+124
This diff is too big to show here.
internal/config/hyper_test.gonew file+205
This diff is too big to show here.
internal/config/init.go+51−30
This diff is too big to show here.
internal/config/load.go+917−166
This diff is too big to show here.
internal/config/load_bench_test.gonew file+103
This diff is too big to show here.
internal/config/load_test.go+1303−197
This diff is too big to show here.
internal/config/lsp_defaults_test.gonew file+35
This diff is too big to show here.
internal/config/mcp_resolved_url_test.gonew file+105
This diff is too big to show here.
internal/config/merge.godeleted−16
This diff is too big to show here.
internal/config/merge_test.godeleted−27
This diff is too big to show here.
internal/config/provider.go+172−69
This diff is too big to show here.
internal/config/provider_empty_test.go+20−28
This diff is too big to show here.
internal/config/provider_test.go+277−42
This diff is too big to show here.
internal/config/recent_models_test.gonew file+158
This diff is too big to show here.
internal/config/refresh_singleflight_test.gonew file+175
This diff is too big to show here.
internal/config/reload_hooks_test.gonew file+102
This diff is too big to show here.
internal/config/resolve.go+140−131
This diff is too big to show here.
internal/config/resolve_real_test.gonew file+512
This diff is too big to show here.
internal/config/resolve_test.go+185−288
This diff is too big to show here.
internal/config/scope.gonew file+29
This diff is too big to show here.
internal/config/scopeb_race_test.gonew file+74
This diff is too big to show here.
internal/config/store.gonew file+1078
This diff is too big to show here.
internal/config/store_test.gonew file+784
This diff is too big to show here.
internal/config/update_model_bench_test.gonew file+108
This diff is too big to show here.
internal/csync/maps.go+57−4
This diff is too big to show here.
internal/csync/maps_test.go+63
This diff is too big to show here.
internal/csync/slices.go+12−38
This diff is too big to show here.
internal/csync/slices_test.go+38−107
This diff is too big to show here.
internal/csync/value.gonew file+44
This diff is too big to show here.
internal/csync/value_test.gonew file+97
This diff is too big to show here.
internal/csync/versionedmap.gonew file+56
This diff is too big to show here.
internal/csync/versionedmap_test.gonew file+89
This diff is too big to show here.
internal/db/connect.go+191−31
This diff is too big to show here.
internal/db/connect_modernc.gonew file+31
This diff is too big to show here.
internal/db/connect_ncruces.gonew file+33
This diff is too big to show here.
internal/db/connect_test.gonew file+210
This diff is too big to show here.
internal/db/datadirlock.gonew file+131
This diff is too big to show here.
This diff is too big to show here.
internal/db/embed.godeleted−6
This diff is too big to show here.
internal/db/files.sql.go+21−5
This diff is too big to show here.
internal/db/messages.sql.go+148−12
This diff is too big to show here.
internal/db/migrations/20250810000000_add_is_summary_message.sqlnew file+5
This diff is too big to show here.
internal/db/migrations/20250812000000_add_todos_to_sessions.sqlnew file+9
This diff is too big to show here.
internal/db/migrations/20260127000000_add_read_files_table.sqlnew file+20
This diff is too big to show here.
internal/db/migrations/20260701000000_add_composite_indexes.sqlnew file+12
This diff is too big to show here.
internal/db/migrations/20260702000000_add_hot_path_indexes.sqlnew file+14
This diff is too big to show here.
internal/db/models.go+18−10
This diff is too big to show here.
internal/db/querier.go+20−1
This diff is too big to show here.
internal/db/read_files.sql.gonew file+79
This diff is too big to show here.
internal/db/sessions.sql.go+117−7
This diff is too big to show here.
internal/db/sql/files.sql+12−4
This diff is too big to show here.
internal/db/sql/messages.sql+21−1
This diff is too big to show here.
internal/db/sql/read_files.sqlnew file+20
This diff is too big to show here.
internal/db/sql/sessions.sql+27−2
This diff is too big to show here.
internal/db/sql/stats.sqlnew file+93
This diff is too big to show here.
internal/db/stats.sql.gonew file+367
This diff is too big to show here.
internal/diffdetect/detect.gonew file+36
This diff is too big to show here.
internal/diffdetect/detect_test.gonew file+152
This diff is too big to show here.
internal/discover/discover.gonew file+145
This diff is too big to show here.
internal/discover/discover_test.gonew file+221
This diff is too big to show here.
internal/discover/enricher.gonew file+60
This diff is too big to show here.
internal/discover/litellm.gonew file+87
This diff is too big to show here.
internal/discover/litellm_test.gonew file+173
This diff is too big to show here.
internal/discover/llamacpp.gonew file+83
This diff is too big to show here.
internal/discover/llamacpp_test.gonew file+135
This diff is too big to show here.
internal/discover/lmstudio.gonew file+95
This diff is too big to show here.
internal/discover/lmstudio_test.gonew file+154
This diff is too big to show here.
internal/discover/ollama.gonew file+105
This diff is too big to show here.
internal/discover/ollama_test.gonew file+131
This diff is too big to show here.
internal/discover/omlx.gonew file+73
This diff is too big to show here.
internal/discover/omlx_test.gonew file+92
This diff is too big to show here.
internal/dns/android.gonew file+41
This diff is too big to show here.
This diff is too big to show here.
internal/env/env_test.go+6−4
This diff is too big to show here.
internal/event/all.gonew file+83
This diff is too big to show here.
internal/event/event.gonew file+162
This diff is too big to show here.
internal/event/event_test.gonew file+105
This diff is too big to show here.
internal/event/identifier.gonew file+49
This diff is too big to show here.
internal/event/logger.gonew file+28
This diff is too big to show here.
internal/filepathext/filepath.gonew file+52
This diff is too big to show here.
internal/filepathext/filepath_test.gonew file+37
This diff is too big to show here.
internal/filetracker/service.gonew file+110
This diff is too big to show here.
internal/filetracker/service_test.gonew file+116
This diff is too big to show here.
internal/format/spinner.go+13−25
This diff is too big to show here.
internal/fsext/drive_other.gonew file+16
This diff is too big to show here.
internal/fsext/drive_windows.gonew file+26
This diff is too big to show here.
internal/fsext/expand.gonew file+29
This diff is too big to show here.
internal/fsext/fileutil.go+148−127
This diff is too big to show here.
internal/fsext/fileutil_dirtrim_test.gonew file+32
This diff is too big to show here.
internal/fsext/fileutil_test.gonew file+269
This diff is too big to show here.
internal/fsext/ignore_test.gonew file+122
This diff is too big to show here.
internal/fsext/lookup.gonew file+276
This diff is too big to show here.
internal/fsext/lookup_test.gonew file+562
This diff is too big to show here.
internal/fsext/ls.go+256−104
This diff is too big to show here.
internal/fsext/ls_test.gonew file+60
This diff is too big to show here.
internal/fsext/owner_others.gonew file+27
This diff is too big to show here.
internal/fsext/owner_windows.gonew file+22
This diff is too big to show here.
internal/fsext/paste.gonew file+129
This diff is too big to show here.
internal/fsext/paste_test.gonew file+149
This diff is too big to show here.
internal/herdr/client.gonew file+405
This diff is too big to show here.
internal/herdr/client_test.gonew file+158
This diff is too big to show here.
internal/herdr/translate.gonew file+150
This diff is too big to show here.
internal/herdr/translate_test.gonew file+145
This diff is too big to show here.
internal/history/file.go+28−16
This diff is too big to show here.
internal/home/home.gonew file+47
This diff is too big to show here.
internal/home/home_test.gonew file+26
This diff is too big to show here.
internal/hooks/hooks.gonew file+193
This diff is too big to show here.
internal/hooks/hooks_test.gonew file+757
This diff is too big to show here.
internal/hooks/input.gonew file+211
This diff is too big to show here.
internal/hooks/runner.gonew file+265
This diff is too big to show here.
internal/llm/agent/agent-tool.godeleted−106
This diff is too big to show here.
internal/llm/agent/agent.godeleted−948
This diff is too big to show here.
internal/llm/agent/mcp-tools.godeleted−249
This diff is too big to show here.
internal/llm/prompt/coder.godeleted−88
This diff is too big to show here.
internal/llm/prompt/coder.mddeleted−267
This diff is too big to show here.
internal/llm/prompt/init.mddeleted−10
This diff is too big to show here.
internal/llm/prompt/initialize.godeleted−10
This diff is too big to show here.
internal/llm/prompt/prompt.godeleted−153
This diff is too big to show here.
internal/llm/prompt/prompt_test.godeleted−123
This diff is too big to show here.
internal/llm/prompt/summarize.mddeleted−11
This diff is too big to show here.
internal/llm/prompt/summarizer.godeleted−10
This diff is too big to show here.
internal/llm/prompt/task.godeleted−15
This diff is too big to show here.
internal/llm/prompt/title.godeleted−10
This diff is too big to show here.
internal/llm/prompt/title.mddeleted−8
This diff is too big to show here.
internal/llm/provider/anthropic.godeleted−569
This diff is too big to show here.
internal/llm/provider/azure.godeleted−32
This diff is too big to show here.
internal/llm/provider/bedrock.godeleted−93
This diff is too big to show here.
internal/llm/provider/gemini.godeleted−562
This diff is too big to show here.
internal/llm/provider/openai.godeleted−534
This diff is too big to show here.
internal/llm/provider/openai_test.godeleted−90
This diff is too big to show here.
internal/llm/provider/provider.godeleted−204
This diff is too big to show here.
internal/llm/provider/vertexai.godeleted−29
This diff is too big to show here.
internal/llm/tools/bash.godeleted−468
This diff is too big to show here.
internal/llm/tools/diagnostics.godeleted−311
This diff is too big to show here.
internal/llm/tools/download.godeleted−223
This diff is too big to show here.
internal/llm/tools/edit.godeleted−541
This diff is too big to show here.
internal/llm/tools/fetch.godeleted−263
This diff is too big to show here.
internal/llm/tools/file.godeleted−53
This diff is too big to show here.
internal/llm/tools/glob.godeleted−187
This diff is too big to show here.
internal/llm/tools/grep.godeleted−462
This diff is too big to show here.
internal/llm/tools/grep_test.godeleted−77
This diff is too big to show here.
internal/llm/tools/ls.godeleted−235
This diff is too big to show here.
internal/llm/tools/multiedit.godeleted−467
This diff is too big to show here.
internal/llm/tools/safe.godeleted−85
This diff is too big to show here.
internal/llm/tools/sourcegraph.godeleted−394
This diff is too big to show here.
internal/llm/tools/tools.godeleted−85
This diff is too big to show here.
internal/llm/tools/view.godeleted−327
This diff is too big to show here.
internal/llm/tools/write.godeleted−240
This diff is too big to show here.
internal/lock/lock.gonew file+75
This diff is too big to show here.
internal/lock/lock_test.gonew file+168
This diff is too big to show here.
internal/lock/lock_unix.gonew file+45
This diff is too big to show here.
internal/lock/lock_windows.gonew file+57
This diff is too big to show here.
internal/log/http.gonew file+131
This diff is too big to show here.
internal/log/http_test.gonew file+73
This diff is too big to show here.
This diff is too big to show here.
internal/lsp/client.go+471−589
This diff is too big to show here.
internal/lsp/client_test.gonew file+204
This diff is too big to show here.
internal/lsp/handlers.go+50−36
This diff is too big to show here.
internal/lsp/language.godeleted−132
This diff is too big to show here.
internal/lsp/manager.gonew file+412
This diff is too big to show here.
internal/lsp/manager_test.gonew file+35
This diff is too big to show here.
internal/lsp/methods.godeleted−554
This diff is too big to show here.
internal/lsp/protocol.godeleted−48
This diff is too big to show here.
internal/lsp/protocol/interface.godeleted−117
This diff is too big to show here.
internal/lsp/protocol/tables.godeleted−30
This diff is too big to show here.
internal/lsp/protocol/tsdocument-changes.godeleted−81
This diff is too big to show here.
internal/lsp/protocol/uri.godeleted−229
This diff is too big to show here.
internal/lsp/transport.godeleted−275
This diff is too big to show here.
internal/lsp/util/edit.go+95−47
This diff is too big to show here.
internal/lsp/util/edit_test.gonew file+376
This diff is too big to show here.
internal/lsp/watcher/ulimit_bsd.godeleted−25
This diff is too big to show here.
internal/lsp/watcher/ulimit_darwin.godeleted−24
This diff is too big to show here.
internal/lsp/watcher/ulimit_fallback.godeleted−8
This diff is too big to show here.
internal/lsp/watcher/ulimit_linux.godeleted−25
This diff is too big to show here.
internal/lsp/watcher/ulimit_windows.godeleted−38
This diff is too big to show here.
internal/lsp/watcher/watcher.godeleted−975
This diff is too big to show here.
internal/message/attachment.go+16
This diff is too big to show here.
internal/message/content.go+321−45
This diff is too big to show here.
internal/message/content_test.gonew file+142
This diff is too big to show here.
internal/message/message.go+493−83
This diff is too big to show here.
internal/message/message_test.gonew file+695
This diff is too big to show here.
internal/oauth/copilot/client.gonew file+94
This diff is too big to show here.
internal/oauth/copilot/client_test.gonew file+70
This diff is too big to show here.
internal/oauth/copilot/disk.gonew file+36
This diff is too big to show here.
internal/oauth/copilot/http.gonew file+17
This diff is too big to show here.
internal/oauth/copilot/oauth.gonew file+200
This diff is too big to show here.
internal/oauth/copilot/urls.gonew file+6
This diff is too big to show here.
internal/oauth/hyper/device.gonew file+251
This diff is too big to show here.
internal/oauth/token.gonew file+57
This diff is too big to show here.
internal/permission/permission.go+194−90
This diff is too big to show here.
internal/permission/permission_test.go+381−17
This diff is too big to show here.
internal/projects/projects.gonew file+126
This diff is too big to show here.
internal/projects/projects_test.gonew file+186
This diff is too big to show here.
internal/proto/agent.gonew file+82
This diff is too big to show here.
internal/proto/history.gonew file+12
This diff is too big to show here.
internal/proto/mcp.gonew file+172
This diff is too big to show here.
internal/proto/message.gonew file+714
This diff is too big to show here.
internal/proto/permission.gonew file+147
This diff is too big to show here.
internal/proto/permission_test.gonew file+186
This diff is too big to show here.
internal/proto/proto.gonew file+309
This diff is too big to show here.
internal/proto/requests.gonew file+137
This diff is too big to show here.
internal/proto/requests_test.gonew file+106
This diff is too big to show here.
internal/proto/server.gonew file+6
This diff is too big to show here.
internal/proto/session.gonew file+37
This diff is too big to show here.
internal/proto/skills.gonew file+28
This diff is too big to show here.
internal/proto/tools.gonew file+234
This diff is too big to show here.
internal/proto/version.gonew file+10
This diff is too big to show here.
internal/pubsub/broker.go+189−29
This diff is too big to show here.
internal/pubsub/broker_test.gonew file+117
This diff is too big to show here.
internal/pubsub/events.go+42−6
This diff is too big to show here.
internal/server/agent_cancel_test.gonew file+227
This diff is too big to show here.
internal/server/config.gonew file+525
This diff is too big to show here.
internal/server/e2e_agent_test.gonew file+742
This diff is too big to show here.
internal/server/e2e_test.gonew file+612
This diff is too big to show here.
internal/server/events.gonew file+311
This diff is too big to show here.
internal/server/events_test.gonew file+182
This diff is too big to show here.
internal/server/logging.gonew file+53
This diff is too big to show here.
internal/server/multiclient_test.gonew file+230
This diff is too big to show here.
internal/server/net_other.gonew file+61
This diff is too big to show here.
internal/server/net_windows.gonew file+37
This diff is too big to show here.
internal/server/proto.gonew file+1129
This diff is too big to show here.
internal/server/recover.gonew file+59
This diff is too big to show here.
internal/server/recover_test.gonew file+94
This diff is too big to show here.
internal/server/server.gonew file+286
This diff is too big to show here.
internal/server/sessions_isbusy_test.gonew file+334
This diff is too big to show here.
internal/server/socket.gonew file+10
This diff is too big to show here.
internal/server/socket_classify.gonew file+27
This diff is too big to show here.
internal/server/socket_test.gonew file+193
This diff is too big to show here.
internal/session/session.go+217−10
This diff is too big to show here.
internal/session/session_test.gonew file+81
This diff is too big to show here.
internal/shell/background.gonew file+245
This diff is too big to show here.
internal/shell/background_test.gonew file+330
This diff is too big to show here.
internal/shell/command_block_test.go+273−20
This diff is too big to show here.
internal/shell/coreutils.go+11−51
This diff is too big to show here.
internal/shell/dispatch.gonew file+425
This diff is too big to show here.
internal/shell/dispatch_test.gonew file+594
This diff is too big to show here.
internal/shell/dispatch_windows_test.gonew file+40
This diff is too big to show here.
internal/shell/doc.go+1−6
This diff is too big to show here.
internal/shell/exec_unix.gonew file+108
This diff is too big to show here.
internal/shell/exec_windows.gonew file+23
This diff is too big to show here.
internal/shell/expand.gonew file+162
This diff is too big to show here.
internal/shell/expand_test.gonew file+241
This diff is too big to show here.
internal/shell/isolation_unix_test.gonew file+143
This diff is too big to show here.
internal/shell/jq.gonew file+342
This diff is too big to show here.
internal/shell/jq_test.gonew file+212
This diff is too big to show here.
internal/shell/persist_message.gonew file+44
This diff is too big to show here.
internal/shell/persist_message_test.gonew file+69
This diff is too big to show here.
internal/shell/persistent.godeleted−37
This diff is too big to show here.
internal/shell/run.gonew file+345
This diff is too big to show here.
internal/shell/run_test.gonew file+364
This diff is too big to show here.
internal/shell/shell.go+117−61
This diff is too big to show here.
internal/shell/shell_test.go+2−2
This diff is too big to show here.
internal/shell/stream.gonew file+52
This diff is too big to show here.
internal/skills/builtin/crush-config/SKILL.mdnew file+370
This diff is too big to show here.
internal/skills/builtin/crush-hooks/SKILL.mdnew file+209
This diff is too big to show here.
internal/skills/builtin/jq/SKILL.mdnew file+97
This diff is too big to show here.
internal/skills/catalog.gonew file+154
This diff is too big to show here.
internal/skills/diagnostics_test.gonew file+104
This diff is too big to show here.
internal/skills/embed.gonew file+79
This diff is too big to show here.
internal/skills/manager.gonew file+227
This diff is too big to show here.
internal/skills/manager_test.gonew file+249
This diff is too big to show here.
internal/skills/skills.gonew file+437
This diff is too big to show here.
internal/skills/skills_test.gonew file+520
This diff is too big to show here.
internal/skills/tracker.gonew file+86
This diff is too big to show here.
internal/skills/tracker_test.gonew file+102
This diff is too big to show here.
internal/stringext/string.gonew file+40
This diff is too big to show here.
internal/stringext/string_test.gonew file+38
This diff is too big to show here.
internal/swagger/docs.gonew file+3717
This diff is too big to show here.
internal/swagger/swagger.jsonnew file+3692
This diff is too big to show here.
internal/swagger/swagger.yamlnew file+2457
This diff is too big to show here.
internal/tui/components/anim/anim.godeleted−446
This diff is too big to show here.
internal/tui/components/anim/example/main.godeleted−90
This diff is too big to show here.
internal/tui/components/chat/chat.godeleted−568
This diff is too big to show here.
internal/tui/components/chat/editor/editor.godeleted−557
This diff is too big to show here.
internal/tui/components/chat/editor/keys.godeleted−71
This diff is too big to show here.
internal/tui/components/chat/header/header.godeleted−145
This diff is too big to show here.
internal/tui/components/chat/messages/messages.godeleted−418
This diff is too big to show here.
internal/tui/components/chat/messages/renderer.godeleted−877
This diff is too big to show here.
internal/tui/components/chat/messages/tool.godeleted−809
This diff is too big to show here.
internal/tui/components/chat/sidebar/sidebar.godeleted−951
This diff is too big to show here.
internal/tui/components/chat/splash/keys.godeleted−53
This diff is too big to show here.
internal/tui/components/chat/splash/splash.godeleted−769
This diff is too big to show here.
internal/tui/components/completions/completions.godeleted−306
This diff is too big to show here.
internal/tui/components/completions/keys.godeleted−72
This diff is too big to show here.
internal/tui/components/core/core.godeleted−215
This diff is too big to show here.
internal/tui/components/core/layout/layout.godeleted−27
This diff is too big to show here.
internal/tui/components/core/status/status.godeleted−109
This diff is too big to show here.
internal/tui/components/core/status_test.godeleted−147
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/AllFieldsWithExtraContent.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/Default.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/EmptyDescription.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/LongDescription.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/NarrowWidth.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/NoIcon.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/VeryNarrowWidth.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/WithColors.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/WithCustomIcon.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatus/WithExtraContent.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatusTruncation/Width20.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatusTruncation/Width30.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatusTruncation/Width40.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatusTruncation/Width50.goldendeleted−1
This diff is too big to show here.
internal/tui/components/core/testdata/TestStatusTruncation/Width60.goldendeleted−1
This diff is too big to show here.
internal/tui/components/dialogs/commands/arguments.godeleted−225
This diff is too big to show here.
internal/tui/components/dialogs/commands/commands.godeleted−396
This diff is too big to show here.
internal/tui/components/dialogs/commands/keys.godeleted−126
This diff is too big to show here.
internal/tui/components/dialogs/commands/loader.godeleted−202
This diff is too big to show here.
internal/tui/components/dialogs/compact/compact.godeleted−265
This diff is too big to show here.
internal/tui/components/dialogs/compact/keys.godeleted−71
This diff is too big to show here.
internal/tui/components/dialogs/dialogs.godeleted−161
This diff is too big to show here.
internal/tui/components/dialogs/filepicker/filepicker.godeleted−238
This diff is too big to show here.
internal/tui/components/dialogs/filepicker/keys.godeleted−80
This diff is too big to show here.
internal/tui/components/dialogs/keys.godeleted−43
This diff is too big to show here.
internal/tui/components/dialogs/models/apikey.godeleted−202
This diff is too big to show here.
internal/tui/components/dialogs/models/keys.godeleted−85
This diff is too big to show here.
internal/tui/components/dialogs/models/list.godeleted−247
This diff is too big to show here.
internal/tui/components/dialogs/models/models.godeleted−388
This diff is too big to show here.
internal/tui/components/dialogs/permissions/keys.godeleted−113
This diff is too big to show here.
internal/tui/components/dialogs/permissions/permissions.godeleted−666
This diff is too big to show here.
internal/tui/components/dialogs/quit/keys.godeleted−75
This diff is too big to show here.
internal/tui/components/dialogs/quit/quit.godeleted−118
This diff is too big to show here.
internal/tui/components/dialogs/sessions/keys.godeleted−67
This diff is too big to show here.
internal/tui/components/dialogs/sessions/sessions.godeleted−179
This diff is too big to show here.
internal/tui/components/image/image.godeleted−86
This diff is too big to show here.
internal/tui/components/image/load.godeleted−146
This diff is too big to show here.
internal/tui/components/logo/logo.godeleted−347
This diff is too big to show here.
internal/tui/exp/diffview/chroma.godeleted−57
This diff is too big to show here.
internal/tui/exp/diffview/split.godeleted−73
This diff is too big to show here.
internal/tui/exp/diffview/style.godeleted−124
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/DarkMode.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/Default/LightMode.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.goldendeleted−4
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/Narrow/LightMode.goldendeleted−4
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/NoLineNumbers/DarkMode.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/NoLineNumbers/LightMode.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.goldendeleted−17
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.goldendeleted−17
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/DarkMode.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/Default/LightMode.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoLineNumbers/DarkMode.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoLineNumbers/LightMode.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.goldendeleted−2
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.goldendeleted−3
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.goldendeleted−4
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.goldendeleted−6
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.goldendeleted−9
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.goldendeleted−11
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.goldendeleted−12
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.goldendeleted−13
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.goldendeleted−14
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.goldendeleted−17
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.goldendeleted−18
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.goldendeleted−19
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.goldendeleted−20
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.goldendeleted−2
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.goldendeleted−3
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.goldendeleted−4
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.goldendeleted−6
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.goldendeleted−9
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.goldendeleted−11
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.goldendeleted−12
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.goldendeleted−13
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.goldendeleted−14
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.goldendeleted−17
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.goldendeleted−18
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.goldendeleted−19
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.goldendeleted−20
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewLineBreakIssue/Split.goldendeleted−9
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewLineBreakIssue/Unified.goldendeleted−12
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewTabs/Split.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewTabs/Unified.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.goldendeleted−15
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.goldendeleted−16
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.goldendeleted−7
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.goldendeleted−8
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf00.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf01.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf02.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf03.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf04.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf05.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf06.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf07.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf08.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf09.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf10.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf11.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf12.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf13.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf14.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf15.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf16.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf00.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf01.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf02.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf03.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf04.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf05.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf06.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf07.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf08.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf09.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf10.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf11.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf12.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf13.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf14.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf15.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf16.goldendeleted−5
This diff is too big to show here.
internal/tui/exp/diffview/util.godeleted−39
This diff is too big to show here.
internal/tui/exp/list/filterable.godeleted−308
This diff is too big to show here.
internal/tui/exp/list/filterable_group.godeleted−261
This diff is too big to show here.
internal/tui/exp/list/filterable_test.godeleted−68
This diff is too big to show here.
internal/tui/exp/list/grouped.godeleted−103
This diff is too big to show here.
internal/tui/exp/list/items.godeleted−390
This diff is too big to show here.
internal/tui/exp/list/keys.godeleted−76
This diff is too big to show here.
internal/tui/exp/list/list.godeleted−1024
This diff is too big to show here.
internal/tui/exp/list/list_test.godeleted−652
This diff is too big to show here.
internal/tui/exp/list/testdata/TestFilterableList/should_create_simple_filterable_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_go_to_selected_item_at_the_beginning.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_go_to_selected_item_at_the_beginning_backwards.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_have_correct_positions_in_list_that_does_not_fits_the_items.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_have_correct_positions_in_list_that_does_not_fits_the_items_and_has_multi_line_items.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_have_correct_positions_in_list_that_does_not_fits_the_items_and_has_multi_line_items_backwards.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_have_correct_positions_in_list_that_does_not_fits_the_items_backwards.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_have_correct_positions_in_list_that_fits_the_items.goldendeleted−20
This diff is too big to show here.
internal/tui/exp/list/testdata/TestList/should_have_correct_positions_in_list_that_fits_the_items_backwards.goldendeleted−20
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_move_viewport_down.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_move_viewport_down_and_up.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_move_viewport_up.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_move_viewport_up_and_down.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_not_change_offset_when_new_items_are_appended_and_we_are_at_the_bottom_in_backwards_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_not_change_offset_when_new_items_are_prepended_and_we_are_at_the_top_in_forward_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_if_an_item_is_appended_and_we_are_in_forward_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_if_an_item_is_prepended_and_we_are_in_backwards_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_new_items_are_added_but_we_moved_down_in_forward_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_new_items_are_added_but_we_moved_up_in_backwards_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_the_hight_of_an_item_above_is_decreases_in_forward_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_the_hight_of_an_item_above_is_increased_in_backwards_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_the_hight_of_an_item_above_is_increased_in_forward_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_the_hight_of_an_item_below_is_decreases_in_backwards_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_the_hight_of_an_item_below_is_increased_in_backwards_list.goldendeleted−10
This diff is too big to show here.
internal/tui/exp/list/testdata/TestListMovement/should_stay_at_the_position_it_is_when_the_hight_of_an_item_below_is_increased_in_forward_list.goldendeleted−10
This diff is too big to show here.
internal/tui/highlight/highlight.godeleted−54
This diff is too big to show here.
internal/tui/keys.godeleted−40
This diff is too big to show here.
internal/tui/page/chat/chat.godeleted−976
This diff is too big to show here.
internal/tui/page/chat/keys.godeleted−38
This diff is too big to show here.
internal/tui/page/page.godeleted−8
This diff is too big to show here.
internal/tui/styles/chroma.godeleted−79
This diff is too big to show here.
internal/tui/styles/crush.godeleted−57
This diff is too big to show here.
internal/tui/styles/icons.godeleted−18
This diff is too big to show here.
internal/tui/styles/markdown.godeleted−20
This diff is too big to show here.
internal/tui/styles/theme.godeleted−676
This diff is too big to show here.
internal/tui/tui.godeleted−537
This diff is too big to show here.
internal/tui/util/util.godeleted−69
This diff is too big to show here.
internal/ui/AGENTS.mdnew file+200
This diff is too big to show here.
internal/ui/anim/anim.gonew file+494
This diff is too big to show here.
internal/ui/attachments/attachments.gonew file+152
This diff is too big to show here.
internal/ui/chat/agent.gonew file+393
This diff is too big to show here.
internal/ui/chat/applyhighlight_callback_test.gonew file+207
This diff is too big to show here.
internal/ui/chat/assistant.go+904
This diff is too big to show here.
internal/ui/chat/assistant_render_test.go+78
This diff is too big to show here.
internal/ui/chat/assistant_section_cache_test.go+464
This diff is too big to show here.
internal/ui/chat/assistant_test.go+142
This diff is too big to show here.
internal/ui/chat/assistant_thinking_bench_test.go+69
This diff is too big to show here.
internal/ui/chat/assistant_thinking_bound_test.go+105
This diff is too big to show here.
internal/ui/chat/assistant_thinking_window_test.go+500
This diff is too big to show here.
internal/ui/chat/bash.go+251
This diff is too big to show here.
internal/ui/chat/diagnostics.go+68
This diff is too big to show here.
internal/ui/chat/docker_mcp.go+283
This diff is too big to show here.
internal/ui/chat/fetch.go+192
This diff is too big to show here.
internal/ui/chat/file.go+371
This diff is too big to show here.
internal/ui/chat/generic.go+73
This diff is too big to show here.
internal/ui/chat/incremental_glamour_test.go+981
This diff is too big to show here.
internal/ui/chat/lsp_restart.go+62
This diff is too big to show here.
internal/ui/chat/mcp.go+78
This diff is too big to show here.
internal/ui/chat/mcp_test.go+406
This diff is too big to show here.
internal/ui/chat/messages.go+440
This diff is too big to show here.
internal/ui/chat/prefix_cache_test.go+197
This diff is too big to show here.
internal/ui/chat/references.go+63
This diff is too big to show here.
internal/ui/chat/search.go+256
This diff is too big to show here.
internal/ui/chat/shell.go+358
This diff is too big to show here.
internal/ui/chat/shell_test.go+59
This diff is too big to show here.
internal/ui/chat/streaming_markdown.go+721
This diff is too big to show here.
internal/ui/chat/todos.go+192
This diff is too big to show here.
internal/ui/chat/tool_result_content.go+60
This diff is too big to show here.
internal/ui/chat/tool_result_content_test.go+116
This diff is too big to show here.
internal/ui/chat/tools.go+1751
This diff is too big to show here.
internal/ui/chat/unified_diff.go+170
This diff is too big to show here.
internal/ui/chat/user.go+181
This diff is too big to show here.
internal/ui/chat/version_bump_test.go+567
This diff is too big to show here.
internal/ui/common/ansi16.go+128
This diff is too big to show here.
internal/ui/common/ansi16_test.go+106
This diff is too big to show here.
internal/ui/common/button.go+69
This diff is too big to show here.
internal/ui/common/capabilities.go+131
This diff is too big to show here.
internal/ui/common/common.go+121
This diff is too big to show here.
internal/ui/common/diff.go+35
This diff is too big to show here.
internal/ui/common/elements.go+242
This diff is too big to show here.
internal/ui/common/elements_test.go+35
This diff is too big to show here.
internal/ui/common/highlight.go+106
This diff is too big to show here.
internal/ui/common/interface.go+20
This diff is too big to show here.
internal/ui/common/markdown.go+139
This diff is too big to show here.
internal/ui/common/scrollbar.go+48
This diff is too big to show here.
internal/ui/completions/completions.go+434
This diff is too big to show here.
internal/ui/completions/completions_test.go+108
This diff is too big to show here.
internal/ui/completions/item.go+225
This diff is too big to show here.
internal/ui/completions/keys.go+74
This diff is too big to show here.
internal/ui/completions/version_bump_test.go+85
This diff is too big to show here.
internal/ui/dialog/actions.go+187
This diff is too big to show here.
internal/ui/dialog/api_key_input.go+367
This diff is too big to show here.
internal/ui/dialog/arguments.go+406
This diff is too big to show here.
internal/ui/dialog/commands.go+453
This diff is too big to show here.
internal/ui/dialog/commands_item.go+136
This diff is too big to show here.
internal/ui/dialog/common.go+171
This diff is too big to show here.
internal/ui/dialog/dialog.go+296
This diff is too big to show here.
internal/ui/dialog/filepicker.go+321
This diff is too big to show here.
internal/ui/dialog/models.go+519
This diff is too big to show here.
internal/ui/dialog/models_item.go+157
This diff is too big to show here.
internal/ui/dialog/models_list.go+275
This diff is too big to show here.
internal/ui/dialog/notifications.go+310
This diff is too big to show here.
internal/ui/dialog/oauth.go+378
This diff is too big to show here.
internal/ui/dialog/oauth_copilot.go+78
This diff is too big to show here.
internal/ui/dialog/oauth_hyper.go+96
This diff is too big to show here.
internal/ui/dialog/overlay_test.go+189
This diff is too big to show here.
internal/ui/dialog/permissions.go+859
This diff is too big to show here.
internal/ui/dialog/permissions_test.go+99
This diff is too big to show here.
internal/ui/dialog/quit.go+133
This diff is too big to show here.
internal/ui/dialog/reasoning.go+318
This diff is too big to show here.
internal/ui/dialog/sessions.go+473
This diff is too big to show here.
internal/ui/dialog/sessions_item.go+294
This diff is too big to show here.
internal/ui/dialog/version_bump_test.go+219
This diff is too big to show here.
internal/ui/difftastic/difftastic.go+60
This diff is too big to show here.
internal/ui/diffview/Taskfile.yaml
This diff is too big to show here.
internal/ui/diffview/diffview.go+59−39
This diff is too big to show here.
internal/ui/diffview/diffview_test.go+1−25
This diff is too big to show here.
internal/ui/diffview/split.go+73
This diff is too big to show here.
internal/ui/diffview/style.go+143
This diff is too big to show here.
internal/ui/diffview/testdata/TestDefault.after
This diff is too big to show here.
internal/ui/diffview/testdata/TestDefault.before
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/CustomContextLines/DarkMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/CustomContextLines/LightMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/Default/DarkMode.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/Default/LightMode.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/LargeWidth/DarkMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/LargeWidth/LightMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/MultipleHunks/DarkMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/MultipleHunks/LightMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/Narrow/DarkMode.golden+4
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/Narrow/LightMode.golden+4
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/NoLineNumbers/DarkMode.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/NoLineNumbers/LightMode.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/DarkMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/NoSyntaxHighlight/LightMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/SmallWidth/DarkMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Split/SmallWidth/LightMode.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/CustomContextLines/DarkMode.golden+17
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/CustomContextLines/LightMode.golden+17
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/Default/DarkMode.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/Default/LightMode.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/LargeWidth/DarkMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/LargeWidth/LightMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/MultipleHunks/DarkMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/MultipleHunks/LightMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/Narrow/DarkMode.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/Narrow/LightMode.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/NoLineNumbers/DarkMode.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/NoLineNumbers/LightMode.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/DarkMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/NoSyntaxHighlight/LightMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/SmallWidth/DarkMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffView/Unified/SmallWidth/LightMode.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf001.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf002.golden+2
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf003.golden+3
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf004.golden+4
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf005.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf006.golden+6
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf007.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf008.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf009.golden+9
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf010.golden+10
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf011.golden+11
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf012.golden+12
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf013.golden+13
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf014.golden+14
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf015.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf016.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf017.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf018.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf019.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Split/HeightOf020.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf001.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf002.golden+2
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf003.golden+3
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf004.golden+4
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf005.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf006.golden+6
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf007.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf008.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf009.golden+9
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf010.golden+10
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf011.golden+11
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf012.golden+12
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf013.golden+13
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf014.golden+14
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf015.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf016.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf017.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf018.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf019.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewHeight/Unified/HeightOf020.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewLineBreakIssue/Split.golden+9
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewLineBreakIssue/Unified.golden+12
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewTabs/Split.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewTabs/Unified.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf001.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf002.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf003.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf004.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf005.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf006.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf007.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf008.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf009.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf010.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf011.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf012.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf013.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf014.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf015.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf016.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf017.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf018.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf019.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf020.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf021.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf022.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf023.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf024.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf025.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf026.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf027.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf028.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf029.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf030.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf031.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf032.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf033.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf034.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf035.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf036.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf037.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf038.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf039.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf040.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf041.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf042.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf043.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf044.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf045.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf046.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf047.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf048.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf049.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf050.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf051.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf052.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf053.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf054.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf055.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf056.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf057.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf058.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf059.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf060.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf061.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf062.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf063.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf064.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf065.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf066.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf067.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf068.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf069.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf070.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf071.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf072.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf073.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf074.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf075.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf076.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf077.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf078.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf079.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf080.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf081.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf082.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf083.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf084.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf085.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf086.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf087.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf088.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf089.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf090.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf091.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf092.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf093.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf094.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf095.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf096.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf097.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf098.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf099.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf100.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf101.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf102.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf103.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf104.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf105.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf106.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf107.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf108.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf109.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Split/WidthOf110.golden+15
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf001.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf002.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf003.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf004.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf005.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf006.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf007.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf008.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf009.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf010.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf011.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf012.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf013.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf014.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf015.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf016.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf017.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf018.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf019.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf020.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf021.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf022.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf023.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf024.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf025.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf026.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf027.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf028.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf029.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf030.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf031.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf032.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf033.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf034.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf035.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf036.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf037.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf038.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf039.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf040.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf041.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf042.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf043.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf044.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf045.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf046.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf047.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf048.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf049.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf050.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf051.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf052.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf053.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf054.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf055.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf056.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf057.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf058.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf059.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewWidth/Unified/WidthOf060.golden+16
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf00.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf01.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf02.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf03.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf04.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf05.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf06.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf07.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf08.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf09.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf10.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf11.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf12.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf13.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf14.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf15.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf16.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf17.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf18.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf19.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Split/XOffsetOf20.golden+7
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf00.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf01.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf02.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf03.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf04.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf05.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf06.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf07.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf08.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf09.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf10.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf11.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf12.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf13.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf14.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf15.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf16.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf17.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf18.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf19.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewXOffset/Unified/XOffsetOf20.golden+8
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf00.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf01.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf02.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf03.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf04.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf05.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf06.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf07.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf08.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf09.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf10.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf11.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf12.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf13.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf14.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf15.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Split/YOffsetOf16.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf00.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf01.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf02.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf03.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf04.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf05.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf06.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf07.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf08.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf09.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf10.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf11.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf12.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf13.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf14.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf15.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffset/Unified/YOffsetOf16.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf00.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf01.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf02.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf03.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf04.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf05.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf06.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf07.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf08.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf09.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf10.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf11.golden+4
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf12.golden+3
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf13.golden+2
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf14.golden+1
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf15.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Split/YOffsetOf16.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf00.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf01.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf02.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf03.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf04.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf05.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf06.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf07.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf08.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf09.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf10.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf11.golden+5
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf12.golden+4
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf13.golden+3
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf14.golden+2
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf15.golden+1
This diff is too big to show here.
internal/ui/diffview/testdata/TestDiffViewYOffsetInfinite/Unified/YOffsetOf16.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestLineBreakIssue.after
This diff is too big to show here.
internal/ui/diffview/testdata/TestLineBreakIssue.before
This diff is too big to show here.
internal/ui/diffview/testdata/TestMultipleHunks.after
This diff is too big to show here.
internal/ui/diffview/testdata/TestMultipleHunks.before
This diff is too big to show here.
internal/ui/diffview/testdata/TestNarrow.after
This diff is too big to show here.
internal/ui/diffview/testdata/TestNarrow.before
This diff is too big to show here.
internal/ui/diffview/testdata/TestTabs.after
This diff is too big to show here.
internal/ui/diffview/testdata/TestTabs.before
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLines/Content.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLines/JSON.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusOne/Content.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusOne/JSON.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusTwo/Content.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/ToUnifiedDiff/DefaultContextLinesPlusTwo/JSON.golden
This diff is too big to show here.
internal/ui/diffview/testdata/TestUdiff/Unified.golden
This diff is too big to show here.
internal/ui/diffview/udiff_test.go+1−1
This diff is too big to show here.
internal/ui/diffview/util.go+46
This diff is too big to show here.
internal/ui/diffview/util_test.go
This diff is too big to show here.
internal/ui/image/image.go+288
This diff is too big to show here.
internal/ui/image/image_test.go+46
This diff is too big to show here.
internal/ui/list/filterable.go+157
This diff is too big to show here.
internal/ui/list/focus.go+13
This diff is too big to show here.
internal/ui/list/highlight.go+212
This diff is too big to show here.
internal/ui/list/item.go+126
This diff is too big to show here.
internal/ui/list/list.go+928
This diff is too big to show here.
internal/ui/list/list_test.go+770
This diff is too big to show here.
internal/ui/logo/example/main.go+49
This diff is too big to show here.
internal/ui/logo/letterforms.go+419
This diff is too big to show here.
internal/ui/logo/logo.go+168
This diff is too big to show here.
internal/ui/logo/rand.go+24
This diff is too big to show here.
internal/ui/model/chat.go+1166
This diff is too big to show here.
internal/ui/model/chat_draw_cache_test.go+334
This diff is too big to show here.
internal/ui/model/chat_expand_test.go+55
This diff is too big to show here.
internal/ui/model/filter.go+108
This diff is too big to show here.
internal/ui/model/filter_test.go+162
This diff is too big to show here.
internal/ui/model/header.go+264
This diff is too big to show here.
internal/ui/model/history.go+200
This diff is too big to show here.
internal/ui/model/keys.go+285
This diff is too big to show here.
internal/ui/model/landing.go+126
This diff is too big to show here.
internal/ui/model/layout_test.go+228
This diff is too big to show here.
internal/ui/model/lsp.go+147
This diff is too big to show here.
internal/ui/model/mcp.go+114
This diff is too big to show here.
internal/ui/model/onboarding.go+116
This diff is too big to show here.
internal/ui/model/permission_test.go+96
This diff is too big to show here.
internal/ui/model/pills.go+363
This diff is too big to show here.
internal/ui/model/session.go+272
This diff is too big to show here.
internal/ui/model/session_test.go+142
This diff is too big to show here.
internal/ui/model/sidebar.go+369
This diff is too big to show here.
internal/ui/model/skills.go+155
This diff is too big to show here.
internal/ui/model/skills_test.go+81
This diff is too big to show here.
internal/ui/model/status.go+123
This diff is too big to show here.
internal/ui/model/ui.go+4564
This diff is too big to show here.
internal/ui/model/ui_test.go+95
This diff is too big to show here.
internal/ui/notification/bell.go+27
This diff is too big to show here.
internal/ui/notification/crush-icon-solo.png
This diff is too big to show here.
internal/ui/notification/crush-icon.png
This diff is too big to show here.
internal/ui/notification/icon_darwin.go+11
This diff is too big to show here.
internal/ui/notification/icon_other.go+10
This diff is too big to show here.
internal/ui/notification/native.go+52
This diff is too big to show here.
internal/ui/notification/noop.go+12
This diff is too big to show here.
internal/ui/notification/notification.go+35
This diff is too big to show here.
internal/ui/notification/notification_test.go+213
This diff is too big to show here.
internal/ui/notification/osc.go+135
This diff is too big to show here.
internal/ui/styles/grad.go+119
This diff is too big to show here.
internal/ui/styles/quickstyle.go+989
This diff is too big to show here.
internal/ui/styles/styles.go+649
This diff is too big to show here.
internal/ui/styles/themes.go+235
This diff is too big to show here.
internal/ui/util/util.go+96
This diff is too big to show here.
internal/ui/xchroma/chroma.go+70
This diff is too big to show here.
internal/update/update.go+118
This diff is too big to show here.
internal/update/update_test.go+48
This diff is too big to show here.
internal/version/version.go+39−12
This diff is too big to show here.
internal/workspace/app_workspace.go+464
This diff is too big to show here.
internal/workspace/client_workspace.go+964
This diff is too big to show here.
internal/workspace/client_workspace_test.go+213
This diff is too big to show here.
internal/workspace/export_test.go+14
This diff is too big to show here.
internal/workspace/multiclient_integration_test.go+176
This diff is too big to show here.
internal/workspace/workspace.go+171
This diff is too big to show here.
This diff is too big to show here.
This diff is too big to show here.
scripts/check_log_capitalization.sh+5
This diff is too big to show here.
scripts/run-labeler.sh+12
This diff is too big to show here.
vendor/charm.land/bubbles/v2/LICENSE+21
This diff is too big to show here.
vendor/charm.land/bubbles/v2/cursor/cursor.go+241
This diff is too big to show here.
vendor/charm.land/bubbles/v2/filepicker/filepicker.go+529
This diff is too big to show here.
vendor/charm.land/bubbles/v2/filepicker/hidden_unix.go+11
This diff is too big to show here.
vendor/charm.land/bubbles/v2/filepicker/hidden_windows.go+21
This diff is too big to show here.
vendor/charm.land/bubbles/v2/help/help.go+253
This diff is too big to show here.
vendor/charm.land/bubbles/v2/internal/memoization/memoization.go+125
This diff is too big to show here.
vendor/charm.land/bubbles/v2/internal/runeutil/runeutil.go+102
This diff is too big to show here.
vendor/charm.land/bubbles/v2/key/key.go+140
This diff is too big to show here.
vendor/charm.land/bubbles/v2/spinner/spinner.go+211
This diff is too big to show here.
vendor/charm.land/bubbles/v2/textarea/textarea.go+1897
This diff is too big to show here.
vendor/charm.land/bubbles/v2/textinput/styles.go+96
This diff is too big to show here.
vendor/charm.land/bubbles/v2/textinput/textinput.go+968
This diff is too big to show here.
vendor/charm.land/bubbles/v2/viewport/highlight.go+141
This diff is too big to show here.
vendor/charm.land/bubbles/v2/viewport/keymap.go+58
This diff is too big to show here.
vendor/charm.land/bubbles/v2/viewport/viewport.go+765
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/.gitattributes+1
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/.gitignore+23
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/.golangci.yml+47
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/.goreleaser.yml+5
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/LICENSE+21
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/README.md+402
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/Taskfile.yaml+38
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/UPGRADE_GUIDE_V2.md+573
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/clipboard.go+70
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/color.go+91
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/commands.go+175
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/cursed_renderer.go+860
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/cursor.go+28
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/environ.go+34
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/exec.go+129
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/focus.go+9
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/input.go+54
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/key.go+371
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/keyboard.go+59
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/logging.go+53
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/mod.go+27
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/mouse.go+144
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/nil_renderer.go+53
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/options.go+168
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/paste.go+20
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/profile.go+15
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/raw.go+37
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/renderer.go+104
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/screen.go+68
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/signals_unix.go+33
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/signals_windows.go+10
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/tea.go+1439
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/termcap.go+48
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/termios_bsd.go+13
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/termios_other.go+8
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/termios_unix.go+14
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/termios_windows.go+11
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/tty.go+136
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/tty_unix.go+47
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/tty_windows.go+64
This diff is too big to show here.
vendor/charm.land/bubbletea/v2/xterm.go+22
This diff is too big to show here.
vendor/charm.land/catwalk/LICENSE+21
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/aihubmix.json+3746
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/alibaba-singapore.json+141
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/alibaba-united-states.json+45
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/anthropic.json+183
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/avian.json+125
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/azure.json+225
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/baseten.json+187
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/bedrock-europe.json+115
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/bedrock-united-states.json+143
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/cerebras.json+42
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/chutes.json+227
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/copilot.json+310
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/cortecs.json+1697
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/deepseek.json+45
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/fireworks.json+171
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/gemini.json+91
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/groq.json+36
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/huggingface.json+267
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/ionet.json+335
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/kimi.json+23
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/minimax-china.json+91
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/minimax.json+91
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/moonshot.json+131
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/nebius.json+419
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/neuralwatt.json+155
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/openai.json+352
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/opencode-go.json+351
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/opencode-zen.json+908
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/openrouter.json+3831
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/qiniucloud.json+179
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/scaleway.json+141
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/synthetic.json+197
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/venice.json+1173
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/vercel.json+3072
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/vertexai.json+170
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/xai.json+59
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/zai.json+136
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/zhipu-coding.json+136
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/configs/zhipu.json+120
This diff is too big to show here.
vendor/charm.land/catwalk/internal/providers/providers.go+349
This diff is too big to show here.
vendor/charm.land/catwalk/pkg/catwalk/client.go+79
This diff is too big to show here.
vendor/charm.land/catwalk/pkg/catwalk/pkg.go+2
This diff is too big to show here.
vendor/charm.land/catwalk/pkg/catwalk/provider.go+157
This diff is too big to show here.
vendor/charm.land/catwalk/pkg/embedded/embedded.go+13
This diff is too big to show here.
vendor/charm.land/fang/v2/.gitignore+3
This diff is too big to show here.
vendor/charm.land/fang/v2/.golangci.yml+47
This diff is too big to show here.
vendor/charm.land/fang/v2/.goreleaser.yml+5
This diff is too big to show here.
vendor/charm.land/fang/v2/LICENSE.md+21
This diff is too big to show here.
vendor/charm.land/fang/v2/README.md+92
This diff is too big to show here.
vendor/charm.land/fang/v2/Taskfile.yml+7
This diff is too big to show here.
vendor/charm.land/fang/v2/UPGRADE_GUIDE_V2.md+127
This diff is too big to show here.
vendor/charm.land/fang/v2/fang.go+208
This diff is too big to show here.
vendor/charm.land/fang/v2/fang_other.go+10
This diff is too big to show here.
vendor/charm.land/fang/v2/fang_windows.go+30
This diff is too big to show here.
vendor/charm.land/fang/v2/help.go+482
This diff is too big to show here.
vendor/charm.land/fang/v2/theme.go+222
This diff is too big to show here.
vendor/charm.land/fantasy/.editorconfig+18
This diff is too big to show here.
vendor/charm.land/fantasy/.gitattributes+1
This diff is too big to show here.
vendor/charm.land/fantasy/.gitignore+42
This diff is too big to show here.
vendor/charm.land/fantasy/.golangci.yml+44
This diff is too big to show here.
vendor/charm.land/fantasy/.goreleaser.yml+6
This diff is too big to show here.
vendor/charm.land/fantasy/AGENTS.md+29
This diff is too big to show here.
vendor/charm.land/fantasy/LICENSE+177
This diff is too big to show here.
vendor/charm.land/fantasy/NOTICE+13
This diff is too big to show here.
vendor/charm.land/fantasy/README.md+95
This diff is too big to show here.
vendor/charm.land/fantasy/Taskfile.yaml+45
This diff is too big to show here.
vendor/charm.land/fantasy/agent.go+1702
This diff is too big to show here.
vendor/charm.land/fantasy/content.go+625
This diff is too big to show here.
vendor/charm.land/fantasy/content_json.go+1046
This diff is too big to show here.
vendor/charm.land/fantasy/crush.json+6
This diff is too big to show here.
vendor/charm.land/fantasy/cspell.json+1
This diff is too big to show here.
vendor/charm.land/fantasy/doc.go+2
This diff is too big to show here.
vendor/charm.land/fantasy/errors.go+155
This diff is too big to show here.
vendor/charm.land/fantasy/jsonrepair/jsonrepair.go+1648
This diff is too big to show here.
vendor/charm.land/fantasy/model.go+261
This diff is too big to show here.
vendor/charm.land/fantasy/model_json.go+156
This diff is too big to show here.
vendor/charm.land/fantasy/object.go+236
This diff is too big to show here.
vendor/charm.land/fantasy/object/object.go+620
This diff is too big to show here.
vendor/charm.land/fantasy/provider.go+11
This diff is too big to show here.
vendor/charm.land/fantasy/provider_registry.go+106
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/anthropic.go+1707
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/bedrock.go+15
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/call_useragent.go+14
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/computer_use.go+427
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/error.go+67
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/google.go+11
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/provider_options.go+283
This diff is too big to show here.
vendor/charm.land/fantasy/providers/anthropic/sanitize.go+33
This diff is too big to show here.
vendor/charm.land/fantasy/providers/azure/README.md+6
This diff is too big to show here.
vendor/charm.land/fantasy/providers/azure/azure.go+125
This diff is too big to show here.
vendor/charm.land/fantasy/providers/bedrock/README.md+10
This diff is too big to show here.
vendor/charm.land/fantasy/providers/bedrock/bedrock.go+87
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/README.md+63
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/auth.go+15
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/call_useragent.go+53
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/error.go+51
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/google.go+1488
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/provider_options.go+146
This diff is too big to show here.
vendor/charm.land/fantasy/providers/google/slice.go+11
This diff is too big to show here.
vendor/charm.land/fantasy/providers/internal/httpheaders/httpheaders.go+60
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/call_useragent.go+31
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/error.go+92
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/language_model.go+990
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/language_model_hooks.go+668
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/openai.go+220
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/provider_options.go+217
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/responses_language_model.go+1678
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openai/responses_options.go+395
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openaicompat/language_model_hooks.go+516
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openaicompat/openaicompat.go+140
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openaicompat/provider_options.go+161
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openrouter/language_model_hooks.go+1063
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openrouter/openrouter.go+121
This diff is too big to show here.
vendor/charm.land/fantasy/providers/openrouter/provider_options.go+218
This diff is too big to show here.
vendor/charm.land/fantasy/providers/vercel/language_model_hooks.go+1074
This diff is too big to show here.
vendor/charm.land/fantasy/providers/vercel/provider_options.go+195
This diff is too big to show here.
vendor/charm.land/fantasy/providers/vercel/vercel.go+122
This diff is too big to show here.
vendor/charm.land/fantasy/retry.go+155
This diff is too big to show here.
vendor/charm.land/fantasy/schema/schema.go+442
This diff is too big to show here.
vendor/charm.land/fantasy/tool.go+176
This diff is too big to show here.
vendor/charm.land/fantasy/util.go+22
This diff is too big to show here.
vendor/charm.land/fantasy/version.go+12
This diff is too big to show here.
vendor/charm.land/fantasy/version.txt+1
This diff is too big to show here.
vendor/charm.land/glamour/v2/.editorconfig+18
This diff is too big to show here.
vendor/charm.land/glamour/v2/.gitattributes+2
This diff is too big to show here.
vendor/charm.land/glamour/v2/.gitignore+2
This diff is too big to show here.
vendor/charm.land/glamour/v2/.golangci.yml+44
This diff is too big to show here.
vendor/charm.land/glamour/v2/.goreleaser.yml+6
This diff is too big to show here.
vendor/charm.land/glamour/v2/CONTRIBUTING.md+23
This diff is too big to show here.
vendor/charm.land/glamour/v2/LICENSE+21
This diff is too big to show here.
vendor/charm.land/glamour/v2/README.md+129
This diff is too big to show here.
vendor/charm.land/glamour/v2/Taskfile.yml+25
This diff is too big to show here.
vendor/charm.land/glamour/v2/UPGRADE_GUIDE_V2.md+279
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/ansi.go+3
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/baseelement.go+157
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/blockelement.go+66
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/blockstack.go+95
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/codeblock.go+151
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/codespan.go+15
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/context.go+38
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/elements.go+481
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/emphasis.go+47
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/heading.go+80
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/image.go+57
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/link.go+112
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/listitem.go+29
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/margin.go+231
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/paragraph.go+63
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/renderer.go+166
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/style.go+252
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/table.go+206
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/table_links.go+234
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/task.go+27
This diff is too big to show here.
vendor/charm.land/glamour/v2/ansi/templatehelper.go+86
This diff is too big to show here.
vendor/charm.land/glamour/v2/examples.sh+19
This diff is too big to show here.
vendor/charm.land/glamour/v2/gallery.sh+23
This diff is too big to show here.
vendor/charm.land/glamour/v2/glamour.go+294
This diff is too big to show here.
vendor/charm.land/glamour/v2/internal/autolink/autolink.go+55
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/README.md+565
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/ascii.json+87
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/dark.json+191
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/dracula.go+216
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/dracula.json+188
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/light.json+190
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/notty.json+87
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/pink.json+90
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/styles.go+691
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/tokyo-night.go+209
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/tokyo-night.json+182
This diff is too big to show here.
vendor/charm.land/glamour/v2/styles/tokyo_night.json+182
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/.editorconfig+18
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/.gitattributes+1
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/.gitignore+3
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/.golangci.yml+50
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/.goreleaser.yml+5
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/LICENSE+21
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/README.md+996
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/Taskfile.yaml+24
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/UPGRADE_GUIDE_V2.md+504
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/align.go+82
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/ansi_unix.go+8
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/ansi_windows.go+30
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/blending.go+196
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/borders.go+587
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/canvas.go+88
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/color.go+359
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/get.go+657
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/join.go+175
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/layer.go+327
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/lipgloss.go+3
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/position.go+134
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/query.go+92
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/ranges.go+48
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/runes.go+43
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/set.go+932
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/size.go+40
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/style.go+637
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/table/resizing.go+489
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/table/rows.go+130
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/table/table.go+568
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/table/util.go+44
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/terminal.go+124
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/tree/children.go+100
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/tree/enumerator.go+74
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/tree/renderer.go+165
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/tree/tree.go+407
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/unset.go+359
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/whitespace.go+76
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/wrap.go+113
This diff is too big to show here.
vendor/charm.land/lipgloss/v2/writer.go+160
This diff is too big to show here.
vendor/charm.land/log/v2/.gitignore+17
This diff is too big to show here.
vendor/charm.land/log/v2/.golangci.yml+50
This diff is too big to show here.
vendor/charm.land/log/v2/.goreleaser.yml+6
This diff is too big to show here.
vendor/charm.land/log/v2/LICENSE+21
This diff is too big to show here.
vendor/charm.land/log/v2/README.md+367
This diff is too big to show here.
vendor/charm.land/log/v2/UPGRADE_GUIDE_V2.md+320
This diff is too big to show here.
vendor/charm.land/log/v2/context.go+23
This diff is too big to show here.
vendor/charm.land/log/v2/doc.go+3
This diff is too big to show here.
vendor/charm.land/log/v2/formatter.go+27
This diff is too big to show here.
vendor/charm.land/log/v2/json.go+157
This diff is too big to show here.
vendor/charm.land/log/v2/level.go+65
This diff is too big to show here.
vendor/charm.land/log/v2/logfmt.go+32
This diff is too big to show here.
vendor/charm.land/log/v2/logger.go+413
This diff is too big to show here.
vendor/charm.land/log/v2/logger_121.go+72
This diff is too big to show here.
vendor/charm.land/log/v2/logger_no121.go+69
This diff is too big to show here.
vendor/charm.land/log/v2/options.go+61
This diff is too big to show here.
vendor/charm.land/log/v2/pkg.go+248
This diff is too big to show here.
vendor/charm.land/log/v2/stdlog.go+67
This diff is too big to show here.
vendor/charm.land/log/v2/styles.go+83
This diff is too big to show here.
vendor/charm.land/log/v2/text.go+272
This diff is too big to show here.
vendor/charm.land/x/vcr/LICENSE+21
This diff is too big to show here.
vendor/charm.land/x/vcr/doc.go+3
This diff is too big to show here.
vendor/charm.land/x/vcr/hooks.go+33
This diff is too big to show here.
vendor/charm.land/x/vcr/marshaler.go+19
This diff is too big to show here.
vendor/charm.land/x/vcr/matcher.go+70
This diff is too big to show here.
vendor/charm.land/x/vcr/recorder.go+70
This diff is too big to show here.
vendor/cloud.google.com/go/LICENSE+202
This diff is too big to show here.
vendor/cloud.google.com/go/auth/CHANGES.md+483
This diff is too big to show here.
vendor/cloud.google.com/go/auth/LICENSE+202
This diff is too big to show here.
vendor/cloud.google.com/go/auth/README.md+40
This diff is too big to show here.
vendor/cloud.google.com/go/auth/auth.go+618
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/compute.go+102
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/detect.go+471
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/doc.go+45
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/filetypes.go+329
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/aws_provider.go+531
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/executable_provider.go+284
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/externalaccount.go+431
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/file_provider.go+78
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/info.go+74
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/programmatic_provider.go+30
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/url_provider.go+93
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccount/x509_provider.go+220
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/externalaccountuser/externalaccountuser.go+115
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/gdch/gdch.go+198
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/impersonate/idtoken.go+105
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/impersonate/impersonate.go+168
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/internal/stsexchange/sts_exchange.go+167
This diff is too big to show here.
vendor/cloud.google.com/go/auth/credentials/selfsignedjwt.go+89
This diff is too big to show here.
vendor/cloud.google.com/go/auth/grpctransport/dial_socketopt.go+62
This diff is too big to show here.
vendor/cloud.google.com/go/auth/grpctransport/directpath.go+177
This diff is too big to show here.
vendor/cloud.google.com/go/auth/grpctransport/grpctransport.go+675
This diff is too big to show here.
vendor/cloud.google.com/go/auth/grpctransport/pool.go+119
This diff is too big to show here.
vendor/cloud.google.com/go/auth/httptransport/httptransport.go+254
This diff is too big to show here.
vendor/cloud.google.com/go/auth/httptransport/transport.go+548
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/compute/compute.go+65
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/compute/manufacturer.go+22
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/compute/manufacturer_linux.go+23
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/compute/manufacturer_windows.go+46
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/credsfile/credsfile.go+63
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/credsfile/filetype.go+159
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/credsfile/parse.go+99
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/internal.go+285
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/jwt/jwt.go+208
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/retry/retry.go+117
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/cba.go+361
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/cert/default_cert.go+65
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/cert/enterprise_cert.go+54
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/cert/secureconnect_cert.go+124
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/cert/workload_cert.go+138
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/headers/headers.go+61
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/s2a.go+138
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/transport/transport.go+137
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/trustboundary/external_accounts_config_providers.go+100
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/trustboundary/trust_boundary.go+392
This diff is too big to show here.
vendor/cloud.google.com/go/auth/internal/version.go+20
This diff is too big to show here.
vendor/cloud.google.com/go/auth/oauth2adapt/CHANGES.md+82
This diff is too big to show here.
vendor/cloud.google.com/go/auth/oauth2adapt/LICENSE+202
This diff is too big to show here.
vendor/cloud.google.com/go/auth/oauth2adapt/oauth2adapt.go+200
This diff is too big to show here.
vendor/cloud.google.com/go/auth/threelegged.go+382
This diff is too big to show here.
vendor/cloud.google.com/go/civil/civil.go+500
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/CHANGES.md+115
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/LICENSE+202
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/README.md+27
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/log.go+149
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/metadata.go+937
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/retry.go+117
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/retry_linux.go+31
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/syscheck.go+28
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/syscheck_linux.go+30
This diff is too big to show here.
vendor/cloud.google.com/go/compute/metadata/syscheck_windows.go+39
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/.gitignore+1
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/ARCHITECTURE.md+244
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/LICENSE+61
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/README.md+86
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/constants.go+65
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/internal/winrt/data/xml/dom/xmldocument.go+73
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/internal/winrt/ui/notifications/toastnotification.go+88
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/internal/winrt/ui/notifications/toastnotificationmanager.go+53
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/internal/winrt/ui/notifications/toastnotificationmanagerforuser.go+68
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/internal/winrt/ui/notifications/toastnotifier.go+64
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/tmpl/powershell.go.tmpl+14
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/tmpl/tmpl.go+28
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/tmpl/xml.go.tmpl+34
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/toast.go+225
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/wintoast/bind.go+86
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/wintoast/bind_noop.go+19
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/wintoast/bind_windows.go+174
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/wintoast/impl.go+179
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/wintoast/procs.go+37
This diff is too big to show here.
vendor/git.sr.ht/~jackmordaunt/go-toast/wintoast/registry.go+110
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md+849
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/LICENSE.txt+21
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/README.md+39
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/ci.yml+29
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud/cloud.go+44
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud/doc.go+53
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go+173
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/doc.go+264
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/errors.go+17
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/etag.go+57
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go+175
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/pipeline.go+77
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go+260
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go+201
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log/log.go+50
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go+159
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go+135
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/fake/fake.go+133
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go+123
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go+148
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/poller.go+24
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go+212
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go+44
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go+149
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/log/doc.go+10
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/log/log.go+55
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/doc.go+10
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go+198
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/doc.go+10
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/errors.go+27
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go+138
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go+94
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_api_version.go+75
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go+236
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go+72
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_http_header.go+40
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_http_trace.go+154
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_include_response.go+35
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_key_credential.go+64
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go+264
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go+34
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go+276
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_sas_credential.go+55
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_telemetry.go+83
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go+396
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/request.go+281
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go+109
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_dialer_other.go+15
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_dialer_wasm.go+15
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/transport_default_http_client.go+48
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/doc.go+9
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go+89
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing/constants.go+41
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing/tracing.go+191
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/LICENSE.txt+21
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/diag/diag.go+51
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/diag/doc.go+7
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo/doc.go+7
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo/errorinfo.go+46
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/exported/exported.go+129
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/log/doc.go+7
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/log/log.go+104
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/poller/util.go+155
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/temporal/resource.go+123
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/uuid/doc.go+7
This diff is too big to show here.
vendor/github.com/Azure/azure-sdk-for-go/sdk/internal/uuid/uuid.go+76
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/.gitignore+14
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/CONTRIBUTING.md
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/LICENSE+21
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/README.md+242
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/SECURITY.md+6
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/commonmark.go+393
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/escape/escape.go+65
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/from.go+464
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/logo_five_years.png
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/markdown.go+212
This diff is too big to show here.
vendor/github.com/JohannesKaufmann/html-to-markdown/utils.go+533
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/.gitignore+16
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/.travis.yml+9
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/LICENSE+21
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/Makefile+32
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/README.md+232
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/depth.go+129
This diff is too big to show here.
vendor/github.com/KyleBanks/depth/pkg.go+184
This diff is too big to show here.
vendor/github.com/MakeNowJust/heredoc/LICENSE+21
This diff is too big to show here.
vendor/github.com/MakeNowJust/heredoc/README.md+52
This diff is too big to show here.
vendor/github.com/MakeNowJust/heredoc/heredoc.go+105
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/.gitattributes+1
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/.gitignore+10
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/.golangci.yml+147
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/CODEOWNERS+1
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/LICENSE+22
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/README.md+89
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/SECURITY.md+41
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/backup.go+287
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/doc.go+22
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/ea.go+137
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/file.go+320
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/fileinfo.go+106
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/hvsock.go+582
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/fs/doc.go+2
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go+262
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/fs/security.go+12
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go+61
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go+20
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go+177
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go+69
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go+132
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/pipe.go+586
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go+232
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go+16
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go+13
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go+27
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/privilege.go+196
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/reparse.go+131
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/sd.go+133
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/syscall.go+5
This diff is too big to show here.
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go+378
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/.gitattributes+1
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/.gitignore+16
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/LICENSE+12
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/README.md+218
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/array.go+124
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/doc.go+123
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/expand.go+70
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/filter.go+163
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/iteration.go+61
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/manipulation.go+679
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/property.go+275
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/query.go+49
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/traversal.go+704
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/type.go+203
This diff is too big to show here.
vendor/github.com/PuerkitoBio/goquery/utilities.go+177
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/.editorconfig+17
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/.gitignore+28
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/.golangci.yml+122
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/.goreleaser.yml+34
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/AGENTS.md+11
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/BUILD.bit+93
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/COPYING+118
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/Dockerfile+64
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/Justfile+59
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/README.md+309
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/biome.json+6
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/chroma.jpg
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/coalesce.go+35
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/colour.go+192
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/delegate.go+161
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/doc.go+7
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/emitters.go+233
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatter.go+43
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/api.go+57
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go+692
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/json.go+39
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/svg/font_liberation_mono.go+51
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/svg/svg.go+222
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/tokens.go+18
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/tty_indexed.go+284
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/formatters/tty_truecolour.go+76
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/iterator.go+93
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexer.go+179
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/README.md+46
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/caddyfile.go+275
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/cl.go+243
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/dns.go+17
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/emacs.go+533
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abap.xml+154
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/abnf.xml+66
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript.xml+68
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/actionscript_3.xml+163
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ada.xml+321
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/agda.xml+66
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/al.xml+75
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/alloy.xml+58
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ampl.xml+98
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/angular2.xml+109
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/antlr.xml+317
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apacheconf.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/apl.xml+59
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/applescript.xml+151
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arangodb_aql.xml+174
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arduino.xml+322
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/armasm.xml+126
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arturo.xml+119
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/atl.xml+165
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autohotkey.xml+78
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/autoit.xml+70
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/awk.xml+95
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ballerina.xml+97
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash.xml+222
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bash_session.xml+25
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/batchfile.xml+660
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/beef.xml+120
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bibtex.xml+152
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bicep.xml+84
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/blitzbasic.xml+141
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bnf.xml+28
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/bqn.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/brainfuck.xml+51
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c#.xml+121
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c++.xml+331
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c.xml+260
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/c3.xml+374
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cap_n_proto.xml+122
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cassandra_cql.xml+137
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ceylon.xml+151
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfengine3.xml+197
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cfstatement.xml+92
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chaiscript.xml+134
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/chapel.xml+143
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cheetah.xml+55
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/clojure.xml+71
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cmake.xml+90
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cobol.xml+90
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coffeescript.xml+210
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/common_lisp.xml+184
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/coq.xml+136
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/core.xml+79
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/crystal.xml+762
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/css.xml+323
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/csv.xml+53
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cue.xml+85
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/cython.xml+372
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/d.xml+133
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml+213
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dax.xml+39
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/desktop_entry.xml+17
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/devicetree.xml+251
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/diff.xml+52
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/django_jinja.xml+153
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dns.xml+44
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/docker.xml+68
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dtd.xml+168
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dylan.xml+176
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ebnf.xml+90
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elixir.xml+744
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/elm.xml+119
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/emacslisp.xml+132
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/erb.xml+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/erlang.xml+166
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/factor.xml+412
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fennel.xml+68
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fish.xml+159
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/forth.xml+78
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortran.xml+102
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fortranfixed.xml+71
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/fsharp.xml+245
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gas.xml+150
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript.xml+259
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gdscript3.xml+270
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gemfile_lock.xml+81
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gettext.xml+24
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gherkin.xml+263
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gleam.xml+100
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/glsl.xml+65
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gnuplot.xml+289
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/go_template.xml+114
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/graphql.xml+92
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groff.xml+90
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/groovy.xml+135
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/handlebars.xml+147
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hare.xml+98
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/haskell.xml+275
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hcl.xml+143
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hexdump.xml+189
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlb.xml+131
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hlsl.xml+110
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/holyc.xml+252
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/html.xml+159
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/hy.xml+104
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/idris.xml+216
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/igor.xml+47
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ini.xml+52
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/io.xml+71
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/iscdhcpd.xml+96
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/j.xml+157
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/janet.xml+48
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml+206
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/javascript.xml+160
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml+117
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonata.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jsonnet.xml+138
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/julia.xml+400
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/jungle.xml+98
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kakoune.xml+96
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kdl.xml+75
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/kotlin.xml+234
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lateralus.xml+184
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lean.xml+56
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lighttpd_configuration_file.xml+42
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lilypond.xml+133
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/llvm.xml+73
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lox.xml+78
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lua.xml+158
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/luau.xml+173
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/makefile.xml+131
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mako.xml+120
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mason.xml+89
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/materialize_sql_dialect.xml+155
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mathematica.xml+60
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/matlab.xml+114
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mcfunction.xml+138
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/meson.xml+86
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/metal.xml+270
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/microcad.xml+139
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/minizinc.xml+82
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mlir.xml+73
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modelica.xml+106
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/modula-2.xml+245
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mojo.xml+228
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/monkeyc.xml+153
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonbit.xml+75
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/moonscript.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/morrowindscript.xml+90
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/myghty.xml+77
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/mysql.xml+121
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nasm.xml+126
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/natural.xml+143
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ndisasm.xml+123
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/newspeak.xml+121
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nginx_configuration_file.xml+101
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nim.xml+211
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nix.xml+258
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nsis.xml+59
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml+126
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objective-c.xml+510
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/objectpascal.xml+142
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ocaml.xml+153
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/octave.xml+101
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/odin.xml+127
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/onesenterprise.xml+92
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openedge_abl.xml+101
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/openscad.xml+96
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/org_mode.xml+329
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pacmanconf.xml+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/perl.xml+400
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/php.xml+258
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pig.xml+105
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pkgconfig.xml+73
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pl_pgsql.xml+119
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plaintext.xml+21
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/plutus_core.xml+105
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/pony.xml+135
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postgresql_sql_dialect.xml+155
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml+93
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/povray.xml+58
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powerquery.xml+51
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/powershell.xml+230
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prolog.xml+115
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promela.xml+119
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/promql.xml+123
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/properties.xml+45
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml+124
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/prql.xml+161
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/psl.xml+213
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/puppet.xml+100
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python.xml+595
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/python_2.xml+356
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qbasic.xml+173
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/qml.xml+113
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/r.xml+128
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/racket.xml+260
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ragel.xml+149
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/react.xml+236
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reasonml.xml+147
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/reg.xml+68
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rego.xml+94
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rexx.xml+127
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rgbasm.xml+239
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ring.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpgle.xml+176
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rpm_spec.xml+58
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml+728
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/rust.xml+375
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sas.xml+191
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sass.xml+362
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scala.xml+274
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scdoc.xml+115
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scheme.xml+106
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scilab.xml+98
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/scss.xml+373
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sed.xml+92
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sieve.xml+61
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smali.xml+73
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smalltalk.xml+294
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/smarty.xml+79
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snbt.xml+58
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/snobol.xml+95
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/solidity.xml+291
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sourcepawn.xml+59
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/spade.xml+292
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sparql.xml+160
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/sql.xml+90
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/squidconf.xml+63
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/standard_ml.xml+548
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stas.xml+85
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/stylus.xml+132
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/swift.xml+207
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemd.xml+63
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/systemverilog.xml+181
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tablegen.xml+69
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tal.xml+43
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tasm.xml+135
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcl.xml+272
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tcsh.xml+121
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/templ.xml+315
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/termcap.xml+75
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terminfo.xml+84
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/terraform.xml+149
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tex.xml+113
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/thrift.xml+154
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/toml.xml+45
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/tradingview.xml+81
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/transact-sql.xml+137
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turing.xml+82
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/turtle.xml+170
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/twig.xml+155
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/txtpb.xml+162
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typescript.xml+302
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscript.xml+178
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscriptcssdata.xml+52
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typoscripthtmldata.xml+52
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/typst.xml+108
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ucode.xml+147
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v.xml+355
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/v_shell.xml+365
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vala.xml+72
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vb_net.xml+162
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/verilog.xml+158
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhdl.xml+171
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vhs.xml+48
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/viml.xml+85
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/vue.xml+295
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wat.xml+149
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/wdte.xml+43
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webgpu_shading_language.xml+142
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/webvtt.xml+283
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/whiley.xml+57
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xml.xml+96
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/xorg.xml+35
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml+132
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yang.xml+99
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/z80_assembly.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zed.xml+51
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/embedded/zig.xml+187
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/erb.go+29
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/gemtext.go+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/genshi.go+118
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/go.go+81
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/haxe.go+647
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/html.go+8
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/http.go+131
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/lexers.go+85
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go+107
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/markless.go+168
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/mysql.go+33
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/php.go+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/raku.go+1710
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/rst.go+89
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/svelte.go+70
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/typoscript.go+85
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/yaml_jinja.go+20
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/lexers/zed.go+24
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/mutators.go+201
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/pygments-lexers.txt+605
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/quick/quick.go+44
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/regexp.go+533
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/registry.go+228
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/remap.go+94
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/renovate.json5+25
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/serialise.go+483
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/style.go+530
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/abap.xml+11
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/algol.xml+18
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/algol_nu.xml+18
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/api.go+95
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/arduino.xml+18
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/ashen.xml+69
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark-soft.xml+107
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/aura-theme-dark.xml+107
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/autumn.xml+36
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/average.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/base16-snazzy.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/borland.xml+26
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/bw.xml+23
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-frappe.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-macchiato.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-mocha.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/colorful.xml+52
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/compat.go+69
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/darcula.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/doom-one.xml+51
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/doom-one2.xml+64
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/dracula.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/emacs.xml+44
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/evergarden.xml+33
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/friendly.xml+44
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/fruity.xml+19
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/github-dark.xml+46
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/github.xml+39
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/gruvbox-light.xml+34
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/gruvbox.xml+34
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/hr_high_contrast.xml+12
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/hrdark.xml+10
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/igor.xml+9
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/kanagawa-dragon.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/kanagawa-lotus.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/kanagawa-wave.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/lovelace.xml+53
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/manni.xml+44
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/modus-operandi.xml+13
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/modus-vivendi.xml+13
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/monokai.xml+29
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/monokailight.xml+26
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/murphy.xml+52
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/native.xml+35
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/nord.xml+46
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/nordic.xml+46
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/onedark.xml+25
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/onesenterprise.xml+10
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/paraiso-dark.xml+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/paraiso-light.xml+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/pastie.xml+45
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/perldoc.xml+37
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/pygments.xml+42
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/rainbow_dash.xml+40
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-dawn.xml+29
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/rose-pine-moon.xml+29
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/rose-pine.xml+29
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/rpgle.xml+30
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/rrt.xml+19
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark.xml+39
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/solarized-dark256.xml+41
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/solarized-light.xml+17
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/swapoff.xml+18
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/tango.xml+72
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-day.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-moon.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-night.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/tokyonight-storm.xml+83
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/trac.xml+35
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/vim.xml+29
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/vs.xml+16
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/vulcan.xml+74
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/witchhazel.xml+31
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/xcode-dark.xml+31
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/styles/xcode.xml+22
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/table.py+31
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/test.jsonl+2
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/tokentype_enumer.go+588
This diff is too big to show here.
vendor/github.com/alecthomas/chroma/v2/types.go+357
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/.gitignore+2
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/LICENSE+19
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/README.md+19
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/backward_references.go+185
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/backward_references_hq.go+796
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/bit_cost.go+436
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/bit_reader.go+266
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/bitwriter.go+56
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/block_splitter.go+144
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/block_splitter_command.go+434
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/block_splitter_distance.go+433
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/block_splitter_literal.go+433
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/brotli_bit_stream.go+1435
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/cluster.go+30
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/cluster_command.go+164
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/cluster_distance.go+326
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/cluster_literal.go+326
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/command.go+254
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/compress_fragment.go+834
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go+775
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/constants.go+77
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/context.go+2176
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/decode.go+2581
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/dictionary.go+122890
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/dictionary_hash.go+32779
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/encode.go+1220
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/encoder.go+177
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/encoder_dict.go+22
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/encoder_fast.go+197
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/entropy_encode.go+592
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/entropy_encode_static.go+4399
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/fast_log.go+290
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/find_match_length.go+45
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/LICENSE+27
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/README.md+2
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/gzip.go+65
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go+517
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/huffman_code.go+346
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/token.go+80
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/flate/writer.go+66
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/h10.go+287
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/h5.go+214
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/h6.go+216
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/hash.go+342
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/hash_composite.go+93
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go+252
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go+214
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/hash_rolling.go+168
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/histogram.go+226
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/http.go+189
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/huffman.go+653
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/literal_cost.go+182
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/bargain1.go+212
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go+248
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go+278
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/emitter.go+34
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/m0.go+175
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/m4.go+339
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/matchfinder.go+103
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/pathfinder.go+328
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/textencoder.go+53
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/trio.go+326
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go+258
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/zfast.go+206
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/matchfinder/zm.go+301
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/memory.go+66
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/metablock.go+574
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/metablock_command.go+165
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/metablock_distance.go+165
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/metablock_literal.go+165
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/params.go+37
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/platform.go+103
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/prefix.go+30
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/prefix_dec.go+723
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/quality.go+196
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/reader.go+111
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/ringbuffer.go+134
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/state.go+294
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/static_dict.go+662
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/static_dict_lut.go+75094
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/symbol_list.go+22
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/transform.go+641
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/utf8_util.go+70
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/util.go+7
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/write_bits.go+52
This diff is too big to show here.
vendor/github.com/andybalholm/brotli/writer.go+162
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/.travis.yml+14
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/LICENSE+24
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/README.md+144
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/parser.go+889
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/pseudo_classes.go+458
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/selector.go+586
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/serialize.go+176
This diff is too big to show here.
vendor/github.com/andybalholm/cascadia/specificity.go+26
This diff is too big to show here.
vendor/github.com/atotto/clipboard/.travis.yml+22
This diff is too big to show here.
vendor/github.com/atotto/clipboard/LICENSE+27
This diff is too big to show here.
vendor/github.com/atotto/clipboard/README.md+48
This diff is too big to show here.
vendor/github.com/atotto/clipboard/clipboard.go+20
This diff is too big to show here.
vendor/github.com/atotto/clipboard/clipboard_darwin.go+52
This diff is too big to show here.
vendor/github.com/atotto/clipboard/clipboard_plan9.go+42
This diff is too big to show here.
vendor/github.com/atotto/clipboard/clipboard_unix.go+149
This diff is too big to show here.
vendor/github.com/atotto/clipboard/clipboard_windows.go+157
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/NOTICE.txt+3
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go+18
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go+33
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/config.go+254
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/context.go+22
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/credential_cache.go+235
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go+234
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/auto.go+38
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/configuration.go+43
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/defaults.go+50
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/defaults/doc.go+2
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/defaultsmode.go+95
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/doc.go+62
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go+247
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/errors.go+9
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/from_ptr.go+365
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/logging.go+119
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/logging_generate.go+95
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/metadata.go+213
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go+168
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/osname.go+24
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/osname_go115.go+24
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/recursion_detection.go+94
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id.go+27
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go+57
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go+398
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/CHANGELOG.md+203
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/debug.go+144
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/decode.go+218
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/encode.go+167
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/error.go+23
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/headers.go+24
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/middleware.go+71
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport.go+13
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi/transport_go117.go+12
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/header.go+175
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/header_value.go+521
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/message.go+99
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go+61
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/encoder.go+80
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/map.go+78
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/middleware.go+62
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go+68
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go+117
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/restjson/decoder_util.go+85
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/xml/error_utils.go+48
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go+20
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/token_bucket.go+96
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/token_rate_limit.go+83
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/request.go+25
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/restrict_file_permissions.go+21
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive.go+156
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive_ratelimit.go+158
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/adaptive_token_bucket.go+83
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go+51
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/doc.go+80
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/errors.go+20
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/jitter_backoff.go+124
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/metadata.go+52
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go+487
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retry.go+103
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go+228
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go+343
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/throttle_error.go+60
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retry/timeout_error.go+52
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/retryer.go+127
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/runtime.go+14
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/cache.go+115
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/const.go+40
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/header_rules.go+82
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go+70
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/hmac.go+13
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/host.go+75
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/scope.go+13
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/time.go+36
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/util.go+80
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go+420
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/presign_middleware.go+127
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/stream.go+86
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go+564
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/to_ptr.go+297
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go+355
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/content_type.go+42
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error.go+33
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go+56
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/timeout_read_closer.go+109
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/types.go+42
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/aws/version.go+8
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md+1097
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/auth_scheme_preference.go+19
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/config.go+237
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/defaultsmode.go+47
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/doc.go+20
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/env_config.go+966
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/generate.go+4
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/errors.go+22
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/ini.go+56
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/parse.go+109
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/sections.go+157
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/strings.go+89
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/token.go+32
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/tokenize.go+92
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/internal/ini/value.go+93
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/load_options.go+1371
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/local.go+51
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/provider.go+802
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/resolve.go+458
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/resolve_bearer_token.go+122
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/resolve_credentials.go+650
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go+1704
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md+990
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/doc.go+4
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds/doc.go+58
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds/provider.go+241
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/auth.go+48
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go+165
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/endpoints.go+20
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/middleware.go+164
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go+207
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/logincreds/dpop.go+150
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/logincreds/file.go+14
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/logincreds/provider.go+184
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/logincreds/token.go+110
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/processcreds/doc.go+92
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/processcreds/provider.go+296
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/doc.go+81
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go+232
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go+165
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_token_provider.go+147
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/static_provider.go+63
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go+338
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/web_identity_provider.go+181
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md+584
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_client.go+358
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetDynamicData.go+77
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetIAMInfo.go+103
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetInstanceIdentityDocument.go+110
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetMetadata.go+77
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetRegion.go+73
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetToken.go+119
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_op_GetUserData.go+61
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/auth.go+48
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/doc.go+12
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/endpoints.go+20
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/internal/config/resolvers.go+114
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/request_middleware.go+313
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/token_provider.go+261
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/auth.go+45
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/scheme.go+191
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/bearer_token_adapter.go+43
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/bearer_token_signer_adapter.go+35
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/credentials_adapter.go+46
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/smithy.go+2
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter.go+57
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter_eventstream.go+51
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md+544
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/config.go+65
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/endpoints.go+57
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/context/context.go+65
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/arn.go+94
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/doc.go+3
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/generate.go+7
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/host.go+51
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partition.go+76
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go+496
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json+267
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/endpoints.go+201
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md+519
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/endpoints.go+302
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/rand/rand.go+33
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/sdk/interfaces.go+9
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/sdk/time.go+74
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/sdkio/byte.go+12
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/shareddefaults/shared_config.go+47
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/strings/strings.go+11
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/sync/singleflight/LICENSE+28
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/sync/singleflight/docs.go+7
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/sync/singleflight/singleflight.go+210
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/timeconv/duration.go+13
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/CHANGELOG.md+486
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/credentials.go+141
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/error.go+17
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/compare.go+30
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/crypto/ecc.go+113
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/const.go+36
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/header_rules.go+82
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/headers.go+68
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/hmac.go+13
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/host.go+75
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/time.go+36
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/internal/v4/util.go+64
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/middleware.go+118
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/presign_middleware.go+117
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/smithy.go+92
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/v4a.go+520
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md+220
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/accept_encoding_gzip.go+176
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/doc.go+22
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md+571
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/context.go+56
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/doc.go+3
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/middleware.go+110
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/CHANGELOG.md+85
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_client.go+945
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_CreateOAuth2Token.go+212
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_DeleteConsoleAuthorizationConfiguration.go+168
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_DeleteResourcePermissionStatement.go+196
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_GetConsoleAuthorizationConfiguration.go+168
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_GetResourcePolicy.go+155
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_ListResourcePermissionStatements.go+261
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_PutConsoleAuthorizationConfiguration.go+168
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/api_op_PutResourcePermissionStatement.go+216
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/auth.go+361
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/deserializers.go+2474
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/doc.go+9
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/endpoints.go+854
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/generated.json+40
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints/endpoints.go+333
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/options.go+242
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/serializers.go+724
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/types/enums.go+46
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/types/errors.go+247
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/types/types.go+162
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/signin/validators.go+111
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md+792
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_client.go+929
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_GetRoleCredentials.go+165
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccountRoles.go+263
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccounts.go+261
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_Logout.go+164
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go+379
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/deserializers.go+1171
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/doc.go+27
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go+570
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/generated.json+35
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go+628
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/options.go+238
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/serializers.go+309
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/types/errors.go+115
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/types/types.go+63
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sso/validators.go+175
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md+790
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_client.go+929
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateToken.go+235
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateTokenWithIAM.go+282
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_RegisterClient.go+206
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_StartDeviceAuthorization.go+188
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go+373
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/deserializers.go+2244
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/doc.go+49
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go+570
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/generated.json+36
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go+628
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/options.go+238
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/serializers.go+512
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/enums.go+44
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/errors.go+430
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/types.go+25
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/validators.go+184
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md+832
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/LICENSE.txt+202
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go+1115
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRole.go+544
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithSAML.go+455
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithWebIdentity.go+472
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoot.go+229
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_DecodeAuthorizationMessage.go+189
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetAccessKeyInfo.go+180
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetCallerIdentity.go+192
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetDelegatedAccessToken.go+169
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetFederationToken.go+393
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetSessionToken.go+239
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetWebIdentityToken.go+192
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go+377
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/deserializers.go+3456
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/doc.go+13
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go+683
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json+45
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go+585
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go+286
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/serializers.go+1198
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/errors.go+363
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/types.go+144
This diff is too big to show here.
vendor/github.com/aws/aws-sdk-go-v2/service/sts/validators.go+433
This diff is too big to show here.
vendor/github.com/aws/smithy-go/.gitignore+29
This diff is too big to show here.
vendor/github.com/aws/smithy-go/.travis.yml+28
This diff is too big to show here.
vendor/github.com/aws/smithy-go/AGENTS.md+172
This diff is too big to show here.
vendor/github.com/aws/smithy-go/CHANGELOG.md+454
This diff is too big to show here.
vendor/github.com/aws/smithy-go/CODE_OF_CONDUCT.md+4
This diff is too big to show here.
vendor/github.com/aws/smithy-go/CONTRIBUTING.md+90
This diff is too big to show here.
vendor/github.com/aws/smithy-go/LICENSE+175
This diff is too big to show here.
vendor/github.com/aws/smithy-go/Makefile+130
This diff is too big to show here.
vendor/github.com/aws/smithy-go/NOTICE+1
This diff is too big to show here.
vendor/github.com/aws/smithy-go/README.md+107
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/auth.go+3
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/bearer/docs.go+3
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/bearer/middleware.go+104
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/bearer/token.go+50
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/bearer/token_cache.go+208
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/identity.go+47
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/option.go+25
This diff is too big to show here.
vendor/github.com/aws/smithy-go/auth/scheme_id.go+20
This diff is too big to show here.
vendor/github.com/aws/smithy-go/changelog-template.json+9
This diff is too big to show here.
vendor/github.com/aws/smithy-go/context/suppress_expired.go+81
This diff is too big to show here.
vendor/github.com/aws/smithy-go/doc.go+2
This diff is too big to show here.
vendor/github.com/aws/smithy-go/document.go+10
This diff is too big to show here.
vendor/github.com/aws/smithy-go/document/doc.go+12
This diff is too big to show here.
vendor/github.com/aws/smithy-go/document/document.go+239
This diff is too big to show here.
vendor/github.com/aws/smithy-go/document/errors.go+75
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/doc.go+4
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/encoding.go+40
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/httpbinding/encode.go+123
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/httpbinding/header.go+122
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/httpbinding/path_replace.go+108
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/httpbinding/query.go+107
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/httpbinding/uri.go+111
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/array.go+35
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/constants.go+15
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/decoder_util.go+139
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/encoder.go+30
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/escape.go+198
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/object.go+40
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/json/value.go+154
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/array.go+49
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/constants.go+10
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/doc.go+49
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/element.go+91
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/encoder.go+51
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/error_utils.go+51
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/escape.go+137
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/map.go+53
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/value.go+302
This diff is too big to show here.
vendor/github.com/aws/smithy-go/encoding/xml/xml_decoder.go+154
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/endpoint.go+23
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/private/bdd/evaluate.go+35
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/doc.go+4
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/split.go+16
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/string_slice.go+18
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/strings.go+25
This diff is too big to show here.
vendor/github.com/aws/smithy-go/endpoints/private/rulesfn/uri.go+133
This diff is too big to show here.
vendor/github.com/aws/smithy-go/errors.go+137
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/const.go+24
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/debug.go+144
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/decode.go+218
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/deserializer.go+294
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/encode.go+167
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/error.go+23
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/header.go+175
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/header_value.go+521
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/message.go+99
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/serializer.go+228
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/signer.go+82
This diff is too big to show here.
vendor/github.com/aws/smithy-go/eventstream/types.go+26
This diff is too big to show here.
vendor/github.com/aws/smithy-go/go_module_metadata.go+6
This diff is too big to show here.
vendor/github.com/aws/smithy-go/internal/sync/singleflight/LICENSE+28
This diff is too big to show here.
vendor/github.com/aws/smithy-go/internal/sync/singleflight/docs.go+8
This diff is too big to show here.
vendor/github.com/aws/smithy-go/internal/sync/singleflight/singleflight.go+210
This diff is too big to show here.
vendor/github.com/aws/smithy-go/io/byte.go+12
This diff is too big to show here.
vendor/github.com/aws/smithy-go/io/doc.go+2
This diff is too big to show here.
vendor/github.com/aws/smithy-go/io/reader.go+16
This diff is too big to show here.
vendor/github.com/aws/smithy-go/io/ringbuffer.go+94
This diff is too big to show here.
vendor/github.com/aws/smithy-go/local-mod-replace.sh+39
This diff is too big to show here.
vendor/github.com/aws/smithy-go/logging/logger.go+82
This diff is too big to show here.
vendor/github.com/aws/smithy-go/metrics/metrics.go+136
This diff is too big to show here.
vendor/github.com/aws/smithy-go/metrics/nop.go+98
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/context.go+41
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/doc.go+67
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/eventstream_middleware.go+21
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/logging.go+46
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/metadata.go+65
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/middleware.go+71
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/ordered_group.go+270
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/stack.go+209
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/stack_values.go+100
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/step_build.go+298
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/step_deserialize.go+300
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/step_finalize.go+298
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/step_initialize.go+299
This diff is too big to show here.
vendor/github.com/aws/smithy-go/middleware/step_serialize.go+305
This diff is too big to show here.
vendor/github.com/aws/smithy-go/modman.toml+9
This diff is too big to show here.
vendor/github.com/aws/smithy-go/private/requestcompression/gzip.go+30
This diff is too big to show here.
vendor/github.com/aws/smithy-go/private/requestcompression/middleware_capture_request_compression.go+52
This diff is too big to show here.
vendor/github.com/aws/smithy-go/private/requestcompression/request_compression.go+103
This diff is too big to show here.
vendor/github.com/aws/smithy-go/properties.go+69
This diff is too big to show here.
vendor/github.com/aws/smithy-go/ptr/doc.go+5
This diff is too big to show here.
vendor/github.com/aws/smithy-go/ptr/from_ptr.go+601
This diff is too big to show here.
vendor/github.com/aws/smithy-go/ptr/gen_scalars.go+83
This diff is too big to show here.
vendor/github.com/aws/smithy-go/ptr/to_ptr.go+499
This diff is too big to show here.
vendor/github.com/aws/smithy-go/rand/doc.go+3
This diff is too big to show here.
vendor/github.com/aws/smithy-go/rand/rand.go+31
This diff is too big to show here.
vendor/github.com/aws/smithy-go/rand/uuid.go+87
This diff is too big to show here.
vendor/github.com/aws/smithy-go/schema.go+328
This diff is too big to show here.
vendor/github.com/aws/smithy-go/schema_ext.go+37
This diff is too big to show here.
vendor/github.com/aws/smithy-go/serde.go+229
This diff is too big to show here.
vendor/github.com/aws/smithy-go/sync/error.go+53
This diff is too big to show here.
vendor/github.com/aws/smithy-go/time/time.go+134
This diff is too big to show here.
vendor/github.com/aws/smithy-go/tracing/context.go+96
This diff is too big to show here.
vendor/github.com/aws/smithy-go/tracing/nop.go+32
This diff is too big to show here.
vendor/github.com/aws/smithy-go/tracing/tracing.go+95
This diff is too big to show here.
vendor/github.com/aws/smithy-go/trait.go+21
This diff is too big to show here.
vendor/github.com/aws/smithy-go/traits/http.go+69
This diff is too big to show here.
vendor/github.com/aws/smithy-go/traits/index.go+107
This diff is too big to show here.
vendor/github.com/aws/smithy-go/traits/serde.go+56
This diff is too big to show here.
vendor/github.com/aws/smithy-go/traits/traits.go+72
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/auth.go+30
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/auth_schemes.go+45
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/checksum_middleware.go+70
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/client.go+161
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/doc.go+5
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/eventstream.go+209
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/eventstream_middleware.go+69
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/headerlist.go+163
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/host.go+89
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/interceptor.go+321
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/interceptor_middleware.go+325
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/internal/io/safe.go+75
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/md5_checksum.go+25
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/metrics.go+204
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go+79
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_content_length.go+84
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_header_comment.go+81
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_headers.go+167
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_http_logging.go+75
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_metadata.go+51
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/middleware_min_proto.go+79
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/properties.go+80
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/protocol.go+27
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/request.go+188
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/response.go+34
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/time.go+13
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/url.go+44
This diff is too big to show here.
vendor/github.com/aws/smithy-go/transport/http/user_agent.go+37
This diff is too big to show here.
vendor/github.com/aws/smithy-go/type_registry.go+70
This diff is too big to show here.
vendor/github.com/aws/smithy-go/validation.go+140
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/LICENSE-BSD+27
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/LICENSE-MIT+21
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/Makefile+4
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/README.md+142
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/diff.go+177
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/export.go+16
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/common.go+179
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/doc.go+156
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/export.go+11
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/git.sh+33
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/labels.go+55
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/old.go+475
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/lcs/sequence.go+70
This diff is too big to show here.
vendor/github.com/aymanbagabas/go-udiff/merge.go+81
This diff is too big to show here.
5779 more files changed are not listed.