Skip to content

Commit f0ef669

Browse files
authored
Merge branch 'main' into feat/feishu-2
2 parents b28981a + f6571d5 commit f0ef669

147 files changed

Lines changed: 9399 additions & 3523 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/reference/gateway-rpc-api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ Response Schema:
440440
"saved_ratio": 0.63,
441441
"trigger_mode": "manual",
442442
"transcript_id": "compact-1",
443-
"transcript_path": ".neocode/transcripts/compact-1.md"
443+
"transcript_path": ".neocode/transcripts/compact-subagent.md"
444444
}
445445
}
446446
}
@@ -1147,7 +1147,7 @@ Success Response:
11471147
"SavedRatio": 0.63,
11481148
"TriggerMode": "manual",
11491149
"TranscriptID": "compact-demo-1",
1150-
"TranscriptPath": ".neocode/transcripts/compact-demo-1.md"
1150+
"TranscriptPath": ".neocode/transcripts/compact-demo-subagent.md"
11511151
}
11521152
}
11531153
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# TUI-Gateway Contract Matrix (Single-Version Baseline)
2+
3+
This document freezes the contract that TUI consumes from gateway.
4+
It is intentionally single-version and fail-fast by design.
5+
6+
## Scope
7+
8+
- Transport contract: JSON-RPC 2.0 (`internal/gateway/protocol`)
9+
- Runtime contract: gateway DTOs (`internal/gateway/contracts.go`)
10+
- Event payload version source of truth: `internal/runtime/controlplane/envelope.go`
11+
12+
## RPC Methods Used By TUI
13+
14+
| Method | Params Type | Result Payload | Notes |
15+
| --- | --- | --- | --- |
16+
| `gateway.authenticate` | `protocol.AuthenticateParams` | frame ack | Must succeed before runtime actions |
17+
| `gateway.bindStream` | `protocol.BindStreamParams` | frame ack | Binds session/run event stream |
18+
| `gateway.run` | `protocol.RunParams` | frame ack with `session_id`/`run_id` | Async acceptance only |
19+
| `gateway.compact` | `protocol.CompactParams` | `gateway.CompactResult` | Manual compact |
20+
| `gateway.executeSystemTool` | `protocol.ExecuteSystemToolParams` | `tools.ToolResult` | Tool execution passthrough |
21+
| `gateway.resolvePermission` | `protocol.ResolvePermissionParams` | frame ack | Permission decision submit |
22+
| `gateway.cancel` | `protocol.CancelParams` | frame ack | Cancels run by run/session binding |
23+
| `gateway.listSessions` | none | `[]gateway.SessionSummary` | Session list |
24+
| `gateway.loadSession` | `protocol.LoadSessionParams` | `gateway.Session` | Full session snapshot |
25+
| `gateway.activateSessionSkill` | `protocol.ActivateSessionSkillParams` | frame ack | Activate skill in session |
26+
| `gateway.deactivateSessionSkill` | `protocol.DeactivateSessionSkillParams` | frame ack | Deactivate skill in session |
27+
| `gateway.listSessionSkills` | `protocol.ListSessionSkillsParams` | `[]gateway.SessionSkillState` | Active skill states |
28+
| `gateway.listAvailableSkills` | `protocol.ListAvailableSkillsParams` | `[]gateway.AvailableSkillState` | Available skill catalog |
29+
30+
## Runtime Event Contract
31+
32+
- Notification method: `gateway.event`
33+
- TUI only accepts a runtime envelope payload with these required keys:
34+
- `runtime_event_type` (string)
35+
- `turn` (number)
36+
- `phase` (string)
37+
- `timestamp` (RFC3339 or RFC3339Nano)
38+
- `payload_version` (number)
39+
- `payload` (event-specific object/string)
40+
- `payload_version` must equal `controlplane.PayloadVersion`.
41+
- Version mismatch is treated as a hard incompatibility and must fail fast.
42+
43+
## Error Contract
44+
45+
TUI consumes standard JSON-RPC errors and gateway extended error codes from
46+
`protocol.JSONRPCError.Data.GatewayCode`.
47+
48+
Primary gateway codes used for UI mapping:
49+
50+
- `invalid_frame`
51+
- `invalid_action`
52+
- `invalid_multimodal_payload`
53+
- `missing_required_field`
54+
- `unsupported_action`
55+
- `internal_error`
56+
- `timeout`
57+
- `unsafe_path`
58+
- `unauthorized`
59+
- `access_denied`
60+
- `resource_not_found`
61+
62+
## Non-Goals
63+
64+
- No multi-version payload decoding.
65+
- No alias method fallback.
66+
- No legacy field fallback in event payload.

