@jslee124/forge 0.3.0 → 0.3.1
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/dist/index.js +1177 -90
- package/package.json +2 -1
- package/resources/docs/en/ARCHITECTURE.md +519 -0
- package/resources/docs/en/AUTHENTICATION.md +224 -0
- package/resources/docs/en/CLI_UI.md +266 -0
- package/resources/docs/en/CONFIGURATION.md +263 -0
- package/resources/docs/en/CONTEXT_MANAGEMENT.md +692 -0
- package/resources/docs/en/GETTING_STARTED.md +241 -0
- package/resources/docs/en/PLUGINS.md +622 -0
- package/resources/docs/en/PRODUCT.md +157 -0
- package/resources/docs/en/PROJECT_CONTEXT.md +225 -0
- package/resources/docs/en/RELEASING.md +94 -0
- package/resources/docs/en/SECURITY.md +272 -0
- package/resources/docs/en/SESSIONS.md +134 -0
- package/resources/docs/en/TROUBLESHOOTING.md +256 -0
- package/resources/docs/index.json +24334 -0
- package/resources/docs/zh-CN/ARCHITECTURE.md +174 -0
- package/resources/docs/zh-CN/AUTHENTICATION.md +96 -0
- package/resources/docs/zh-CN/CLI_UI.md +112 -0
- package/resources/docs/zh-CN/CONFIGURATION.md +221 -0
- package/resources/docs/zh-CN/CONTEXT_MANAGEMENT.md +200 -0
- package/resources/docs/zh-CN/GETTING_STARTED.md +193 -0
- package/resources/docs/zh-CN/PLUGINS.md +286 -0
- package/resources/docs/zh-CN/PRODUCT.md +86 -0
- package/resources/docs/zh-CN/PROJECT_CONTEXT.md +130 -0
- package/resources/docs/zh-CN/RELEASING.md +86 -0
- package/resources/docs/zh-CN/SECURITY.md +92 -0
- package/resources/docs/zh-CN/SESSIONS.md +69 -0
- package/resources/docs/zh-CN/TROUBLESHOOTING.md +185 -0
- package/resources/skills/forge-plugin-creator/SKILL.md +70 -0
- package/resources/skills/forge-plugin-creator/references/plugin-api.md +36 -0
- package/resources/skills/forge-plugin-creator/templates/index.mjs +30 -0
- package/resources/skills/forge-plugin-creator/templates/plugin.json +8 -0
- package/resources/skills/forge-plugin-creator/templates/plugin.test-template.ts +14 -0
- package/resources/skills/forge-product-help/SKILL.md +16 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Authentication Model
|
|
2
|
+
|
|
3
|
+
简体中文 · Documentation index
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Forge supports DeepSeek and OpenAI API-key authentication through
|
|
8
|
+
`DEEPSEEK_API_KEY` and `OPENAI_API_KEY`, plus ChatGPT subscription
|
|
9
|
+
authentication through the official Codex App Server.
|
|
10
|
+
User-scoped provider routes additionally support an explicitly selected bearer
|
|
11
|
+
credential or no authentication for local/self-hosted endpoints.
|
|
12
|
+
Forge presents the login command and browser/device-code instructions, while
|
|
13
|
+
Codex owns OAuth, credential persistence, refresh, and revocation.
|
|
14
|
+
|
|
15
|
+
## Supported and planned methods
|
|
16
|
+
|
|
17
|
+
| Method | Intended use | Status |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| DeepSeek API key | Local development and automation | Implemented |
|
|
20
|
+
| OpenAI API key | Optional usage-based OpenAI API access | Implemented |
|
|
21
|
+
| Provider route bearer key | OpenAI-compatible gateways | Implemented |
|
|
22
|
+
| Provider route without authentication | Local Ollama/vLLM-style servers | Implemented |
|
|
23
|
+
| Sign in with ChatGPT | OpenAI subscription access through Codex App Server | Implemented |
|
|
24
|
+
| Codex access token | Trusted enterprise automation | Deferred |
|
|
25
|
+
|
|
26
|
+
DeepSeek's official API uses `https://api.deepseek.com` and the initial adapter
|
|
27
|
+
uses the official AI SDK provider package. The model ID remains configurable
|
|
28
|
+
because provider model names have a different lifecycle from the Forge release.
|
|
29
|
+
|
|
30
|
+
Official DeepSeek references:
|
|
31
|
+
|
|
32
|
+
- [DeepSeek API model documentation](https://api-docs.deepseek.com/quick_start/pricing/)
|
|
33
|
+
- [AI SDK DeepSeek provider](https://ai-sdk.dev/providers/ai-sdk-providers/deepseek)
|
|
34
|
+
|
|
35
|
+
OpenAI now documents Codex App Server as the integration protocol for embedding
|
|
36
|
+
Codex into a product. Its account surface supports managed ChatGPT browser and
|
|
37
|
+
device-code login. Forge uses that public surface rather than copying OpenCode's
|
|
38
|
+
OAuth client ID or rewriting requests to an undocumented ChatGPT endpoint.
|
|
39
|
+
|
|
40
|
+
Official reference:
|
|
41
|
+
[OpenAI Codex App Server](https://developers.openai.com/codex/app-server)
|
|
42
|
+
|
|
43
|
+
## Architectural boundary
|
|
44
|
+
|
|
45
|
+
The two execution paths have different ownership boundaries:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
Forge Engine: Forge Runtime -> Model Adapter -> DeepSeek or OpenAI API
|
|
49
|
+
|
|
50
|
+
Codex Engine: Forge CLI -> Codex App Server -> ChatGPT subscription
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The Codex Engine is not wrapped as a Forge `ModelAdapter`: App Server owns a
|
|
54
|
+
complete agent runtime, including turns, tools, sandboxing, approvals, and
|
|
55
|
+
history. Treating it as a raw model transport would obscure which runtime made
|
|
56
|
+
security and execution decisions.
|
|
57
|
+
|
|
58
|
+
The provider-neutral authentication manager resolves API keys from an explicit
|
|
59
|
+
environment variable first, then from Forge's owner-readable user credential
|
|
60
|
+
store. Missing credentials produce an actionable error without printing the
|
|
61
|
+
key or a stack trace. Keys are never copied into Forge configuration, prompts,
|
|
62
|
+
traces, plugin events, or repository files.
|
|
63
|
+
|
|
64
|
+
## OpenAI-compatible provider routes
|
|
65
|
+
|
|
66
|
+
Routes are declared under `providers` in `$FORGE_HOME/config.json`. They name a
|
|
67
|
+
wire protocol, canonical endpoint, explicit authentication mode, and model
|
|
68
|
+
profiles. Repository `.forge/config.json` files may not define routes because
|
|
69
|
+
that would let untrusted project content decide where a user credential is
|
|
70
|
+
sent.
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"schemaVersion": 1,
|
|
75
|
+
"providers": {
|
|
76
|
+
"my-gateway": {
|
|
77
|
+
"api": "openai-responses",
|
|
78
|
+
"baseUrl": "https://gateway.example/openai/v1",
|
|
79
|
+
"auth": { "type": "bearer", "apiKeyEnv": "GATEWAY_API_KEY" },
|
|
80
|
+
"models": [
|
|
81
|
+
{
|
|
82
|
+
"id": "reasoning-model",
|
|
83
|
+
"contextWindow": 128000,
|
|
84
|
+
"maxOutputTokens": 8192,
|
|
85
|
+
"reasoningGears": { "none": "none", "high": "high" }
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`auth.type` is mandatory. `bearer` reads the declared variable, or derives
|
|
94
|
+
`FORGE_<ROUTE>_API_KEY`, before consulting Forge's stored credential. `none`
|
|
95
|
+
does not read or send any API key. Stored route credentials are bound to the
|
|
96
|
+
canonical `baseUrl`; after an endpoint change Forge refuses the old key until a
|
|
97
|
+
new one is saved.
|
|
98
|
+
|
|
99
|
+
Remote endpoints require HTTPS. Plain HTTP is accepted only for loopback hosts.
|
|
100
|
+
URLs containing credentials, query strings, or fragments are rejected. Model
|
|
101
|
+
discovery does not follow redirects, remains bounded to 4 MiB and 15 seconds,
|
|
102
|
+
and is optional because model IDs can be entered manually.
|
|
103
|
+
|
|
104
|
+
Forge treats an omitted reasoning setting as **provider default**, which is not
|
|
105
|
+
the same as disabling reasoning. Each `reasoningGears` entry maps a Forge UI
|
|
106
|
+
level to the exact wire value sent to the provider, so an explicit
|
|
107
|
+
`"none": "none"` is required when the endpoint supports disabling reasoning.
|
|
108
|
+
Legacy version-1 `null` mappings are read as their canonical key to avoid
|
|
109
|
+
silently turning `none` into provider default.
|
|
110
|
+
|
|
111
|
+
Model discovery also accepts bounded optional reasoning metadata such as
|
|
112
|
+
`reasoning_efforts`, `supported_reasoning_efforts`, or
|
|
113
|
+
`capabilities.reasoning.efforts`. These fields are non-standard extensions:
|
|
114
|
+
when they are absent Forge reports capabilities as unknown and keeps provider
|
|
115
|
+
defaults instead of guessing or issuing paid probe requests. The setup screen
|
|
116
|
+
prefills advertised levels and lets the user override them before saving.
|
|
117
|
+
|
|
118
|
+
An OpenAI API key is optional and is billed independently of ChatGPT. A ChatGPT
|
|
119
|
+
Plus, Pro, Business, or other subscription does not cause Forge to select the
|
|
120
|
+
API path. Users who only want subscription access should keep
|
|
121
|
+
`model.provider = "deepseek"` or use `forge codex`; they do not need to create
|
|
122
|
+
or export `OPENAI_API_KEY`.
|
|
123
|
+
|
|
124
|
+
## Compatibility requirements
|
|
125
|
+
|
|
126
|
+
The selected App Server integration satisfies these requirements:
|
|
127
|
+
|
|
128
|
+
- The flow is publicly documented for embedding Codex into a product
|
|
129
|
+
- Forge never supplies or copies an OAuth client identity
|
|
130
|
+
- Codex performs token exchange, refresh, revocation, and account selection
|
|
131
|
+
- The user-facing description accurately distinguishes subscription access from
|
|
132
|
+
usage-based API access
|
|
133
|
+
|
|
134
|
+
Forge must not:
|
|
135
|
+
|
|
136
|
+
- Copy another application's client secret or identity
|
|
137
|
+
- Treat reverse-engineered endpoints as a permanent API contract
|
|
138
|
+
- Ask users to paste access or refresh tokens into chat
|
|
139
|
+
- Read, import, or modify `~/.codex/auth.json` directly
|
|
140
|
+
- Store credentials inside the current repository
|
|
141
|
+
|
|
142
|
+
## Credential storage
|
|
143
|
+
|
|
144
|
+
The interactive `/login` flow can persist API keys in
|
|
145
|
+
`$FORGE_HOME/auth.json`. The directory is mode `0700`, the file is mode `0600`,
|
|
146
|
+
updates are atomic, and environment variables take precedence. This is a
|
|
147
|
+
plaintext filesystem-protected fallback rather than an OS keychain. ChatGPT
|
|
148
|
+
subscription credentials remain owned entirely by Codex App Server.
|
|
149
|
+
The interactive `/logout` picker lists authenticated providers, removes the
|
|
150
|
+
selected stored API credential, or asks Codex App Server to sign out the
|
|
151
|
+
ChatGPT subscription. A logged-out third-party route remains visible as signed
|
|
152
|
+
out in `/login`, where it can be authenticated again. The route management
|
|
153
|
+
screen has a separate confirmed **Remove provider** action that deletes the
|
|
154
|
+
route, its models, and its stored credential. It reports any provider
|
|
155
|
+
environment variable that remains active; Forge cannot unset a variable in the
|
|
156
|
+
parent shell.
|
|
157
|
+
|
|
158
|
+
The current runtime lookup order is:
|
|
159
|
+
|
|
160
|
+
1. The provider's explicit or conventional environment variable
|
|
161
|
+
2. `$FORGE_HOME/auth.json`, outside the project with owner-only permissions
|
|
162
|
+
|
|
163
|
+
An operating-system credential store would be preferable to plaintext file
|
|
164
|
+
storage and remains a future improvement. Environment variables remain the
|
|
165
|
+
recommended injection mechanism for automation.
|
|
166
|
+
|
|
167
|
+
Credentials must be excluded from prompts, run events, JSONL traces, plugin
|
|
168
|
+
events, telemetry, and ordinary error messages.
|
|
169
|
+
|
|
170
|
+
## Refresh and concurrency
|
|
171
|
+
|
|
172
|
+
Codex App Server owns subscription token refresh and persistence. Forge never
|
|
173
|
+
receives OAuth access or refresh tokens. The App Server may use the Codex
|
|
174
|
+
credential-store configuration shared with other local Codex clients.
|
|
175
|
+
|
|
176
|
+
Credential updates must be atomic. A failed refresh must not destroy the last
|
|
177
|
+
known credential before the error is handled.
|
|
178
|
+
|
|
179
|
+
## Commands
|
|
180
|
+
|
|
181
|
+
The CLI exposes:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
forge auth login openai
|
|
185
|
+
forge auth status openai
|
|
186
|
+
forge auth status openai-api
|
|
187
|
+
forge auth logout openai
|
|
188
|
+
forge models list --provider openai
|
|
189
|
+
forge codex "Inspect this repository" --model <id> --reasoning-effort <effort>
|
|
190
|
+
forge run "Inspect this repository" --provider openai --model gpt-5.4-mini --reasoning-effort low
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Use `forge auth login openai --method device-code` for a headless login. Forge
|
|
194
|
+
prints the official verification URL and code and waits for App Server's
|
|
195
|
+
completion notification. Browser callback validation and PKCE are owned by
|
|
196
|
+
Codex. Cancelling Forge asks App Server to cancel the pending login.
|
|
197
|
+
|
|
198
|
+
Sign-in URLs are much wider than a terminal window. Terminals that linkify
|
|
199
|
+
plain text do so one display line at a time, so a wrapped URL would stay
|
|
200
|
+
clickable only up to its first wrap. Forge therefore emits the URL as a single
|
|
201
|
+
OSC 8 hyperlink on terminals known to support it, including VS Code, Ghostty,
|
|
202
|
+
WezTerm, iTerm2, Kitty, Windows Terminal, Konsole, and VTE 5000 or newer. The
|
|
203
|
+
visible label remains the complete address, so an unsupported terminal still
|
|
204
|
+
shows a copyable URL. Redirected output, `TERM=dumb`, and `NO_COLOR` always
|
|
205
|
+
produce the bare URL. Set `FORCE_HYPERLINK=1` to opt an unrecognized terminal
|
|
206
|
+
in, or `FORCE_HYPERLINK=0` to opt out.
|
|
207
|
+
|
|
208
|
+
`forge auth logout openai` operates on the shared Codex account and can sign
|
|
209
|
+
other local Codex clients out. Forge does not claim that these are Forge-owned
|
|
210
|
+
credentials.
|
|
211
|
+
|
|
212
|
+
`forge auth status openai-api` reports whether an environment or stored
|
|
213
|
+
credential is active; it never validates the key with a paid request.
|
|
214
|
+
`forge auth login openai-api` directs the user to the masked interactive
|
|
215
|
+
`/login` flow or `OPENAI_API_KEY` because the plain subcommand never reads a
|
|
216
|
+
secret from command arguments. The interactive `/model` picker discovers the current Codex catalog
|
|
217
|
+
and also shows native API adapters without duplicating models by reasoning
|
|
218
|
+
effort. The separate `/effort` picker and Shift+Tab shortcut use the selected
|
|
219
|
+
model's supported levels. Forge persists these ordinary
|
|
220
|
+
engine/provider/model/reasoning settings under `$FORGE_HOME/config.json`;
|
|
221
|
+
credentials remain separate in the environment, `$FORGE_HOME/auth.json`, or
|
|
222
|
+
Codex-owned storage.
|
|
223
|
+
Selecting a ChatGPT entry routes subsequent interactive prompts through Codex
|
|
224
|
+
Engine.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Interactive CLI UI
|
|
2
|
+
|
|
3
|
+
简体中文 · Documentation index
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
This document defines the implemented Milestone 4.6 terminal experience. Ink
|
|
8
|
+
now provides the interactive renderer while the non-interactive commands and
|
|
9
|
+
Forge-owned runtime retain their existing boundaries.
|
|
10
|
+
|
|
11
|
+
## Goals
|
|
12
|
+
|
|
13
|
+
The interactive CLI should make common coding-agent actions discoverable
|
|
14
|
+
without moving the agent loop, tools, or policy decisions out of Forge core.
|
|
15
|
+
The terminal UI should provide:
|
|
16
|
+
|
|
17
|
+
- A multi-line prompt editor
|
|
18
|
+
- Discoverable slash-command completion
|
|
19
|
+
- Workspace-file completion with `@`
|
|
20
|
+
- Clear streamed reasoning, answers, tool activity, and run state
|
|
21
|
+
- Terminal-native Markdown for headings, lists, quotes, links, inline code,
|
|
22
|
+
emphasis, and fenced code blocks
|
|
23
|
+
- A readable diff review before file-write approval
|
|
24
|
+
- Keyboard-only operation with predictable cancellation
|
|
25
|
+
- A startup capability summary inside the blue Forge frame
|
|
26
|
+
|
|
27
|
+
Ink is the renderer for the interactive CLI. Commander remains
|
|
28
|
+
responsible for process-level command parsing. React and Ink must stay inside
|
|
29
|
+
`apps/cli`; `@forge/core` must remain independent of the terminal framework.
|
|
30
|
+
Forge uses full-frame Ink updates so terminal reflow during a resize cannot
|
|
31
|
+
leave stale rows from the previous width.
|
|
32
|
+
|
|
33
|
+
## Startup capability summary
|
|
34
|
+
|
|
35
|
+
Before the first prompt, the blue Forge frame lists enabled user plugins,
|
|
36
|
+
project plugins with `trusted` or `untrusted, skipped` state, and discovered
|
|
37
|
+
built-in, user, and project Skills. Compact category labels follow Pi's resource-list pattern while
|
|
38
|
+
preserving Forge's explicit trust semantics.
|
|
39
|
+
|
|
40
|
+
Startup detection reads plugin manifests and Skill metadata only. It must not
|
|
41
|
+
import a project plugin merely to display its name. Actual plugin activation
|
|
42
|
+
remains part of a native Forge Engine run. Native runs advertise bounded Skill
|
|
43
|
+
metadata and lazily load matching Skills; explicit `$skill-name` remains an
|
|
44
|
+
override. The Codex Engine owns a separate tool
|
|
45
|
+
runtime, so the listing describes Forge resources rather than Codex tools.
|
|
46
|
+
|
|
47
|
+
`/plugins` opens a metadata-only review panel. It shows each project plugin's
|
|
48
|
+
version, capabilities, and current workspace trust state. Trust requires a
|
|
49
|
+
second `y` confirmation after an in-process privilege warning; revocation is
|
|
50
|
+
available from the same panel. A successful decision refreshes the blue startup
|
|
51
|
+
frame immediately, while plugin activation remains deferred until the next
|
|
52
|
+
native Forge Engine task.
|
|
53
|
+
|
|
54
|
+
## Interaction states
|
|
55
|
+
|
|
56
|
+
The UI owns an explicit state machine so menus, streaming output, and approval
|
|
57
|
+
prompts never compete for the same terminal input:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
editing
|
|
61
|
+
|-- "/" --> selecting_command -- execute/insert --> editing
|
|
62
|
+
|-- "@" --> selecting_file ---- insert ---------> editing
|
|
63
|
+
`-- submit --> running --> awaiting_approval --> running --> editing
|
|
64
|
+
`---------------- completed ------------^
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Only the active state consumes keyboard input. Ctrl+C closes an open completion
|
|
68
|
+
menu first, cancels an active run second, and preserves the existing deliberate
|
|
69
|
+
session-exit behavior when Forge is otherwise idle.
|
|
70
|
+
|
|
71
|
+
## Prompt editor
|
|
72
|
+
|
|
73
|
+
- Enter submits a non-empty prompt when no completion or approval menu owns the
|
|
74
|
+
key.
|
|
75
|
+
- Shift+Enter inserts a newline without submitting. Terminal integrations that
|
|
76
|
+
encode it as Meta+Enter (`ESC+Enter`) are treated the same way.
|
|
77
|
+
- Because some legacy terminals do not distinguish Shift+Enter from Enter,
|
|
78
|
+
Ctrl+J also inserts a newline as a portable fallback. The input footer should
|
|
79
|
+
advertise the shortcut that is available.
|
|
80
|
+
- Forge directly enables the enhanced keyboard protocol in known-compatible
|
|
81
|
+
terminals such as VS Code and Ghostty, avoiding a startup capability query
|
|
82
|
+
that some terminals echo as input. Older or unknown terminals continue to
|
|
83
|
+
use Ctrl+J or Meta+Enter as fallbacks.
|
|
84
|
+
- The editor preserves newlines exactly when constructing the user message.
|
|
85
|
+
- Left/right movement, backspace, delete, Home/End, paste, Unicode text, and
|
|
86
|
+
terminal resize must not corrupt the buffer or display.
|
|
87
|
+
- Up/down keys navigate an open completion menu. When no menu is open, they may
|
|
88
|
+
later be used for prompt history; history is not required for Milestone 4.6.
|
|
89
|
+
- Shift+Tab cycles through the active model's supported thinking-effort levels.
|
|
90
|
+
|
|
91
|
+
## Slash-command completion
|
|
92
|
+
|
|
93
|
+
Typing `/` as the first non-whitespace character opens a list of available
|
|
94
|
+
commands. Additional characters filter the list by command name.
|
|
95
|
+
|
|
96
|
+
Each command is defined once with its name, description, and handler. The same
|
|
97
|
+
registry drives completion and `/help`, preventing the two surfaces from
|
|
98
|
+
drifting. The registry contains `/help`, `/new`, `/clear`, `/context`,
|
|
99
|
+
`/compact`, `/plugins`, `/login`, `/logout`, `/model`, `/delete-model`,
|
|
100
|
+
`/effort`, `/resume`, and `/exit`.
|
|
101
|
+
`/plugins` opens the project-plugin trust review described above. `/model`
|
|
102
|
+
opens a keyboard picker, discovers current
|
|
103
|
+
ChatGPT/Codex models, includes configured API providers, and saves one model
|
|
104
|
+
entry without multiplying it by effort level. `/effort` opens a separate
|
|
105
|
+
model-specific effort picker; `/effort <level>` sets a supported level directly.
|
|
106
|
+
Both selections are atomically saved to user configuration.
|
|
107
|
+
`/logout` lists authenticated providers and removes a selected stored
|
|
108
|
+
credential without pretending to unset a parent-shell environment variable.
|
|
109
|
+
`/delete-model` shows only user-configured provider models, requires
|
|
110
|
+
confirmation, retains the provider route and credential, and refuses to delete
|
|
111
|
+
the active model until another is selected.
|
|
112
|
+
The `/login` picker always lists configured third-party routes, including their
|
|
113
|
+
full Base URL, API type, authentication mode, status, and model count. Selecting
|
|
114
|
+
a route opens provider management: add or restore a model, delete one configured
|
|
115
|
+
model, log out when a stored credential is active, or remove the provider.
|
|
116
|
+
Deleting a model keeps the route and credential so it can be added again
|
|
117
|
+
immediately. Logout leaves a signed-out
|
|
118
|
+
route visible. Remove provider is a separate confirmed action that deletes the
|
|
119
|
+
route, its models, and its stored credential; it refuses to remove the active
|
|
120
|
+
provider and cannot unset a parent-shell environment variable.
|
|
121
|
+
|
|
122
|
+
Model setup prefills reasoning levels only when `/models` returns recognized,
|
|
123
|
+
bounded capability metadata. It labels the source as discovered or manual;
|
|
124
|
+
with no metadata, Enter keeps the provider default. Forge does not infer that
|
|
125
|
+
missing metadata means a non-reasoning model and does not make paid capability
|
|
126
|
+
probe requests. Provider management separately labels the protocol-supported
|
|
127
|
+
tool surface and the provider's end-to-end agent loop as unverified.
|
|
128
|
+
|
|
129
|
+
- Up/Down changes the highlighted command.
|
|
130
|
+
- Enter executes the highlighted command.
|
|
131
|
+
- Tab completes its name without executing it.
|
|
132
|
+
- Escape closes the menu without changing the input.
|
|
133
|
+
- A slash elsewhere in ordinary prose or a filesystem path does not open the
|
|
134
|
+
command menu.
|
|
135
|
+
|
|
136
|
+
## Workspace-file mentions
|
|
137
|
+
|
|
138
|
+
Typing `@` opens a bounded list of files beneath the selected workspace. Text
|
|
139
|
+
after the active `@` token filters candidates by relative path using
|
|
140
|
+
case-insensitive fuzzy matching.
|
|
141
|
+
|
|
142
|
+
- Candidate paths are workspace-relative and use `/` as the display separator.
|
|
143
|
+
- `.git`, dependency directories, build output, and paths outside the canonical
|
|
144
|
+
workspace are excluded.
|
|
145
|
+
- The menu shows at most 10 ranked candidates and indicates when more matches
|
|
146
|
+
exist.
|
|
147
|
+
- Up/Down changes the highlighted file; Enter or Tab inserts it; Escape closes
|
|
148
|
+
the menu.
|
|
149
|
+
- Selecting a file inserts a visible mention while retaining a structured
|
|
150
|
+
`{ path }` reference in editor state. Paths with spaces must not depend on
|
|
151
|
+
reparsing the rendered prompt.
|
|
152
|
+
- File discovery is read-only, bounded, cancellable, and does not invoke the
|
|
153
|
+
model or run an external shell command for every keystroke.
|
|
154
|
+
|
|
155
|
+
On submission, Forge sends the user's text plus an explicit list of referenced
|
|
156
|
+
workspace-relative paths to the model. Selecting a mention does not
|
|
157
|
+
automatically inject the complete file contents. The model can use `read_file`
|
|
158
|
+
through the normal tool, policy, and trace path when it needs the contents.
|
|
159
|
+
|
|
160
|
+
## Pasted image attachments
|
|
161
|
+
|
|
162
|
+
When a bracketed paste or terminal drag-and-drop begins with an absolute image
|
|
163
|
+
path, Forge removes that path from the text and shows a compact
|
|
164
|
+
`[Image #N] filename` attachment. This supports OS and terminal clipboard
|
|
165
|
+
helpers that materialize screenshots beneath temporary directories such as
|
|
166
|
+
`/var/.../T/otty-paste/`. Quoted paths, shell-escaped spaces, and `file://`
|
|
167
|
+
paths are accepted. Backspace removes the most recent attachment when the text
|
|
168
|
+
composer is empty.
|
|
169
|
+
|
|
170
|
+
This is an explicit user action, so the attachment may be outside the selected
|
|
171
|
+
workspace. Forge does not scan arbitrary prompt prose for image paths, and this
|
|
172
|
+
does not widen the workspace boundary used by model file tools. The active
|
|
173
|
+
model must support image input.
|
|
174
|
+
|
|
175
|
+
Example logical message:
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
Please explain the cancellation behavior.
|
|
179
|
+
|
|
180
|
+
Referenced files:
|
|
181
|
+
- apps/cli/src/session.ts
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Diff review
|
|
185
|
+
|
|
186
|
+
File-write approval must present the exact proposed change in a dedicated,
|
|
187
|
+
readable panel before the user decides. The renderer should show:
|
|
188
|
+
|
|
189
|
+
- Operation and path: create, modify, or delete
|
|
190
|
+
- A compact file summary and changed-line counts
|
|
191
|
+
- Unified diff hunks with old/new line numbers
|
|
192
|
+
- Added lines in green with `+`, removed lines in red with `-`, and subdued
|
|
193
|
+
context lines
|
|
194
|
+
- Clear file and hunk headers that remain understandable without color
|
|
195
|
+
- Syntax highlighting when the file type is known, without allowing syntax
|
|
196
|
+
color to obscure addition/removal meaning
|
|
197
|
+
- An explicit truncation message when a safety display limit is reached
|
|
198
|
+
|
|
199
|
+
Approval must never rely on color alone. `--no-color`, a non-color terminal,
|
|
200
|
+
and common color-vision deficiencies must retain the `+`/`-`, headers, and line
|
|
201
|
+
number cues. A diff that exceeds the safe review limit remains unapprovable;
|
|
202
|
+
visual truncation must not silently turn partial content into approval for an
|
|
203
|
+
unseen patch.
|
|
204
|
+
|
|
205
|
+
The approval controls are visible next to the diff and describe their scope.
|
|
206
|
+
For example, approving the first workspace write covers later workspace writes
|
|
207
|
+
only in the current run, while process commands continue to require separate
|
|
208
|
+
approval.
|
|
209
|
+
|
|
210
|
+
Process-command approval uses the same dedicated panel. It renders a
|
|
211
|
+
shell-readable `$ command` line followed by clearly labelled working-directory
|
|
212
|
+
and timeout rows; these details must not appear as detached transcript text.
|
|
213
|
+
|
|
214
|
+
Network-tool approval also uses the dedicated panel. It shows the registered
|
|
215
|
+
tool name and the bounded URL or search query that will be sent externally.
|
|
216
|
+
Plugin-specific secrets and arbitrary input objects are never rendered as an
|
|
217
|
+
approval preview.
|
|
218
|
+
|
|
219
|
+
## Sign-in panel
|
|
220
|
+
|
|
221
|
+
A pending browser sign-in is a dedicated panel, not transcript text. The Codex
|
|
222
|
+
auth surface reports the URL as a structured `login` output event carrying the
|
|
223
|
+
address as its own field, so the UI never re-parses it out of a text chunk.
|
|
224
|
+
|
|
225
|
+
Sign-in URLs are several times wider than a terminal window. The panel wraps
|
|
226
|
+
the address in a single OSC 8 hyperlink, which keeps the whole URL clickable
|
|
227
|
+
after Ink wraps it; terminals that linkify plain text do so one display line at
|
|
228
|
+
a time and would otherwise leave only the first wrapped line clickable. The
|
|
229
|
+
visible label stays the complete address so an unsupported terminal still shows
|
|
230
|
+
a copyable URL, and escape sequences must not count toward display width or the
|
|
231
|
+
panel border would fall out of alignment.
|
|
232
|
+
|
|
233
|
+
## Rendering boundaries
|
|
234
|
+
|
|
235
|
+
The CLI may turn runtime events into components such as message blocks, tool
|
|
236
|
+
activity rows, status indicators, and diff panels. It must not infer execution
|
|
237
|
+
success from presentation state or parse previously rendered terminal text.
|
|
238
|
+
|
|
239
|
+
Core events and approval requests remain the source of truth. Interactive and
|
|
240
|
+
non-interactive commands continue to share the same Forge-owned runtime,
|
|
241
|
+
workspace validation, policy gateway, and tool execution behavior.
|
|
242
|
+
|
|
243
|
+
Model Markdown is rendered as a bounded terminal-native subset rather than
|
|
244
|
+
HTML. The renderer must tolerate incomplete constructs while text is streaming
|
|
245
|
+
and strip model-supplied ANSI control sequences before styling output.
|
|
246
|
+
|
|
247
|
+
## Test strategy
|
|
248
|
+
|
|
249
|
+
Milestone 4.6 should include deterministic tests for:
|
|
250
|
+
|
|
251
|
+
- Slash-menu opening, filtering, navigation, selection, and dismissal
|
|
252
|
+
- File candidate filtering, ignored directories, result limits, spaces, and
|
|
253
|
+
prevention of workspace escape
|
|
254
|
+
- Structured file mentions and the exact model message assembled from them
|
|
255
|
+
- Enter submission versus Shift+Enter, Meta+Enter, and Ctrl+J newline insertion
|
|
256
|
+
- Multi-line editing, paste, Unicode, resize, and cancellation
|
|
257
|
+
- State transitions between editing, completion, running, and approval
|
|
258
|
+
- Startup plugin/Skill listing, trust labels, and metadata-only discovery
|
|
259
|
+
- Diff rendering for create and modify operations, multiple hunks, no-color
|
|
260
|
+
output, truncation, and approval scope
|
|
261
|
+
|
|
262
|
+
No UI test may require a paid model request. Component tests should consume
|
|
263
|
+
scripted input and events, while a small pseudo-terminal integration test proves
|
|
264
|
+
the supported key sequences in representative terminals.
|
|
265
|
+
|
|
266
|
+
`/resources` shows every discovered Skill's source, description, automatic or explicit-only status, shadowing, and bounded diagnostics. It does not import plugin entries or eagerly load Skill bodies. `/plugins` remains limited to executable plugins and points users to `/resources` for Skills.
|