@globant/coda-linux-arm64 1.3.0 → 1.5.0

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.
Files changed (47) hide show
  1. package/assets/agents/coda-help.md +25 -12
  2. package/assets/agents/council.md +11 -0
  3. package/assets/agents/reviewer.md +14 -0
  4. package/assets/agents/side.md +15 -0
  5. package/assets/docs/add-mcp-server-skill.md +137 -0
  6. package/assets/docs/agents.md +1 -1
  7. package/assets/docs/cli-reference.md +40 -4
  8. package/assets/docs/cli-vs-batch.md +2 -0
  9. package/assets/docs/config-json.md +71 -57
  10. package/assets/docs/config-reference.md +99 -48
  11. package/assets/docs/configuration.md +33 -18
  12. package/assets/docs/connect-provider.md +34 -31
  13. package/assets/docs/extensions.md +25 -28
  14. package/assets/docs/faq.md +47 -15
  15. package/assets/docs/glossary.md +8 -8
  16. package/assets/docs/guide-automate.md +6 -2
  17. package/assets/docs/guide-changes.md +4 -4
  18. package/assets/docs/guide-collaborate.md +8 -8
  19. package/assets/docs/guide-extend.md +32 -5
  20. package/assets/docs/hooks.md +33 -69
  21. package/assets/docs/how-it-works.md +3 -3
  22. package/assets/docs/index.md +8 -7
  23. package/assets/docs/installation.md +9 -9
  24. package/assets/docs/logging.md +1 -1
  25. package/assets/docs/overview.md +9 -8
  26. package/assets/docs/permissions.md +35 -16
  27. package/assets/docs/quickstart.md +9 -5
  28. package/assets/docs/sessions.md +6 -2
  29. package/assets/docs/shortcuts.md +53 -3
  30. package/assets/docs/tools-reference.md +21 -10
  31. package/assets/docs/workflows.md +2 -1
  32. package/assets/output-styles/attention-kind.md +50 -0
  33. package/assets/output-styles/concise.md +46 -0
  34. package/assets/output-styles/default.md +4 -0
  35. package/assets/output-styles/explanatory.md +84 -0
  36. package/assets/output-styles/learning.md +103 -0
  37. package/assets/output-styles/plain.md +39 -0
  38. package/assets/output-styles/proactive.md +52 -0
  39. package/assets/output-styles/rundown.md +23 -0
  40. package/assets/output-styles/spartan.md +26 -0
  41. package/assets/output-styles/visual.md +96 -0
  42. package/assets/skills/configure-mcp/SKILL.md +281 -0
  43. package/assets/skills/create-hook/SKILL.md +5 -5
  44. package/assets/skills/init-rules/SKILL.md +78 -26
  45. package/coda +2 -2
  46. package/lib/opentui/parser.worker.js +15 -14
  47. package/package.json +1 -1