docs/repository-design.md

Lines changed: 642 additions & 53 deletions
Large diffs are not rendered by default.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ require (
8080
github.com/muesli/termenv v0.16.0 // indirect
8181
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
8282
github.com/ncruces/go-strftime v1.0.0 // indirect
83+
github.com/odvcencio/gotreesitter v0.15.3 // indirect
8384
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
8485
github.com/prometheus/client_model v0.6.2 // indirect
8586
github.com/prometheus/common v0.66.1 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
191191
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
192192
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
193193
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
194+
github.com/odvcencio/gotreesitter v0.15.3 h1:bcSIEMyRrDaFIZw2zwM8cNR03VX6y8CbXFxVzfFSGX0=
195+
github.com/odvcencio/gotreesitter v0.15.3/go.mod h1:ccYZsDUmAJQAtliLsNHT33F3X4AN7f/Z6JGiPNZoEzY=
196+
github.com/openai/openai-go/v3 v3.30.0 h1:T8VkhqAm6BuvxwpVG+Aw+H4TcYIsbj9nqytjpWcE/aU=
197+
github.com/openai/openai-go/v3 v3.30.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
194198
github.com/openai/openai-go/v3 v3.32.0 h1:aHp/3wkX1W6jB8zTtf9xV0aK0qPFSVDqS7AHmlJ4hXs=
195199
github.com/openai/openai-go/v3 v3.32.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
196200
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=

internal/app/bootstrap.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ import (
2121
"neo-code/internal/provider/builtin"
2222
providercatalog "neo-code/internal/provider/catalog"
2323
providertypes "neo-code/internal/provider/types"
24+
"neo-code/internal/repository"
2425
agentruntime "neo-code/internal/runtime"
2526
"neo-code/internal/security"
2627
agentsession "neo-code/internal/session"
2728
"neo-code/internal/skills"
2829
"neo-code/internal/tools"
2930
"neo-code/internal/tools/bash"
31+
"neo-code/internal/tools/codebase"
3032
diagnosetool "neo-code/internal/tools/diagnose"
3133
"neo-code/internal/tools/filesystem"
3234
"neo-code/internal/tools/mcp"
@@ -460,6 +462,10 @@ func buildToolRegistry(cfg config.Config) (*tools.Registry, func() error, error)
460462
}))
461463
toolRegistry.Register(todo.New())
462464
toolRegistry.Register(spawnsubagent.New())
465+
repoSvc := repository.NewService()
466+
toolRegistry.Register(codebase.NewRead(repoSvc, cfg.Workdir))
467+
toolRegistry.Register(codebase.NewSearchText(repoSvc, cfg.Workdir))
468+
toolRegistry.Register(codebase.NewSearchSymbol(repoSvc, cfg.Workdir))
463469
mcpRegistry, err := BuildMCPRegistry(cfg)
464470
if err != nil {
465471
return nil, nil, err

internal/checkpoint/bash_capture_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,15 @@ func TestSourceFilesInWorkdir_HandlesEmptyWorkdir(t *testing.T) {
220220
t.Fatalf("expected nil with empty workdir, got %v", got)
221221
}
222222
}
223+
224+
func equalStringSlice(a, b []string) bool {
225+
if len(a) != len(b) {
226+
return false
227+
}
228+
for i := range a {
229+
if a[i] != b[i] {
230+
return false
231+
}
232+
}
233+
return true
234+
}

