orch-code 0.1.3 → 0.1.4

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 CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## v0.1.4 - 2026-04-03
6
+
7
+ - feat: add live probe mode for doctor
5
8
  ## v0.1.3 - 2026-04-03
6
9
 
7
10
  - ci: harden npm install and release flow
package/README.md CHANGED
@@ -333,8 +333,11 @@ Validate runtime readiness:
333
333
 
334
334
  ```bash
335
335
  ./orch doctor
336
+ ./orch doctor --probe
336
337
  ```
337
338
 
339
+ `--probe` runs a small live OpenAI chat check, which is useful for validating account-mode OAuth auth beyond local token shape checks.
340
+
338
341
  Generate a structured plan only:
339
342
 
340
343
  ```bash
package/cmd/doctor.go CHANGED
@@ -9,10 +9,13 @@ import (
9
9
 
10
10
  "github.com/furkanbeydemir/orch/internal/auth"
11
11
  "github.com/furkanbeydemir/orch/internal/config"
12
+ "github.com/furkanbeydemir/orch/internal/providers"
12
13
  "github.com/furkanbeydemir/orch/internal/providers/openai"
13
14
  "github.com/spf13/cobra"
14
15
  )
15
16
 
17
+ var doctorProbeFlag bool
18
+
16
19
  var doctorCmd = &cobra.Command{
17
20
  Use: "doctor",
18
21
  Short: "Validate Orch runtime readiness",
@@ -21,6 +24,7 @@ var doctorCmd = &cobra.Command{
21
24
 
22
25
  func init() {
23
26
  rootCmd.AddCommand(doctorCmd)
27
+ doctorCmd.Flags().BoolVar(&doctorProbeFlag, "probe", false, "Run a live provider chat probe")
24
28
  }
25
29
 
26
30
  func runDoctor(cmd *cobra.Command, args []string) error {
@@ -85,8 +89,8 @@ func runDoctor(cmd *cobra.Command, args []string) error {
85
89
  })
86
90
 
87
91
  checks = append(checks, check{
88
- name: "openai.account_refresh",
89
- ok: authMode != "account" || accountToken != "" || !storedAccount || storedRefresh || (storedCred != nil && storedCred.ExpiresAt.IsZero()) || time.Now().UTC().Before(storedCred.ExpiresAt),
92
+ name: "openai.account_refresh",
93
+ ok: authMode != "account" || accountToken != "" || !storedAccount || storedRefresh || (storedCred != nil && storedCred.ExpiresAt.IsZero()) || time.Now().UTC().Before(storedCred.ExpiresAt),
90
94
  detail: fmt.Sprintf("required_when_expired=%t", authMode == "account" && accountToken == ""),
91
95
  })
92
96
 
@@ -95,30 +99,27 @@ func runDoctor(cmd *cobra.Command, args []string) error {
95
99
  checks = append(checks, check{name: "openai.model.reviewer", ok: strings.TrimSpace(cfg.Provider.OpenAI.Models.Reviewer) != "", detail: cfg.Provider.OpenAI.Models.Reviewer})
96
100
 
97
101
  if cfg.Provider.Flags.OpenAIEnabled && defaultProvider == "openai" {
98
- client := openai.New(cfg.Provider.OpenAI)
99
- client.SetTokenResolver(func(ctx context.Context) (string, error) {
100
- _ = ctx
101
- if authMode == "api_key" {
102
- if storedCred != nil && strings.TrimSpace(storedCred.Key) != "" {
103
- return strings.TrimSpace(storedCred.Key), nil
104
- }
105
- return "", nil
106
- }
107
- resolved, resolveErr := auth.ResolveAccountAccessToken(cwd, "openai")
108
- if resolveErr != nil {
109
- return "", resolveErr
110
- }
111
- return resolved, nil
112
- })
102
+ client := newDoctorOpenAIClient(cwd, cfg.Provider.OpenAI, authMode, storedCred)
113
103
 
114
104
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
115
105
  defer cancel()
116
106
  validateErr := client.Validate(ctx)
117
107
  checks = append(checks, check{
118
- name: "openai.auth",
108
+ name: "openai.auth.local",
119
109
  ok: validateErr == nil,
120
110
  detail: errDetail(validateErr, "ok"),
121
111
  })
112
+
113
+ if doctorProbeFlag {
114
+ probeCtx, probeCancel := context.WithTimeout(context.Background(), doctorProbeTimeout(cfg.Provider.OpenAI.TimeoutSeconds))
115
+ defer probeCancel()
116
+ probeErr := runOpenAIProbe(probeCtx, client, cfg.Provider.OpenAI.Models.Coder)
117
+ checks = append(checks, check{
118
+ name: "openai.auth.probe",
119
+ ok: probeErr == nil,
120
+ detail: errDetail(probeErr, "ok"),
121
+ })
122
+ }
122
123
  }
123
124
 
124
125
  failed := 0
@@ -147,3 +148,44 @@ func errDetail(err error, fallback string) string {
147
148
  }
148
149
  return err.Error()
149
150
  }
151
+
152
+ func newDoctorOpenAIClient(cwd string, cfg config.OpenAIProviderConfig, authMode string, storedCred *auth.Credential) *openai.Client {
153
+ client := openai.New(cfg)
154
+ client.SetTokenResolver(func(ctx context.Context) (string, error) {
155
+ _ = ctx
156
+ if authMode == "api_key" {
157
+ if storedCred != nil && strings.TrimSpace(storedCred.Key) != "" {
158
+ return strings.TrimSpace(storedCred.Key), nil
159
+ }
160
+ return "", nil
161
+ }
162
+ resolved, resolveErr := auth.ResolveAccountAccessToken(cwd, "openai")
163
+ if resolveErr != nil {
164
+ return "", resolveErr
165
+ }
166
+ return resolved, nil
167
+ })
168
+ return client
169
+ }
170
+
171
+ func runOpenAIProbe(ctx context.Context, client *openai.Client, model string) error {
172
+ _, err := client.Chat(ctx, providers.ChatRequest{
173
+ Role: providers.RoleCoder,
174
+ Model: strings.TrimSpace(model),
175
+ SystemPrompt: "Reply with OK only.",
176
+ UserPrompt: "ping",
177
+ ReasoningEffort: "low",
178
+ })
179
+ return err
180
+ }
181
+
182
+ func doctorProbeTimeout(timeoutSeconds int) time.Duration {
183
+ if timeoutSeconds <= 0 {
184
+ return 20 * time.Second
185
+ }
186
+ timeout := time.Duration(timeoutSeconds) * time.Second
187
+ if timeout > 20*time.Second {
188
+ return 20 * time.Second
189
+ }
190
+ return timeout
191
+ }
@@ -1,7 +1,11 @@
1
1
  package cmd
2
2
 
3
3
  import (
4
+ "encoding/base64"
4
5
  "encoding/json"
6
+ "fmt"
7
+ "net/http"
8
+ "net/http/httptest"
5
9
  "strings"
6
10
  "testing"
7
11
 
@@ -56,6 +60,76 @@ func TestDoctorFailsWithoutAPIKey(t *testing.T) {
56
60
  }
57
61
  }
58
62
 
63
+ func TestDoctorProbeAccountModeSucceeds(t *testing.T) {
64
+ repoRoot := t.TempDir()
65
+ t.Chdir(repoRoot)
66
+
67
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68
+ if r.URL.Path != "/codex/responses" {
69
+ t.Fatalf("unexpected path: %s", r.URL.Path)
70
+ }
71
+ if got := r.Header.Get("ChatGPT-Account-Id"); got != "acc-123" {
72
+ t.Fatalf("unexpected account header: %s", got)
73
+ }
74
+ w.Header().Set("Content-Type", "application/json")
75
+ _, _ = w.Write([]byte(`{"output_text":"OK","status":"completed","usage":{"input_tokens":1,"output_tokens":1,"total_tokens":2}}`))
76
+ }))
77
+ defer server.Close()
78
+
79
+ if err := config.EnsureOrchDir(repoRoot); err != nil {
80
+ t.Fatalf("ensure orch dir: %v", err)
81
+ }
82
+ cfg := config.DefaultConfig()
83
+ cfg.Provider.OpenAI.AuthMode = "account"
84
+ cfg.Provider.OpenAI.BaseURL = server.URL
85
+ cfg.Provider.OpenAI.TimeoutSeconds = 5
86
+ if err := config.Save(repoRoot, cfg); err != nil {
87
+ t.Fatalf("save config: %v", err)
88
+ }
89
+
90
+ t.Setenv("OPENAI_ACCOUNT_TOKEN", testDoctorAccountToken("acc-123"))
91
+ doctorProbeFlag = true
92
+ defer func() { doctorProbeFlag = false }()
93
+
94
+ if err := runDoctor(nil, nil); err != nil {
95
+ t.Fatalf("expected doctor probe to succeed: %v", err)
96
+ }
97
+ }
98
+
99
+ func TestDoctorProbeAccountModeFailsWhenProviderRejects(t *testing.T) {
100
+ repoRoot := t.TempDir()
101
+ t.Chdir(repoRoot)
102
+
103
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
104
+ w.WriteHeader(http.StatusUnauthorized)
105
+ _, _ = w.Write([]byte(`{"error":"unauthorized"}`))
106
+ }))
107
+ defer server.Close()
108
+
109
+ if err := config.EnsureOrchDir(repoRoot); err != nil {
110
+ t.Fatalf("ensure orch dir: %v", err)
111
+ }
112
+ cfg := config.DefaultConfig()
113
+ cfg.Provider.OpenAI.AuthMode = "account"
114
+ cfg.Provider.OpenAI.BaseURL = server.URL
115
+ cfg.Provider.OpenAI.TimeoutSeconds = 5
116
+ if err := config.Save(repoRoot, cfg); err != nil {
117
+ t.Fatalf("save config: %v", err)
118
+ }
119
+
120
+ t.Setenv("OPENAI_ACCOUNT_TOKEN", testDoctorAccountToken("acc-123"))
121
+ doctorProbeFlag = true
122
+ defer func() { doctorProbeFlag = false }()
123
+
124
+ err := runDoctor(nil, nil)
125
+ if err == nil {
126
+ t.Fatalf("expected doctor probe failure")
127
+ }
128
+ if !strings.Contains(err.Error(), "doctor failed") {
129
+ t.Fatalf("unexpected doctor error: %v", err)
130
+ }
131
+ }
132
+
59
133
  func TestProviderListJSONOutput(t *testing.T) {
60
134
  repoRoot := t.TempDir()
61
135
  t.Chdir(repoRoot)
@@ -89,3 +163,10 @@ func TestProviderListJSONOutput(t *testing.T) {
89
163
  t.Fatalf("expected openai in all providers, got: %#v", all)
90
164
  }
91
165
  }
166
+
167
+ func testDoctorAccountToken(accountID string) string {
168
+ header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"none"}`))
169
+ payload := fmt.Sprintf(`{"https://api.openai.com/auth":{"chatgpt_account_id":"%s"}}`, accountID)
170
+ body := base64.RawURLEncoding.EncodeToString([]byte(payload))
171
+ return header + "." + body + ".sig"
172
+ }
package/cmd/version.go CHANGED
@@ -1,4 +1,4 @@
1
1
  package cmd
2
2
 
3
3
  // version is overridden in release builds via GoReleaser ldflags.
4
- var version = "0.1.3"
4
+ var version = "0.1.4"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orch-code",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Local-first control plane for deterministic AI coding",
5
5
  "license": "MIT",
6
6
  "bin": {