@@ -0,0 +1,281 @@
1
+ ---
2
+ name: configure-mcp
3
+ description: Configure g-coda's MCP client to connect to an MCP server from a Git URL, remote HTTP endpoint, or npm/pip package, at project or global scope. Use when the user asks to add, register, configure, install, or set up an MCP server or MCP client. e.g. "add the playwright MCP server", "configure an MCP server from this URL", "install this MCP tool globally".
4
+ ---
5
+
6
+ # Configure MCP
7
+
8
+ Configure g-coda's MCP client to connect to an MCP server by registering the server entry in the correct config file at the user-chosen scope. The input can be a Git URL, remote HTTP endpoint, or npm/pip package. Reject inputs from which no valid transport (`command` or `url`) can be derived — write nothing in that case.
9
+
10
+ ---
11
+
12
+ ## Golden Rule
13
+
14
+ **Never overwrite existing server entries.** Always merge your new entry into the existing `mcpServers` object. If a server with the same name already exists, confirm with the user before replacing it.
15
+
16
+ **Never hardcode secrets.** Tokens, API keys, and credentials must use `${VAR}` or `${VAR:-default}` interpolation — never inline values. A default is literal text up to the first `}`; it cannot contain another `${…}` reference (no `${A:-${B}}`) or a line break.
17
+
18
+ ---
19
+
20
+ ## Step 1: Determine Scope
21
+
22
+ Ask the user which scope they want if not specified:
23
+
24
+ | Scope | Write to | When to use |
25
+ |---|---|---|
26
+ | **Project** | `<cwd>/.coda/mcp.json` | Only this repo; shared via version control |
27
+ | **Global** | `~/.coda/mcp.json` | All projects on this machine; personal |
28
+
29
+ - `<cwd>` = `process.cwd()` where g-coda is running, not the nearest `.git` root.
30
+ - If unsure, **default to project scope**.
31
+ - A project entry always wins over a global entry with the same server name.
32
+
33
+ **Target file:** always write to `mcp.json` (top-level `mcpServers` key).
34
+
35
+ ---
36
+
37
+ ## Step 2: Detect Input Type and Validate
38
+
39
+ ### 2a. Remote HTTP endpoint
40
+
41
+ Input is `https://…` or `http://…` pointing to a live MCP endpoint (Streamable HTTP transport).
42
+
43
+ Example entry — replace the URL, token variable name, and header values with the real ones:
44
+
45
+ ```jsonc
46
+ {
47
+ "url": "https://api.example.com/mcp",
48
+ "authorizationToken": "Bearer ${API_TOKEN}",
49
+ "headers": { "X-Custom": "${CUSTOM_HEADER}" },
50
+ "timeout": 120
51
+ }
52
+ ```
53
+
54
+ > ⚠️ Make sure no tokens or secrets are exposed — always use `${VAR}` interpolation for credentials.
55
+
56
+ Transport: `url` → HTTP. Do **not** set `command`.
57
+
58
+ ### 2b. npm/pip package or CLI tool
59
+
60
+ Input is a package name, `npx`/`uvx` invocation, or local binary path (stdio transport).
61
+
62
+ Example entry — replace the package name and env var names with the real ones:
63
+
64
+ ```jsonc
65
+ {
66
+ "command": "npx",
67
+ "args": ["-y", "@scope/mcp-package@latest"],
68
+ "env": { "API_KEY": "${MY_API_KEY}" }
69
+ }
70
+ ```
71
+
72
+ > ⚠️ Make sure no tokens or secrets are exposed — always use `${VAR}` interpolation for credentials.
73
+
74
+ Common patterns: `npx -y <pkg>`, `uvx <pkg>`, `node /path/to/server.js`, `/path/to/binary`.
75
+
76
+ Transport: `command` → stdio. Do **not** set `url`.
77
+
78
+ ### 2c. Git URL
79
+
80
+ Most MCP server repositories support **multiple installation methods** (e.g. `npx`, `uvx`, Docker, a remote HTTP endpoint, or a local build). Do not assume — read the repo's documentation first, then ask the user which method they prefer.
81
+
82
+ Steps:
83
+
84
+ 1. **Clone temporarily** to read the docs:
85
+ - Project scope: `<cwd>/.coda/tmp/<name>/`
86
+ - Global scope: `~/.coda/tmp/<name>/`
87
+ - Command: `git clone --depth 1 <url> <tmp-dir>`
88
+ 2. **Read the README and any MCP-specific docs** to identify all available installation methods.
89
+ 3. **Ask the user** which method they prefer — present the options you found. Common options:
90
+ - `npx -y <pkg>` or `uvx <pkg>` (no local build needed — preferred when available)
91
+ - Remote HTTP endpoint (if the project exposes one)
92
+ - Local build (`npm install && npm run build`, entry via `node dist/index.js`)
93
+ 4. **Derive the entry** using the chosen method (see sections 2a and 2b for the corresponding entry shape).
94
+ 5. **Write the config entry** to `mcp.json`.
95
+ 6. **Delete the temporary clone** (`<tmp-dir>`) — it is no longer needed once the config entry is written.
96
+
97
+ > If the chosen method does not require the cloned directory at runtime (e.g. `npx`/`uvx`/HTTP), the tmp directory is always safe to remove. If the user explicitly chooses a local-build method and the runtime depends on the clone, move the directory to its final location (`<cwd>/.coda/mcp-servers/<name>/` or `~/.coda/mcp-servers/<name>/`) instead of deleting it, and tell the user.
98
+
99
+ ### 2d. Rejection — no derivable transport
100
+
101
+ If you **cannot** determine either a `command` or a `url` from the input, **do not write anything**. Respond:
102
+
103
+ > "I couldn't determine a valid MCP server transport from what you provided. An MCP server needs either a runnable command (for stdio transport) or an HTTP URL (for Streamable HTTP transport). Please share the server's npm package name, a Git URL, a binary path, or its HTTP endpoint."
104
+
105
+ ---
106
+
107
+ ## Step 3: Build the Server Entry
108
+
109
+ A valid entry has **exactly one** of `command` (stdio) or `url` (http) — never both, never neither.
110
+
111
+ | Field | Transport | Description |
112
+ |---|---|---|
113
+ | `command` | stdio | Executable to run as a subprocess |
114
+ | `args` | stdio | Arguments for the subprocess |
115
+ | `cwd` | stdio | Working directory for the subprocess |
116
+ | `url` | http | MCP server HTTP endpoint |
117
+ | `authorizationToken` | http | Shorthand `Authorization` header; supports `${VAR}` |
118
+ | `oauth` | http | `true` for an OAuth 2.1 server; the user signs in with `coda mcp login <name>` |
119
+ | `oauthClientId` | http | Pre-registered OAuth client id, for servers without dynamic client registration (Glob.AI: `mcp`); requires `oauth: true` |
120
+ | `headers` | http | Extra request headers; string values support `${VAR}` |
121
+ | `timeout` | both | Timeout in seconds for each request to the server; unset means 60 s for MCP requests and 30 s for OAuth sign-in requests |
122
+ | `env` | both | Environment variables; supports `${VAR}` and `${VAR:-default}` |
123
+ | `disabled` | both | `true` to skip at load time (default: `false`) |
124
+
125
+ Secrets in `env`, `headers`, and `authorizationToken` are resolved from `~/.coda/.secrets`, project `.env`, and `process.env` at load time. Never put raw credentials in the config.
126
+
127
+ Choose a descriptive, kebab-case server name (e.g., `playwright`, `github`, `my-internal-api`).
128
+
129
+ ---
130
+
131
+ ## Step 4: Non-Destructive Merge into Config
132
+
133
+ ### Writing to `mcp.json` (preferred)
134
+
135
+ ```jsonc
136
+ // <cwd>/.coda/mcp.json (project) or ~/.coda/mcp.json (global)
137
+ {
138
+ "mcpServers": {
139
+ "<server-name>": { /* entry fields */ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ Merge steps:
145
+ 1. Read the existing file, or start with `{ "mcpServers": {} }` if absent.
146
+ 2. Check whether `mcpServers["<server-name>"]` exists — confirm with the user before replacing.
147
+ 3. Add or replace only the target key; preserve all other entries.
148
+ 4. Write the file back.
149
+
150
+ ---
151
+
152
+ ## Step 5: Verify and Notify
153
+
154
+ After writing:
155
+
156
+ 1. Show the user exactly what was written (entry + file path).
157
+ 2. Confirm the file is valid JSON (no trailing commas, balanced braces).
158
+ 3. Remind the user how to activate the change:
159
+
160
+ > **MCP changes are not picked up by `/skills refresh`.** To activate:
161
+ > - Run `/mcp` → select **Reload MCP servers**, or
162
+ > - Restart g-coda.
163
+
164
+ 4. For cloned Git repos, delete the temporary directory (`<cwd>/.coda/tmp/<name>/` or `~/.coda/tmp/<name>/`) once the config entry has been written — unless the user chose a local-build method that requires the directory at runtime, in which case it was already moved to its final location as part of step 2c.
165
+
166
+ ---
167
+
168
+ ## Examples
169
+
170
+ ### Example 1 — npm package, project scope
171
+
172
+ **User:** "Add the Playwright MCP server to this project."
173
+
174
+ Written to `<cwd>/.coda/mcp.json`:
175
+ ```json
176
+ {
177
+ "mcpServers": {
178
+ "playwright": {
179
+ "command": "npx",
180
+ "args": ["-y", "@playwright/mcp@latest"]
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ **Response:** Added `playwright` to `.coda/mcp.json`. Run `/mcp` → Reload MCP servers to activate it.
187
+
188
+ ---
189
+
190
+ ### Example 2 — HTTP endpoint, global scope, with auth
191
+
192
+ **User:** "Set up the GitHub MCP server globally. My token is in `GITHUB_TOKEN`."
193
+
194
+ Written to `~/.coda/mcp.json`:
195
+ ```json
196
+ {
197
+ "mcpServers": {
198
+ "github": {
199
+ "url": "https://api.githubcopilot.com/mcp/",
200
+ "authorizationToken": "Bearer ${GITHUB_TOKEN}",
201
+ "timeout": 120
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
207
+ **Response:** Added `github` to `~/.coda/mcp.json`. Make sure `GITHUB_TOKEN` is set in your environment or `~/.coda/.secrets`. Run `/mcp` → Reload MCP servers to activate it.
208
+
209
+ ---
210
+
211
+ ### Example 3 — Git URL, project scope
212
+
213
+ **User:** "Install from https://github.com/example/my-mcp-server into this project."
214
+
215
+ Steps:
216
+ 1. Clone to `<cwd>/.coda/tmp/my-mcp-server/` with `git clone --depth 1 <url> <tmp-dir>`.
217
+ 2. Read `README.md` — it documents two options: `npx -y @example/my-mcp-server` or a local build.
218
+ 3. Ask the user: *"The repository supports `npx` (no local build needed) or a local build. Which do you prefer?"*
219
+ 4. User chooses `npx`. Derive the entry (section 2b).
220
+ 5. Write config, then delete `<cwd>/.coda/tmp/my-mcp-server/`.
221
+
222
+ Written to `<cwd>/.coda/mcp.json`:
223
+ ```json
224
+ {
225
+ "mcpServers": {
226
+ "my-mcp-server": {
227
+ "command": "npx",
228
+ "args": ["-y", "@example/my-mcp-server@latest"]
229
+ }
230
+ }
231
+ }
232
+ ```
233
+
234
+ **Response:** Added `my-mcp-server` to `.coda/mcp.json` and removed the temporary clone. Run `/mcp` → Reload MCP servers to activate it.
235
+
236
+ ---
237
+
238
+ ### Example 4 — Rejection
239
+
240
+ **User:** "Add `my-special-tool` as an MCP server."
241
+
242
+ No URL or command is derivable from the name alone.
243
+
244
+ **Response:** I couldn't determine a valid MCP server transport for `my-special-tool`. Please share the npm package name, a Git URL, a binary path, or the HTTP endpoint.
245
+
246
+ ---
247
+
248
+ ## Error Handling
249
+
250
+ | Situation | Action |
251
+ |---|---|
252
+ | File exists but is invalid JSON | Report the parse error and path; do not overwrite. Ask user to fix manually. |
253
+ | Server name already exists | Show the existing entry; ask user to confirm replacement. |
254
+ | No transport derivable | Reject with a clear explanation (Step 2d). Do not write anything. |
255
+ | Git clone fails | Report the error and path; do not write a config entry. Clean up any partial tmp directory. |
256
+ | No installation method found in repo docs | Tell the user no clear method was found; ask them to provide the command or URL directly. |
257
+ | Secret value unclear | Ask which env var name to use; never guess a value. |
258
+
259
+ ---
260
+
261
+ ## Instructions for the Agent
262
+
263
+ 1. **Clarify scope first** — ask project vs global if not stated. Default to project.
264
+ 2. **Derive the entry** — HTTP URL → `url` field; package/git/binary → `command` field. For Git URLs, clone to a tmp dir, read the docs, ask the user which method to use, then delete the tmp dir. If no transport is derivable, reject immediately (do not write).
265
+ 3. **Choose the config file** — always use `mcp.json` (top-level `mcpServers` key).
266
+ 4. **Merge non-destructively** — read the existing file first; preserve all other entries.
267
+ 5. **No inline secrets** — always use `${VAR}` notation; tell the user which env var to set.
268
+ 6. **Validate JSON** — ensure the written file is syntactically valid.
269
+ 7. **Remind about reload** — MCP changes need `/mcp` → Reload MCP servers or a restart. `/skills refresh` does NOT reload MCP.
270
+ 8. **Show the result** — always display the final entry and the full path of the file written.
271
+
272
+ ---
273
+
274
+ ## Deliverables
275
+
276
+ When done, provide:
277
+
278
+ 1. The exact file path written (e.g., `<cwd>/.coda/mcp.json` or `~/.coda/mcp.json`).
279
+ 2. The server entry that was added (JSON block).
280
+ 3. Any env vars the user needs to set (if secrets are involved).
281
+ 4. The activation command: `/mcp` → Reload MCP servers (or restart g-coda).
@@ -65,7 +65,7 @@ Spawns a shell command via `sh -c`. g-coda writes a JSON payload to the command'
65
65
  | `command` | string | required | Shell command to run |
66
66
  | `args` | string[] | — | Extra arguments appended to the command |
67
67
  | `timeout` | number | 600 | Seconds before the hook is killed |
68
- | `shell` | `"bash"` \| `"powershell"` | system default | Shell to use |
68
+ | `shell` | `"sh"` \| `"bash"` \| `"powershell"` \| `"auto"` | `"auto"` (POSIX-first: `sh` on macOS/Linux, Git Bash on Windows, PowerShell as a last resort) | Shell to use |
69
69
  | `statusMessage` | string | — | Spinner text shown while the hook runs |
70
70
  | `if` | string | — | Conditional expression (tool events only) |
71
71
 
@@ -154,15 +154,15 @@ Every hook receives a JSON object on stdin. All events include these base fields
154
154
  ```json
155
155
  {
156
156
  "session_id": "abc123",
157
- "transcript_path": "/path/to/transcript.json",
157
+ "transcript_path": "",
158
158
  "cwd": "/path/to/project",
159
159
  "hook_event_name": "PreToolUse",
160
- "permission_mode": "default",
161
- "agent_id": "...",
162
- "agent_type": "main"
160
+ "cli_version": "0.4.2"
163
161
  }
164
162
  ```
165
163
 
164
+ `transcript_path` is always an empty string (Coda persists conversations to a database, not a transcript file; the field exists for wire-compatibility). `cli_version` is the running Coda version — also available to command hooks as the `CODA_VERSION` env var, which is cheaper than parsing stdin in hot-path hooks. `permission_mode`, `agent_id`, and `agent_type` are reserved fields that are currently never populated — do not depend on them.
165
+
166
166
  Additional fields by event:
167
167
 
168
168
  **Tool events** (`PreToolUse`, `PostToolUse`, `PostToolUseFailure`):
@@ -17,6 +17,8 @@ This skill assumes the session is running in **auto mode** (unattended/hands-off
17
17
 
18
18
  If the user is not in auto mode, still proceed — the rules are valid in any mode — but note that in `default`/`read-only` mode many commands already require approval, so `deny`/`ask` rules matter most.
19
19
 
20
+ Keeping auto after the rules land: on a fresh install the silent `auto` default applies to the current session only, and only while no `permissions` block exists. Saving a rule never changes the starting mode, so once the first rule is written, later sessions start in `default`. If the user wants to keep starting in auto, ask them, and if they agree propose it explicitly: `propose_policy` with `{ "op": "set-mode", "mode": "auto", "scope": "global" }`. It is a loosen, so the user sees and approves exactly that change. Project scope can only lower the mode, so raising it must be global. Headless, a loosen is auto-refused: report the `set-mode` suggestion instead. If the user already chose a mode, don't propose one.
21
+
20
22
  ## Interactive vs. headless
21
23
 
22
24
  - **Interactive:** follow every step, using `ask_user` to confirm choices.
@@ -24,7 +26,25 @@ If the user is not in auto mode, still proceed — the rules are valid in any mo
24
26
 
25
27
  ---
26
28
 
27
- ## Step 1 — Explore the project
29
+ ## Step 1 — Detect the OS and shell dialect
30
+
31
+ CODA's command rules are **dialect-scoped**: a `Bash(...)` rule only matches when the session's resolved shell routes to the POSIX extractor, and a `PowerShell(...)` rule only matches when it routes to the PowerShell extractor. A bash rule is **inert on Windows PowerShell**, and a PowerShell rule is inert on macOS/Linux. So you MUST author rules for the dialect the user actually runs, or the rules silently match nothing.
32
+
33
+ Detect the platform first, then pick the dialect:
34
+
35
+ - Run a quick probe to learn the OS/shell. Prefer a portable check, e.g. `uname -s` (prints `Darwin`/`Linux` on macOS/Linux; fails or is absent on native Windows), or inspect the environment. On Windows, `$PSVersionTable` / `echo $env:OS` confirm PowerShell.
36
+ - Map the result to a dialect:
37
+ - **macOS (`Darwin`) or Linux → `bash` dialect.** Author `Bash(...)` rules. (This also covers WSL and any POSIX shell — bash/zsh/sh/dash/ksh/ash.)
38
+ - **Windows PowerShell / pwsh → `pwsh` dialect.** Author `PowerShell(...)` rules (the tags `PowerShell(...)`, `powershell(...)`, and `pwsh(...)` are all equivalent).
39
+ - If the probe is ambiguous, ask the user with `ask_user` which shell they run (`bash`/`zsh` vs `PowerShell`) before proposing any command rules.
40
+
41
+ State the detected dialect back to the user, e.g. *"You're on macOS, so I'll propose `Bash(...)` rules"* or *"You're on Windows PowerShell, so I'll propose `PowerShell(...)` rules"*, and use **that dialect for every command rule** in the steps below. Everywhere this skill shows `Bash(...)`, substitute `PowerShell(...)` when the user is on Windows.
42
+
43
+ > Note: file rules (`Read`/`Edit`/`Write`) and MCP rules (`mcp__server`) are **not** dialect-scoped — they apply on every OS unchanged. Only command rules switch between `Bash(...)` and `PowerShell(...)`.
44
+
45
+ ---
46
+
47
+ ## Step 2 — Explore the project
28
48
 
29
49
  Understand what commands this project legitimately runs so your rules fit reality. Do NOT skip this.
30
50
 
@@ -38,7 +58,9 @@ Search in the ~/.coda/coda.db database for bash commands to get a sense of the c
38
58
 
39
59
  ---
40
60
 
41
- ## Step 2 — Choose how permissive the rules should be
61
+ ## Step 3 — Choose how permissive the rules should be
62
+
63
+ > Use the dialect you detected in Step 1 for every command rule below. The examples show the `Bash(...)` (macOS/Linux) form; on Windows author the `PowerShell(...)` equivalents from the palette further down.
42
64
 
43
65
  Ask the user which posture they want. Use `ask_user`:
44
66
 
@@ -47,32 +69,34 @@ Ask the user which posture they want. Use `ask_user`:
47
69
  > - **Restrictive** — allow only a short, explicit allowlist; `ask` before anything not on it; deny a broad set of destructive/network commands.
48
70
  > - **Balanced** — allow the confirmed dev commands, `ask` for git-writes and network/publish, deny destructive ones.
49
71
 
50
- Then, using what you found in Step 1, propose the concrete rule set and confirm the risky ones with `ask_user` before writing. Typical shapes (adapt to the actual project):
72
+ Then, using what you found in Step 2, propose the concrete rule set and confirm the risky ones with `ask_user` before writing. Typical shapes (adapt to the actual project):
51
73
 
52
- - **Allow** (permissive/balanced): `Bash(pnpm test:*)`, `Bash(pnpm lint:*)`, `Bash(pnpm type-check)`, `Bash(git status)`, `Bash(git log:*)`, `Bash(git diff:*)`.
74
+ - **Allow** (permissive): `Bash(pnpm:*)`, `Bash(git:*)`, `Bash(bunx)`, `Bash(npx)`, `Bash(git:*)`, `Bash(python3:*)`.
53
75
  - **Ask** (guardrails on state-changing / outbound actions): `Bash(git push:*)`, `Bash(git commit:*)`, `Bash(npm publish:*)`, `Bash(curl:*)`.
54
76
  - **Deny** (destructive / dangerous): `Bash(rm:*)`, `Bash(git reset --hard:*)`, `Bash(chmod:*)` — deny whatever the user does not want the agent doing unattended.
55
77
 
56
78
  Rule syntax reminders (this is exactly what `propose_policy` writes):
57
- - `Bash(npm:*)` = any command starting with `npm`; `Bash(git push origin main)` = exact match; `Bash(*)` = any bash command (**too permissive — don't recommend it**, see below); bare `Bash` = the whole tool.
58
- - File tools take globs: `Read(//etc/passwd)` (double slash = absolute), `Edit(src/**)`, `Write(package.json)`.
79
+ - **Command rules are dialect-scoped (Step 1):** `Bash(...)` matches POSIX shells (macOS/Linux); `PowerShell(...)` (also written `pwsh(...)` / `powershell(...)`) matches Windows PowerShell. Author the tag for the detected OS — the other tag is inert.
80
+ - `Bash(npm:*)` = any command starting with `npm`; `Bash(git push origin main)` = exact match; `Bash(*)` = any bash command (**too permissive — don't recommend it**, see below); bare `Bash` = the whole tool. On Windows the same shapes are `PowerShell(npm:*)`, `PowerShell(Remove-Item -Recurse ...)`, etc.
81
+ - PowerShell command names are **case-insensitive** and cmdlet aliases are normalized — `PowerShell(Invoke-Expression:*)` also matches `iex`, and `-Force` matches `-force`. Bash names stay case-sensitive.
82
+ - File tools take globs (dialect-independent): `Read(//etc/passwd)` (double slash = absolute), `Edit(src/**)`, `Write(package.json)`.
59
83
  - MCP: `mcp__filesystem` (whole server) or `mcp__filesystem__read_file` (one tool).
60
84
  - Effects: `allow` (no prompt), `ask` (always prompt, even in auto), `deny` (always block).
61
85
 
62
- Precedence is **deny-first**: `deny` > `ask` > `allow` > mode. Nothing overrides a `deny`, and nothing overrides the catastrophic floor (`rm -rf /`, `sudo`, private-key/credential reads, writes to secret files like `.env` / `.secrets`, etc. — never relaxable, so don't bother proposing rules for those). Note that editing `config.json`, `mcp.json`, or `agents.md` is *not* on that floor: it is allowed as an approval-gated authoring write (see Step 5).
86
+ Precedence is **deny-first**: `deny` > `ask` > `allow` > mode. Nothing overrides a `deny`, and nothing overrides the catastrophic floor (`rm -rf /`, `sudo`, private-key/credential reads, writes to secret files like `.env` / `.secrets`, etc. — never relaxable, so don't bother proposing rules for those). Note that editing `config.json`, `mcp.json`, or `agents.md` is *not* on that floor: it is allowed as an approval-gated authoring write (see Step 6).
63
87
 
64
88
  ### Command-scoped allow rules
65
89
 
66
- IMPORTANT: Do not recommend `Bash(*)` as it won't allow cases that are related to package managers, etc.
67
- Bash(*) doesn't allow every bash command, it isn't the most permissive rule possible.
68
- Each command is broken down and evaluated independently.
90
+ IMPORTANT: Do not recommend `Bash(*)` (or `PowerShell(*)`). A token-less wildcard is deliberately **rejected as a floor-relaxer** by the engine: install-class commands (package managers, package runners, interpreter installs) keep asking even with `Bash(*)` present, so it does not actually give the blanket auto-approval users expect — it just weakens their allowlist without buying the convenience. Each sub-command of a compound command (`a && b`) is also evaluated independently, so a broad allow can never rescue a sub-command a floor or deny rule blocks.
69
91
 
70
- Recommendation: **allow one command family at a time** with `Bash(<tool>:*)`. Each such rule auto-allows only that executable and its arguments, so the agent can run the tool freely while everything else still falls back to `ask`/`deny`/mode.
92
+ Recommendation: **allow one command family at a time** with `Bash(<tool>:*)` (or `PowerShell(<tool>:*)` on Windows). Each such rule auto-allows only that executable and its arguments — and, because it names a binary, it *can* relax that command's install-class floor — while everything else still falls back to `ask`/`deny`/mode.
71
93
 
72
94
  - If a user needs to run **all `pnpm` commands**, the ideal rule is `Bash(pnpm:*)` — not `Bash(*)`.
73
95
  - Same idea per tool: `Bash(bun:*)` for all `bun` commands, `Bash(cargo:*)` for all `cargo` commands, and so on.
74
96
 
75
- Build the allow list from the tools the project actually uses (from Step 1). A palette of common command-scoped rules to draw from:
97
+ Build the allow list from the tools the project actually uses (from Step 2). **Pick the palette for the detected OS** (Step 1) — use the `Bash(...)` palette on macOS/Linux, the `PowerShell(...)` palette on Windows. Do not mix dialects.
98
+
99
+ **macOS / Linux (`bash` dialect):**
76
100
 
77
101
  ```jsonc
78
102
  // ❌ do NOT recommend this:
@@ -107,14 +131,46 @@ Build the allow list from the tools the project actually uses (from Step 1). A p
107
131
  "Bash(sqlite3:*)", "Bash(ffmpeg:*)", "Bash(ffprobe:*)", "Bash(open:*)"
108
132
  ```
109
133
 
134
+ **Windows PowerShell (`pwsh` dialect):** same idea, one command family per rule, but authored with the `PowerShell(...)` tag. Cross-platform tools (git, node, package managers) keep the same executable names; native cmdlets replace the POSIX coreutils. Names are case-insensitive.
135
+
136
+ ```jsonc
137
+ // ❌ do NOT recommend this:
138
+ "PowerShell(*)",
139
+
140
+ // ✅ Recommended: scope to one command family each.
141
+ // Package managers / runtimes (same executables as POSIX):
142
+ "PowerShell(bun:*)", "PowerShell(bunx:*)", "PowerShell(pnpm:*)",
143
+ "PowerShell(npm:*)", "PowerShell(npx:*)", "PowerShell(node:*)",
144
+ "PowerShell(python:*)", "PowerShell(py:*)", "PowerShell(uv:*)", "PowerShell(uvx:*)",
145
+ // Lint / format / build / type-check / test:
146
+ "PowerShell(biome:*)", "PowerShell(tsc:*)", "PowerShell(vitest:*)",
147
+ "PowerShell(jest:*)", "PowerShell(eslint:*)", "PowerShell(prettier:*)",
148
+ // Build / task runners:
149
+ "PowerShell(dotnet:*)", "PowerShell(cargo:*)", "PowerShell(go:*)", "PowerShell(msbuild:*)",
150
+ // Version control:
151
+ "PowerShell(git:*)", "PowerShell(gh:*)",
152
+ // Read-only file / text inspection (cmdlets + common aliases):
153
+ "PowerShell(Get-Content:*)", "PowerShell(Get-ChildItem:*)", "PowerShell(Select-String:*)",
154
+ "PowerShell(Get-Item:*)", "PowerShell(Test-Path:*)", "PowerShell(Measure-Object:*)",
155
+ "PowerShell(Write-Output:*)", "PowerShell(Write-Host:*)", "PowerShell(Sort-Object:*)",
156
+ "PowerShell(Where-Object:*)", "PowerShell(ForEach-Object:*)",
157
+ // Environment / navigation:
158
+ "PowerShell(Set-Location:*)", "PowerShell(Get-Location:*)",
159
+ "PowerShell(Set-Item:*)", "PowerShell(Get-Command:*)",
160
+ // Filesystem-mutating — riskier, usually `ask`/`deny`, not blanket `allow`:
161
+ "PowerShell(New-Item:*)", "PowerShell(Copy-Item:*)", "PowerShell(Move-Item:*)",
162
+ "PowerShell(Remove-Item:*)", "PowerShell(Rename-Item:*)"
163
+ ```
164
+
110
165
  Caveats to relay when proposing these:
111
166
  - These are all **fairly permissive** examples; if the user wants this you should add one rule for each command the user has in their history of commands executed.
112
- - The filesystem-mutating (`rm`, `mv`, `cp`, `chmod`, …) and network (`curl`, `wget`) families change state or reach outbound — prefer `ask` (or `deny` for the destructive ones) over a blanket `allow`, and confirm each with `ask_user` first.
113
- - You can scope tighter than a whole tool: `Bash(pnpm test:*)` allows only `pnpm test …`, `Bash(git log:*)` only `git log …`. Prefer the narrowest rule that still lets the project's real commands run.
167
+ - The filesystem-mutating families (`rm`/`mv`/`cp`/`chmod` on POSIX; `Remove-Item`/`Move-Item`/`Copy-Item` on PowerShell) and network families (`curl`, `wget`, `Invoke-WebRequest`, `Invoke-RestMethod`) change state or reach outbound — prefer `ask` (or `deny` for the destructive ones) over a blanket `allow`, and confirm each with `ask_user` first.
168
+ - You can scope tighter than a whole tool: `Bash(pnpm test:*)` / `PowerShell(git log:*)` allow only that sub-command. Prefer the narrowest rule that still lets the project's real commands run.
169
+ - **A command rule keyed on a bare name can be bypassed by an absolute path**: a `deny Bash(rm:*)` does *not* block `/bin/rm`, and a `deny Bash(curl:*)` does not block `/usr/bin/curl` (same for `PowerShell(...)`). What guarantees protection against `rm -rf /` and friends is the **catastrophic floor**, not user deny rules. Treat `deny`/`ask` command rules as convenience guardrails, not airtight blocks.
114
170
 
115
171
  ---
116
172
 
117
- ## Step 3 — Choose the target scope: project or global
173
+ ## Step 4 — Choose the target scope: project or global
118
174
 
119
175
  Ask the user with `ask_user`:
120
176
 
@@ -128,11 +184,11 @@ Map their choice to the `scope` argument (`"project"` or `"global"`) you pass to
128
184
 
129
185
  ---
130
186
 
131
- ## Step 4 — Apply the rules with `propose_policy`
187
+ ## Step 5 — Apply the rules with `propose_policy`
132
188
 
133
189
  For each rule the user confirmed, call `propose_policy` once:
134
190
 
135
- - Add a rule: `op: "add-rule"`, `rule: "<rule string>"`, `effect: "allow" | "ask" | "deny"`, `scope: "<from Step 3>"`.
191
+ - Add a rule: `op: "add-rule"`, `rule: "<rule string>"`, `effect: "allow" | "ask" | "deny"`, `scope: "<from Step 4>"`.
136
192
  - Change the mode (if needed): `op: "set-mode"`, `mode: "read-only" | "default" | "auto"`, `scope`.
137
193
  - Remove a stale rule: `op: "remove-rule"` with the same `rule` + `effect`.
138
194
 
@@ -145,13 +201,13 @@ Do them in a sensible order (deny rules first, then ask, then allow, then any mo
145
201
 
146
202
  ---
147
203
 
148
- ## Step 5 — Optionally enable the LLM safety-check layer
204
+ ## Step 6 — Optionally enable the LLM safety-check layer
149
205
 
150
206
  Ask the user with `ask_user`:
151
207
 
152
208
  > "Do you want an **LLM safety check** on commands the agent would otherwise run? When enabled, a classifier model reviews commands and can flag/deny risky ones as an extra layer on top of your rules."
153
209
 
154
- This layer is configured under `permissions.llmSafetyCheck` in `config.json`. `propose_policy` does not cover this block, so **edit `config.json` directly** — the same config file they chose in Step 3 (`<repo>/.coda/config.json` for project, `~/.coda/config.json` for global) — merging the block into the existing `permissions` object. Read the file first (create it if absent), then apply the change with `edit`/`write`.
210
+ This layer is configured under `permissions.llmSafetyCheck` in `config.json`. `propose_policy` does not cover this block, so **edit `config.json` directly** — the same config file they chose in Step 4 (`<repo>/.coda/config.json` for project, `~/.coda/config.json` for global) — merging the block into the existing `permissions` object. Read the file first (create it if absent), then apply the change with `edit`/`write`.
155
211
 
156
212
  This is a control-plane authoring write, so CODA will show a **mandatory approval prompt** describing the effect before anything is saved. Tell the user to expect and approve it; if they decline, the block is not written. If you cannot get approval (e.g. headless), fall back to giving them the JSON snippet to paste in by hand.
157
213
 
@@ -165,10 +221,7 @@ The block to add:
165
221
  // Optional: an explicit model list REPLACES the built-in default.
166
222
  // Omit this key to use the shipped default classifier models.
167
223
  // If you want to use another model, just modify the list.
168
- "models": ["openai/gpt-5.4", "openai/gpt-5.4", "anthropic/claude-sonnet-4-6", "anthropic/claude-haiku-4-5"],
169
- // Optional: after this many auto-approvals in an interactive session,
170
- // a one-time nudge suggests adding an explicit allow rule. Default: 10.
171
- "nudgeThreshold": 10
224
+ "models": ["openai/gpt-5.4", "openai/gpt-5.4", "anthropic/claude-sonnet-4-6", "anthropic/claude-haiku-4-5"]
172
225
  }
173
226
  }
174
227
  }
@@ -177,12 +230,11 @@ The block to add:
177
230
  Notes to give the user:
178
231
  - It is **default-off**; an absent block leaves it inert. Set `enabled: true` to turn it on.
179
232
  - If `enabled: true` but `models` is an empty list `[]`, the check is inert (a startup warning fires). Omit `models` to use the built-in default, or list at least one model.
180
- - `nudgeThreshold` must be an integer ≥ 1.
181
- - If they picked **project** scope in Step 3, this belongs in the project config; if **global**, in `~/.coda/config.json`. Since it rides the global→project cascade, a project block overrides the global one.
233
+ - If they picked **project** scope in Step 4, this belongs in the project config; if **global**, in `~/.coda/config.json`. Since it rides the global→project cascade, a project block overrides the global one.
182
234
 
183
235
  ---
184
236
 
185
- ## Step 6 — Wrap up: tell the user to restart
237
+ ## Step 7 — Wrap up: tell the user to restart
186
238
 
187
239
  After applying rules and (optionally) writing the safety-check block, finish with a short summary of what was set, then clearly instruct the user:
188
240
 
package/coda CHANGED
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/coda
3
- size: 131139904 bytes
4
- sha256: 7a0990aca788c9901f641fc02838edc612afc5e922a8fba81ae154ac43f1df26
3
+ size: 108710184 bytes
4
+ sha256: cb9742b992c992bee91b9447b54238b8a6858709f10d0467ceb53eaa1afdd3e9
@@ -18,22 +18,23 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  return cached;
19
19
  }
20
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
21
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
- for (let key of __getOwnPropNames(mod))
23
- if (!__hasOwnProp.call(to, key))
24
- __defProp(to, key, {
25
- get: __accessProp.bind(mod, key),
26
- enumerable: true
27
- });
21
+ const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ if (mod && typeof mod === "object" || typeof mod === "function") {
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ }
28
30
  if (canCache)
29
31
  cache.set(mod, to);
30
32
  return to;
31
33
  };
32
34
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
- var __require = import.meta.require;
34
35
 
35
36
  // ../../node_modules/.pnpm/web-tree-sitter@0.25.10/node_modules/web-tree-sitter/tree-sitter.wasm
36
- var require_tree_sitter = __commonJS((exports, module2) => {
37
+ var require_tree_sitter = __commonJS(function(exports, module2) {
37
38
  module2.exports = Bun.fileURLToPath(new URL("./tree-sitter-3jzf13jk.wasm", import.meta.url));
38
39
  });
39
40
 
@@ -1576,7 +1577,7 @@ var Module2 = (() => {
1576
1577
  throw new Error(response.status + " : " + response.url);
1577
1578
  }, "readAsync");
1578
1579
  }
1579
- } else {}
1580
+ }
1580
1581
  var out = Module["print"] || console.log.bind(console);
1581
1582
  var err = Module["printErr"] || console.error.bind(console);
1582
1583
  Object.assign(Module, moduleOverrides);
@@ -3362,8 +3363,8 @@ class DownloadUtils {
3362
3363
  return "";
3363
3364
  }
3364
3365
  }
3365
- function isBunfsPath(path22) {
3366
- return path22.includes("$bunfs") || /^B:[\\/]~BUN/i.test(path22);
3366
+ function isBunfsPath(path2) {
3367
+ return path2.includes("$bunfs") || /^B:[\\/]~BUN/i.test(path2);
3367
3368
  }
3368
3369
  function getBunfsRootPath() {
3369
3370
  return process.platform === "win32" ? "B:\\~BUN\\root" : "/$bunfs/root";
@@ -3463,8 +3464,8 @@ var stripANSI = bun?.stripANSI ?? stripAnsi;
3463
3464
  var writeFile2 = bun?.write ?? writeFilePortable;
3464
3465
  async function resolveBundledFilePath(loadBundledFile, fallbackPath, metaUrl) {
3465
3466
  if (!bun) {
3466
- const path22 = typeof fallbackPath === "function" ? fallbackPath() : fallbackPath;
3467
- return fileURLToPath(path22 instanceof URL ? path22 : new URL(path22, metaUrl));
3467
+ const path2 = typeof fallbackPath === "function" ? fallbackPath() : fallbackPath;
3468
+ return fileURLToPath(path2 instanceof URL ? path2 : new URL(path2, metaUrl));
3468
3469
  }
3469
3470
  const loadedPath = (await loadBundledFile()).default;
3470
3471
  if (loadedPath.startsWith("file:")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globant/coda-linux-arm64",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Coda CLI native binary (linux-arm64)",
5
5
  "os": [
6
6
  "linux"