internal/checkpoint/per_edit_snapshot.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"time"
1818

1919
"github.com/pmezard/go-difflib/difflib"
20+
21+
"neo-code/internal/repository"
2022
)
2123

2224
const (
@@ -446,20 +448,17 @@ func (s *PerEditSnapshotStore) HasPending() bool {
446448
return len(s.pending) > 0
447449
}
448450

449-
// FileChangeKind 表示两个 checkpoint 之间单个 path 的变更类别
450-
type FileChangeKind string
451+
// FileChangeKind 是 repository.FileChangeKind 的别名,保留以维持向后兼容
452+
type FileChangeKind = repository.FileChangeKind
451453

452454
const (
453-
FileChangeAdded FileChangeKind = "added"
454-
FileChangeDeleted FileChangeKind = "deleted"
455-
FileChangeModified FileChangeKind = "modified"
455+
FileChangeAdded = repository.FileChangeAdded
456+
FileChangeDeleted = repository.FileChangeDeleted
457+
FileChangeModified = repository.FileChangeModified
456458
)
457459

458-
// FileChangeEntry 描述端到端 diff 中单个 path 的变更。
459-
type FileChangeEntry struct {
460-
Path string
461-
Kind FileChangeKind
462-
}
460+
// FileChangeEntry 是 repository.FileChangeEntry 的别名,保留以维持向后兼容。
461+
type FileChangeEntry = repository.FileChangeEntry
463462

464463
// ChangedFiles 端到端比较两个 checkpoint,返回 path → 变更类别的列表(按 path 字典序)。
465464
// 不返回内容差异,仅用于 UI 分组(添加/删除/修改)。完整 patch 仍由 Diff 生成。

internal/cli/gateway_commands.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type gatewayCommandOptions struct {
5959

6060
MetricsEnabled bool
6161
MetricsEnabledOverridden bool
62-
SkipIPC bool
62+
SkipIPC bool
6363
}
6464

6565
// defaultNewAuthManager 创建默认网关认证器,并把具体持久化实现收敛在 CLI 装配层内部。

internal/cli/gateway_runtime_bridge_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ func TestGatewayRuntimePortBridgeRuntimeMethods(t *testing.T) {
591591
SavedRatio: 0.5,
592592
TriggerMode: "manual",
593593
TranscriptID: "tx-1",
594-
TranscriptPath: "/tmp/tx-1.md",
594+
TranscriptPath: "/tmp/tx-subagent.md",
595595
},
596596
systemToolRes: tools.ToolResult{
597597
ToolCallID: "call-system-1",
@@ -2627,3 +2627,22 @@ func TestGatewayRuntimePortBridgeDeleteMCPServerSuccess(t *testing.T) {
26272627
t.Fatalf("servers = %+v, want [srv-2]", cfgMgr.cfg.Tools.MCP.Servers)
26282628
}
26292629
}
2630+
2631+
func TestDefaultBuildGatewayRuntimePortListSessionsWithoutExplicitWorkdir(t *testing.T) {
2632+
home := t.TempDir()
2633+
t.Setenv("HOME", home)
2634+
t.Setenv("USERPROFILE", home)
2635+
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
2636+
2637+
port, cleanup, err := defaultBuildGatewayRuntimePort(context.Background(), "")
2638+
if err != nil {
2639+
t.Fatalf("defaultBuildGatewayRuntimePort() error = %v", err)
2640+
}
2641+
if cleanup != nil {
2642+
defer func() { _ = cleanup() }()
2643+
}
2644+
2645+
if _, err := port.ListSessions(context.Background()); err != nil {
2646+
t.Fatalf("ListSessions() with empty cli workdir should succeed, got %v", err)
2647+
}
2648+
}

0 commit comments

Comments
 (0)