@oh-my-pi/pi-coding-agent 16.2.7 → 16.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/dist/cli.js +3661 -3482
- package/dist/types/config/settings-schema.d.ts +97 -13
- package/dist/types/edit/hashline/filesystem.d.ts +1 -0
- package/dist/types/modes/components/mcp-add-wizard.d.ts +8 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +9 -0
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +0 -5
- package/dist/types/session/settings-stream-fn.d.ts +2 -2
- package/dist/types/stt/index.d.ts +1 -0
- package/dist/types/stt/stt-controller.d.ts +2 -0
- package/dist/types/stt/submit-trigger.d.ts +30 -0
- package/dist/types/task/index.d.ts +1 -1
- package/dist/types/task/types.d.ts +6 -6
- package/dist/types/tiny/models.d.ts +22 -8
- package/dist/types/tools/output-schema-validator.d.ts +10 -0
- package/package.json +12 -12
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/agentic/prompts/system.md +1 -1
- package/src/commit/agentic/tools/analyze-file.ts +2 -2
- package/src/config/settings-schema.ts +54 -2
- package/src/debug/profiler.ts +7 -1
- package/src/discovery/builtin-rules/go-add-cleanup.md +32 -0
- package/src/discovery/builtin-rules/go-bench-loop.md +36 -0
- package/src/discovery/builtin-rules/go-exp-promoted.md +39 -0
- package/src/discovery/builtin-rules/go-ioutil.md +36 -0
- package/src/discovery/builtin-rules/go-join-hostport.md +29 -0
- package/src/discovery/builtin-rules/go-new-expr.md +44 -0
- package/src/discovery/builtin-rules/go-rand-v2.md +40 -0
- package/src/discovery/builtin-rules/go-range-int.md +45 -0
- package/src/discovery/builtin-rules/index.ts +16 -0
- package/src/edit/hashline/filesystem.ts +12 -0
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/mcp/oauth-flow.ts +35 -8
- package/src/modes/components/mcp-add-wizard.ts +43 -3
- package/src/modes/components/model-selector.ts +21 -9
- package/src/modes/controllers/event-controller.ts +9 -0
- package/src/modes/controllers/mcp-command-controller.ts +84 -3
- package/src/modes/controllers/tool-args-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +5 -4
- package/src/prompts/agents/tester.md +107 -0
- package/src/prompts/system/orchestrate-notice.md +2 -2
- package/src/prompts/system/system-prompt.md +2 -5
- package/src/prompts/system/thinking-loop-redirect.md +10 -0
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/bash.md +1 -4
- package/src/prompts/tools/task.md +2 -9
- package/src/session/agent-session.ts +161 -24
- package/src/session/session-context.ts +13 -2
- package/src/session/settings-stream-fn.ts +12 -2
- package/src/stt/index.ts +1 -0
- package/src/stt/stt-controller.ts +31 -2
- package/src/stt/submit-trigger.ts +74 -0
- package/src/task/agents.ts +4 -4
- package/src/task/executor.ts +1 -1
- package/src/task/index.ts +18 -5
- package/src/task/types.ts +5 -5
- package/src/tiny/models.ts +10 -0
- package/src/tools/grep.ts +19 -1
- package/src/tools/output-schema-validator.ts +38 -0
- package/src/tools/yield.ts +52 -15
- package/src/prompts/agents/oracle.md +0 -54
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Prefer runtime.AddCleanup over runtime.SetFinalizer for new code (Go 1.24)"
|
|
3
|
+
condition: 'runtime\.SetFinalizer'
|
|
4
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Go 1.24 added `runtime.AddCleanup`, a finalization mechanism that is more flexible and less error-prone than `runtime.SetFinalizer`. The release notes state plainly: **new code should prefer `AddCleanup` over `SetFinalizer`.**
|
|
8
|
+
|
|
9
|
+
## Why AddCleanup wins
|
|
10
|
+
|
|
11
|
+
- Multiple cleanups may attach to one object; `SetFinalizer` allows only one.
|
|
12
|
+
- Cleanups may attach to interior pointers.
|
|
13
|
+
- Objects that form a reference cycle still get cleaned up — finalizers leak them.
|
|
14
|
+
- A cleanup does not resurrect its object or delay freeing it (and what it points to) by an extra GC cycle.
|
|
15
|
+
|
|
16
|
+
## Migration
|
|
17
|
+
|
|
18
|
+
```go
|
|
19
|
+
// Before
|
|
20
|
+
runtime.SetFinalizer(obj, func(o *T) { o.release() })
|
|
21
|
+
|
|
22
|
+
// After — the cleanup func receives a value you supply, NOT the object,
|
|
23
|
+
// so it cannot accidentally keep the object alive.
|
|
24
|
+
runtime.AddCleanup(obj, func(h handle) { h.release() }, obj.handle)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The cleanup argument must not reference `obj` itself (that would keep it reachable forever). Capture only the data the cleanup needs — a file descriptor, handle, or pointer that is independent of `obj`.
|
|
28
|
+
|
|
29
|
+
## Keep SetFinalizer only when
|
|
30
|
+
|
|
31
|
+
- The module targets a Go release older than 1.24.
|
|
32
|
+
- You depend on finalizer-specific behavior (e.g. object resurrection) that `AddCleanup` deliberately does not provide.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use for b.Loop() in benchmarks instead of the for i := 0; i < b.N; i++ loop (Go 1.24)"
|
|
3
|
+
interruptMode: never
|
|
4
|
+
scope: "tool:edit(*_test.go), tool:write(*_test.go)"
|
|
5
|
+
astCondition:
|
|
6
|
+
- "func $F($B *testing.B) { $$$PRE for $I := 0; $I < $B.N; $I++ { $$$BODY } $$$POST }"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Go 1.24 added `testing.B.Loop`. Write `for b.Loop() { ... }` instead of looping over `b.N`.
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
- Setup and teardown outside the loop run exactly once per `-count`, not once per `b.N` re-estimation, so expensive fixtures are no longer timed or repeated.
|
|
14
|
+
- The compiler keeps the loop's parameters and results alive, so it can't optimize away the body you are trying to measure — a classic `b.N` benchmarking footgun.
|
|
15
|
+
|
|
16
|
+
## Avoid
|
|
17
|
+
|
|
18
|
+
```go
|
|
19
|
+
func BenchmarkEncode(b *testing.B) {
|
|
20
|
+
for i := 0; i < b.N; i++ {
|
|
21
|
+
Encode(input)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Use
|
|
27
|
+
|
|
28
|
+
```go
|
|
29
|
+
func BenchmarkEncode(b *testing.B) {
|
|
30
|
+
for b.Loop() {
|
|
31
|
+
Encode(input)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Requires Go 1.24+. If the module targets an older Go, keep the `b.N` loop.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use the standard library slices and maps packages instead of golang.org/x/exp/{slices,maps}"
|
|
3
|
+
condition:
|
|
4
|
+
- '"golang.org/x/exp/slices"'
|
|
5
|
+
- '"golang.org/x/exp/maps"'
|
|
6
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
`golang.org/x/exp/slices` and `golang.org/x/exp/maps` were promoted into the standard library as `slices` and `maps` in Go 1.21. Import the stdlib packages in new code instead of the experimental ones.
|
|
10
|
+
|
|
11
|
+
## Migration
|
|
12
|
+
|
|
13
|
+
```go
|
|
14
|
+
// Before
|
|
15
|
+
import (
|
|
16
|
+
"golang.org/x/exp/slices"
|
|
17
|
+
"golang.org/x/exp/maps"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
// After
|
|
21
|
+
import (
|
|
22
|
+
"slices"
|
|
23
|
+
"maps"
|
|
24
|
+
)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Most call sites are unchanged: `slices.Sort`, `slices.Contains`, `slices.Index`, `slices.Equal`, `maps.Clone`, etc.
|
|
28
|
+
|
|
29
|
+
## Watch the signature differences
|
|
30
|
+
|
|
31
|
+
The promoted APIs were tweaked, so a blind path swap can break the build:
|
|
32
|
+
|
|
33
|
+
- `x/exp/maps.Keys(m)` / `Values(m)` returned a slice; the stdlib `maps.Keys(m)` / `maps.Values(m)` return an **iterator** (`iter.Seq`). Use `slices.Collect(maps.Keys(m))` to recover a slice, or range over the iterator.
|
|
34
|
+
- `slices.SortFunc` takes a comparison returning `int` (cmp-style), matching the stdlib signature.
|
|
35
|
+
|
|
36
|
+
## Keep x/exp when
|
|
37
|
+
|
|
38
|
+
- The module's `go` directive is below 1.21 (stdlib `slices`/`maps` don't exist yet).
|
|
39
|
+
- You need an `x/exp` helper that was not promoted (e.g. parts of `x/exp/constraints` still live outside the stdlib).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use io and os instead of the deprecated io/ioutil package"
|
|
3
|
+
condition: '"io/ioutil"'
|
|
4
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`io/ioutil` has been deprecated since Go 1.16. Every function moved to `io` or `os` with the same behavior. Do not import it in new code.
|
|
8
|
+
|
|
9
|
+
## Mapping
|
|
10
|
+
|
|
11
|
+
| io/ioutil | Replacement |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `ioutil.ReadAll` | `io.ReadAll` |
|
|
14
|
+
| `ioutil.ReadFile` | `os.ReadFile` |
|
|
15
|
+
| `ioutil.WriteFile` | `os.WriteFile` |
|
|
16
|
+
| `ioutil.ReadDir` | `os.ReadDir` (returns `[]os.DirEntry`, not `[]os.FileInfo`) |
|
|
17
|
+
| `ioutil.TempFile` | `os.CreateTemp` |
|
|
18
|
+
| `ioutil.TempDir` | `os.MkdirTemp` |
|
|
19
|
+
| `ioutil.NopCloser` | `io.NopCloser` |
|
|
20
|
+
| `ioutil.Discard` | `io.Discard` |
|
|
21
|
+
|
|
22
|
+
## Migration
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
// Before
|
|
26
|
+
import "io/ioutil"
|
|
27
|
+
data, err := ioutil.ReadFile(path)
|
|
28
|
+
_ = ioutil.WriteFile(out, data, 0o644)
|
|
29
|
+
|
|
30
|
+
// After
|
|
31
|
+
import "os"
|
|
32
|
+
data, err := os.ReadFile(path)
|
|
33
|
+
_ = os.WriteFile(out, data, 0o644)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`os.ReadDir` returns `[]os.DirEntry` rather than `[]os.FileInfo` — call `entry.Info()` if you need the old `FileInfo`. Everything else is a drop-in rename.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Build network addresses with net.JoinHostPort, not fmt.Sprintf(\"%s:%d\", host, port) — the Sprintf form breaks on IPv6"
|
|
3
|
+
condition: 'fmt\.Sprintf\("%s:%d"'
|
|
4
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Use `net.JoinHostPort(host, port)` to assemble a `host:port` address. `fmt.Sprintf("%s:%d", host, port)` produces invalid addresses for IPv6 hosts, which must be bracketed (`[::1]:80`). Go 1.25's `go vet` `hostport` analyzer flags exactly this pattern.
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
- An IPv6 literal like `::1` has its own colons, so `fmt.Sprintf("%s:%d", "::1", 80)` yields `::1:80` — unparseable by `net.Dial`.
|
|
12
|
+
- `net.JoinHostPort` adds the brackets when the host contains a colon and leaves IPv4/hostnames untouched.
|
|
13
|
+
|
|
14
|
+
## Avoid
|
|
15
|
+
|
|
16
|
+
```go
|
|
17
|
+
addr := fmt.Sprintf("%s:%d", host, port)
|
|
18
|
+
conn, err := net.Dial("tcp", addr)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Use
|
|
22
|
+
|
|
23
|
+
```go
|
|
24
|
+
// port is a string here; convert an int with strconv.Itoa.
|
|
25
|
+
addr := net.JoinHostPort(host, strconv.Itoa(port))
|
|
26
|
+
conn, err := net.Dial("tcp", addr)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`net.JoinHostPort` takes the port as a string. For an `int` port, wrap it in `strconv.Itoa`. The function is available in every supported Go version.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use new(expr) for pointer-to-value helpers instead of `func ptr[T any](v T) *T { return &v }` (Go 1.26)"
|
|
3
|
+
interruptMode: never
|
|
4
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
5
|
+
astCondition:
|
|
6
|
+
- "func $F($V $T) *$T { return &$V }"
|
|
7
|
+
- "func $F[$$$TP]($V $T) *$T { return &$V }"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Go 1.26 lets `new` take an expression: `new(expr)` allocates, stores `expr`, and returns its `*T`. That removes the need for hand-written `Ptr`/`boolPtr`/`Int64`-style helpers and the `x := v; p := &x` two-step.
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
- One builtin replaces a helper per type (`boolPtr`, `strPtr`, `int64Ptr`, …) and the generic `func Ptr[T any](v T) *T`.
|
|
15
|
+
- No extra function-call frame and no separate heap escape — the value is constructed directly in the allocation.
|
|
16
|
+
- The intent (`new(false)`) reads at the call site instead of hiding behind a helper name.
|
|
17
|
+
|
|
18
|
+
## Avoid
|
|
19
|
+
|
|
20
|
+
```go
|
|
21
|
+
// A helper that just takes a value and returns its address.
|
|
22
|
+
func boolPtr(v bool) *bool { return &v }
|
|
23
|
+
func strPtr(v string) *string { return &v }
|
|
24
|
+
func Ptr[T any](v T) *T { return &v }
|
|
25
|
+
|
|
26
|
+
cfg := Config{Enabled: boolPtr(true), Name: strPtr("svc")}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Use
|
|
30
|
+
|
|
31
|
+
```go
|
|
32
|
+
cfg := Config{Enabled: new(true), Name: new("svc")}
|
|
33
|
+
|
|
34
|
+
// Was: x := int64(300); p := &x
|
|
35
|
+
p := new(int64(300))
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`new(true)` / `new(false)` give you `*bool`; `new(expr)` works for any expression, including function results (`new(time.Now())`).
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- Requires Go 1.26+. If the module's `go` directive is older, keep the helper or the temp-variable form until the toolchain is bumped.
|
|
43
|
+
- This is for helpers that *only* take a value and return its address. A function that does real work before taking an address is not in scope.
|
|
44
|
+
- `new(T)` (a bare type) is unchanged and still zero-initializes.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Prefer math/rand/v2 over the legacy math/rand package
|
|
3
|
+
condition: '"math/rand"'
|
|
4
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Use `math/rand/v2` instead of the legacy `math/rand` package (stable since Go 1.22).
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
- No global `Seed`: `math/rand`'s top-level functions read a process-global generator (auto-seeded since Go 1.20), so a fixed seed is global mutable state that's easy to misuse; `v2` drops the global `Seed` entirely.
|
|
12
|
+
- Cleaner, better-bounded API: `rand.IntN(n)` / generic `rand.N(n)` replace `rand.Intn(n)`, and `Shuffle`, `Perm`, `Float64` carry over with clearer names.
|
|
13
|
+
- Modern generators: `v2` exposes `PCG` and `ChaCha8` sources instead of the old default LCG.
|
|
14
|
+
|
|
15
|
+
## Migration
|
|
16
|
+
|
|
17
|
+
```go
|
|
18
|
+
// Before
|
|
19
|
+
import "math/rand"
|
|
20
|
+
n := rand.Intn(100)
|
|
21
|
+
f := rand.Float64()
|
|
22
|
+
|
|
23
|
+
// After
|
|
24
|
+
import "math/rand/v2"
|
|
25
|
+
n := rand.IntN(100)
|
|
26
|
+
f := rand.Float64()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| math/rand | math/rand/v2 |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| `rand.Intn(n)` | `rand.IntN(n)` |
|
|
32
|
+
| `rand.Int63n(n)` | `rand.Int64N(n)` |
|
|
33
|
+
| `rand.Intn`/`Int31n` on a `*Rand` | `(*Rand).IntN` / `Int32N` |
|
|
34
|
+
| `rand.Seed(x)` | drop it — `v2` has no global seed |
|
|
35
|
+
| explicit `rand.New(rand.NewSource(seed))` | `rand.New(rand.NewPCG(s1, s2))` or `rand.NewChaCha8(seed)` |
|
|
36
|
+
|
|
37
|
+
## Keep math/rand only when
|
|
38
|
+
|
|
39
|
+
- You need a reproducible stream from a fixed seed via the classic `NewSource`/`Seed` API that a caller already depends on.
|
|
40
|
+
- Reach for `crypto/rand` instead when the values are security-sensitive — neither `math/rand` variant is cryptographically secure.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use for i := range n instead of the C-style for i := 0; i < n; i++ loop (Go 1.22)"
|
|
3
|
+
interruptMode: never
|
|
4
|
+
scope: "tool:edit(*.go), tool:write(*.go)"
|
|
5
|
+
astCondition:
|
|
6
|
+
- "for $I := 0; $I < $N; $I++ { $$$BODY }"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Go 1.22 lets `for` range over an integer. A plain counting loop from `0` to `n` with step `1` reads better as `for i := range n` (or `for range n` when the index is unused).
|
|
10
|
+
|
|
11
|
+
## Avoid
|
|
12
|
+
|
|
13
|
+
```go
|
|
14
|
+
for i := 0; i < n; i++ {
|
|
15
|
+
use(i)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
for i := 0; i < len(s); i++ {
|
|
19
|
+
use(s[i])
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Use
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
for i := range n {
|
|
27
|
+
use(i)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Ranging the slice directly is usually clearer than indexing.
|
|
31
|
+
for i := range s {
|
|
32
|
+
use(s[i])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Index unused → drop it entirely.
|
|
36
|
+
for range n {
|
|
37
|
+
tick()
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## When it does not apply
|
|
42
|
+
|
|
43
|
+
- Non-zero start, step other than `++`, or a descending loop (`for i := n - 1; i >= 0; i--`) — keep the explicit form.
|
|
44
|
+
- The body reassigns the loop variable or depends on `i` surviving past the loop.
|
|
45
|
+
- Requires Go 1.22+. If the module's `go` directive is older, keep the classic loop.
|
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
* Registered by the lowest-priority `builtin-defaults` rule provider so any
|
|
9
9
|
* user/project/tool rule with the same name overrides the bundled copy.
|
|
10
10
|
*/
|
|
11
|
+
import goAddCleanup from "./go-add-cleanup.md" with { type: "text" };
|
|
12
|
+
import goBenchLoop from "./go-bench-loop.md" with { type: "text" };
|
|
13
|
+
import goExpPromoted from "./go-exp-promoted.md" with { type: "text" };
|
|
14
|
+
import goIoutil from "./go-ioutil.md" with { type: "text" };
|
|
15
|
+
import goJoinHostport from "./go-join-hostport.md" with { type: "text" };
|
|
16
|
+
import goNewExpr from "./go-new-expr.md" with { type: "text" };
|
|
17
|
+
import goRandV2 from "./go-rand-v2.md" with { type: "text" };
|
|
18
|
+
import goRangeInt from "./go-range-int.md" with { type: "text" };
|
|
11
19
|
import rsBoxLeak from "./rs-box-leak.md" with { type: "text" };
|
|
12
20
|
import rsFuturePrelude from "./rs-future-prelude.md" with { type: "text" };
|
|
13
21
|
import rsLazylock from "./rs-lazylock.md" with { type: "text" };
|
|
@@ -35,6 +43,14 @@ export interface BuiltinRuleSource {
|
|
|
35
43
|
|
|
36
44
|
/** All bundled default rules, ordered by name. */
|
|
37
45
|
export const BUILTIN_RULE_SOURCES: readonly BuiltinRuleSource[] = [
|
|
46
|
+
{ name: "go-add-cleanup", content: goAddCleanup },
|
|
47
|
+
{ name: "go-bench-loop", content: goBenchLoop },
|
|
48
|
+
{ name: "go-exp-promoted", content: goExpPromoted },
|
|
49
|
+
{ name: "go-ioutil", content: goIoutil },
|
|
50
|
+
{ name: "go-join-hostport", content: goJoinHostport },
|
|
51
|
+
{ name: "go-new-expr", content: goNewExpr },
|
|
52
|
+
{ name: "go-rand-v2", content: goRandV2 },
|
|
53
|
+
{ name: "go-range-int", content: goRangeInt },
|
|
38
54
|
{ name: "rs-box-leak", content: rsBoxLeak },
|
|
39
55
|
{ name: "rs-future-prelude", content: rsFuturePrelude },
|
|
40
56
|
{ name: "rs-lazylock", content: rsLazylock },
|
|
@@ -28,6 +28,7 @@ import { invalidateFsScanAfterWrite } from "../../tools/fs-cache-invalidation";
|
|
|
28
28
|
import { isInternalUrlPath } from "../../tools/path-utils";
|
|
29
29
|
import { enforcePlanModeWrite, resolvePlanPath, targetsLocalSandbox } from "../../tools/plan-mode-guard";
|
|
30
30
|
import { canonicalSnapshotKey } from "../file-snapshot-store";
|
|
31
|
+
import { isNotebookPath } from "../notebook";
|
|
31
32
|
import { readEditFileText, serializeEditFileText } from "../read-file";
|
|
32
33
|
import type { LspBatchRequest } from "../renderer";
|
|
33
34
|
|
|
@@ -123,6 +124,17 @@ export class HashlineFilesystem extends Filesystem {
|
|
|
123
124
|
return content;
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
async readBinary(relativePath: string): Promise<Uint8Array | undefined> {
|
|
128
|
+
const absolutePath = this.resolveAbsolute(relativePath);
|
|
129
|
+
if (isNotebookPath(absolutePath)) return undefined;
|
|
130
|
+
try {
|
|
131
|
+
return await fs.readFile(absolutePath);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (isEnoent(error)) throw new NotFoundError(relativePath, error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
126
138
|
async preflightWrite(relativePath: string, options?: PreflightWriteOptions): Promise<void> {
|
|
127
139
|
const fileOp = options?.fileOp;
|
|
128
140
|
if (fileOp?.kind === "rem") {
|