@swifty.js/swifty 0.0.31 → 0.0.32
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/README.md +46 -3
- package/dist/agent-2DUTUJFX.js +4 -0
- package/dist/{anthropic-CFM2DXMB.js → anthropic-KR5MXB5I.js} +1 -1
- package/dist/{checker-A6PGACKZ.js → checker-RKAWOOXC.js} +1 -1
- package/dist/{chunk-OQCEP2F5.js → chunk-2EV72T5X.js} +1 -1
- package/dist/{chunk-MVVSONAE.js → chunk-4YVJP2CO.js} +1 -1
- package/dist/chunk-BWWNI2FK.js +121 -0
- package/dist/{chunk-AGJYBJ5M.js → chunk-JMF2DWGY.js} +1 -1
- package/dist/{chunk-4ABFUBO4.js → chunk-LTFPTWX4.js} +117 -106
- package/dist/chunk-NERVCUWE.js +4 -0
- package/dist/chunk-S35E7OYL.js +5 -0
- package/dist/{chunk-C3WGLVVZ.js → chunk-TKQ5T5VO.js} +1 -1
- package/dist/{chunk-YAXZ2OUD.js → chunk-TW7RHCDS.js} +1 -1
- package/dist/lib/agent-3OEC4SOB.js +10 -0
- package/dist/lib/{anthropic-R6DMXE7U.js → anthropic-B33M2AVN.js} +4 -4
- package/dist/lib/{checker-M7RKMKJQ.js → checker-QNMXPZ7C.js} +3 -3
- package/dist/lib/{chunk-OQIQOU5S.js → chunk-3OFLDUAW.js} +121 -1
- package/dist/lib/{chunk-EY7HE52Q.js → chunk-3XCGUKGJ.js} +18 -24
- package/dist/lib/{chunk-EWE5IWZE.js → chunk-4BPKIIQD.js} +9 -0
- package/dist/lib/{chunk-FZ4Y6MBN.js → chunk-BCBD34D2.js} +1 -1
- package/dist/lib/{chunk-4MDCRPVV.js → chunk-FODSMOWP.js} +6 -6
- package/dist/lib/{chunk-A4MXZA5Q.js → chunk-SOOSTGHI.js} +2 -2
- package/dist/lib/{chunk-OEPCNATU.js → chunk-TJLAJGG4.js} +2 -2
- package/dist/lib/{chunk-J6AV7SIF.js → chunk-UH5M7FDP.js} +9 -5
- package/dist/lib/index.d.ts +1402 -721
- package/dist/lib/index.js +11656 -10928
- package/dist/lib/{openai-5N42ZYIJ.js → openai-C2PZFGJ2.js} +3 -3
- package/dist/lib/{tool-filter-XG2GXFVN.js → tool-filter-IMIU7CW2.js} +1 -1
- package/dist/main.js +175 -176
- package/dist/{node-4LTSRXL2.js → node-GXMM4JG3.js} +1 -1
- package/dist/{openai-NQYARTT6.js → openai-M7B2TITO.js} +1 -1
- package/dist/seatbelt-3GM2YGXV.js +5 -0
- package/dist/{server-BNT2IIKB.js → server-QMMIYNXW.js} +10 -17
- package/dist/{tool-filter-5NDJMSTD.js → tool-filter-7LLVAHD5.js} +1 -1
- package/package.json +9 -12
- package/dist/agent-O6C4FCQY.js +0 -4
- package/dist/chunk-AQ3A5CF4.js +0 -5
- package/dist/chunk-OTVZGPHD.js +0 -121
- package/dist/chunk-Y2UUXOQA.js +0 -4
- package/dist/lib/agent-YRTROHXU.js +0 -10
- package/dist/seatbelt-YXUQ5XR3.js +0 -5
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ mcp_servers:
|
|
|
103
103
|
- name: database
|
|
104
104
|
command: npx
|
|
105
105
|
args: ["-y", "@swifty-db/mcp@latest"]
|
|
106
|
-
env: # map<string, string>; ${VAR}
|
|
106
|
+
env: # map<string, string>; supports ${VAR}, ${VAR:-default}, and $VAR
|
|
107
107
|
API_BASE_URL: "https://swifty-db.dev"
|
|
108
108
|
API_KEY: "${DATABASE_API_KEY}"
|
|
109
109
|
|
|
@@ -139,6 +139,31 @@ The thinking level controls reasoning depth. For `anthropic` it maps to a thinki
|
|
|
139
139
|
|
|
140
140
|
API keys are resolved in this order: explicit api_key field, then environment variables (ANTHROPIC_API_KEY for anthropic, OPENAI_API_KEY for openai and openai-compat).
|
|
141
141
|
|
|
142
|
+
### Project-level MCP servers (.mcp.json)
|
|
143
|
+
|
|
144
|
+
In addition to `mcp_servers` in `config.yaml`, Swifty reads a project-level `.mcp.json` from the working directory, using the Claude Code-compatible format:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"mcpServers": {
|
|
149
|
+
"database": {
|
|
150
|
+
"command": "npx",
|
|
151
|
+
"args": ["-y", "@swifty-db/mcp@latest"],
|
|
152
|
+
"env": { "API_KEY": "${DATABASE_API_KEY}" }
|
|
153
|
+
},
|
|
154
|
+
"remote": {
|
|
155
|
+
"type": "http",
|
|
156
|
+
"url": "https://example.com/mcp",
|
|
157
|
+
"headers": { "Authorization": "Bearer ${TOKEN}" }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Each entry takes `command`/`args`/`env` (stdio) or `url`/`headers` with `type` of `http` or `sse`. Environment references support `${VAR}`, `${VAR:-default}`, and `$VAR` in commands, arguments, environment values, URLs, and headers; an unset variable without a default prevents that server from connecting. These servers are merged with the user-level `mcp_servers`; on a name collision the user-level entry wins. At startup, a malformed `.mcp.json` is ignored (logged), while an invalid individual server entry is skipped without disabling valid siblings. During `/mcp reload`, invalid config aborts the reload so the current connections remain intact.
|
|
164
|
+
|
|
165
|
+
After editing `.mcp.json` or `config.yaml`, use `/mcp reload` in the TUI to re-read both sources. Unchanged connections stay live, removed servers disconnect, new servers connect, and servers whose settings changed restart.
|
|
166
|
+
|
|
142
167
|
## Usage
|
|
143
168
|
|
|
144
169
|
### Interactive TUI Mode
|
|
@@ -149,9 +174,9 @@ swifty
|
|
|
149
174
|
|
|
150
175
|
Launches the terminal interface. If multiple providers are configured, a provider selection screen appears first.
|
|
151
176
|
|
|
152
|
-
Use `/login` to configure and activate a provider from the TUI. When no provider is configured, the login form opens automatically. Name, protocol, base URL, API key, and model are required in the form. Use ↑↓ or Tab to move between fields, ←→ to select protocol or cycle the thinking level, Enter to save, and Esc to cancel. Changing the protocol also moves an untouched thinking level to that protocol's default.
|
|
177
|
+
Use `/login` to configure and activate a provider from the TUI. When no provider is configured, the login form opens automatically. Name, protocol, base URL, API key, and model are required in the form. Use ↑↓ or Tab to move between fields, ←→ to select protocol or cycle the thinking level, Enter to save, and Esc to cancel. Changing the protocol also moves an untouched thinking level to that protocol's default.
|
|
153
178
|
|
|
154
|
-
The form saves to `~/.swifty/config.yaml`, retaining existing providers and other settings. Context window accepts integers from 1000 to 10000000; max output accepts integers from 1 to 1000000 and must not exceed the context window. Empty optional fields use the defaults above.
|
|
179
|
+
The form saves to `~/.swifty/config.yaml`, retaining existing providers and other settings. `base_url` is the provider identity: saving a provider whose `base_url` already exists replaces that entry in place instead of adding another one, and names may repeat freely. Context window accepts integers from 1000 to 10000000; max output accepts integers from 1 to 1000000 and must not exceed the context window. Empty optional fields use the defaults above.
|
|
155
180
|
|
|
156
181
|
### Print Mode (Non-Interactive)
|
|
157
182
|
|
|
@@ -195,6 +220,7 @@ Inside the TUI, these commands are available:
|
|
|
195
220
|
| /sandbox [1/2/3] | Configure sandbox (1=on+auto, 2=on+manual, 3=off) |
|
|
196
221
|
| /worktree | List git worktrees |
|
|
197
222
|
| /mcp | Show MCP server status |
|
|
223
|
+
| /mcp reload | Re-read MCP config; reconcile unchanged, removed, new, and changed servers |
|
|
198
224
|
| /thinking [level] | Show or set the thinking level (off, minimal, low, medium, high, xhigh, max); setting persists to `~/.swifty/config.yaml` |
|
|
199
225
|
| /quit | Exit the application |
|
|
200
226
|
|
|
@@ -211,3 +237,20 @@ Inside the TUI, these commands are available:
|
|
|
211
237
|
Pastes longer than 10 lines or 1,000 characters collapse to `[paste #1 +124 lines]` or `[paste #1 1234 chars]`. Clipboard images appear as `[Image #1]`. Arrow keys move across each placeholder as a unit, and Backspace/Delete remove it as a unit. Placeholders survive dialog switches; submitting restores the full text and image attachments.
|
|
212
238
|
|
|
213
239
|
Pasting an image saves it as a PNG under `.swifty/file-history/<session-id>/`. Its placeholder expands to a workDir-relative `@` reference on submit and loads as an inline image block. Linux requires `wl-clipboard` (Wayland) or `xclip` (X11).
|
|
240
|
+
|
|
241
|
+
## Library Build
|
|
242
|
+
|
|
243
|
+
Besides the `swifty` CLI, the package ships a library entry for embedding Swifty in another host process.
|
|
244
|
+
|
|
245
|
+
| Entry | Output | Contents |
|
|
246
|
+
| -------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
|
|
247
|
+
| CLI (`swifty`) | `dist/main.js` | Fully bundled, minified single file with a shebang; only Node built-ins stay external. |
|
|
248
|
+
| Library | `dist/lib/index.js`, `dist/lib/index.d.ts` | The `src/index.ts` barrel; runtime dependencies stay external and resolve from the consumer's `node_modules`. |
|
|
249
|
+
|
|
250
|
+
The library entry is terminal-independent by contract: it must never reach `src/tui/**` or a terminal-only dependency, so a host without a TTY (a server, an editor extension, a test harness) can import it. `pnpm build` enforces that contract:
|
|
251
|
+
|
|
252
|
+
- **Terminal-only dependency ban** — the `ban-terminal-only-deps` plugin in `tsup.config.ts` fails the build when a bundle-reachable module imports one of the terminal-only packages (`ink`, `chalk`, `ansi-escapes`, …) or a path inside `src/tui`. The list is declared once in `tsup.config.ts` and re-derived from the actual import sites by `tests/build-guards.test.ts`, which fails if the two drift apart.
|
|
253
|
+
- **`react` and `react-dom` are allowed** — the cross-platform hooks under `src/ui/**` are public API and depend on them.
|
|
254
|
+
- **Ambiguous export scan** — once the bundle is written, the build runs the TypeScript ambiguous-export check (`TS2308`) over the library graph. A name exported by two `export *` sources is dropped by the bundler without any warning; the scan turns that into a build failure instead of a quietly smaller public API.
|
|
255
|
+
|
|
256
|
+
In a long-lived host process, prefer the composable modules (`Agent`, `ToolRegistry`, …) over the process-level entry points (`print-mode`, `recover`, `teammate`), which may write crash dumps or call `process.exit()`.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __swiftyCreateRequire } from "node:module";
|
|
3
|
+
const require = __swiftyCreateRequire(import.meta.url);
|
|
4
|
+
import{s as a}from"./chunk-TW7RHCDS.js";import"./chunk-TCQ4EB4G.js";import"./chunk-S35E7OYL.js";import"./chunk-2EV72T5X.js";import"./chunk-BWWNI2FK.js";import"./chunk-X3UA5OZL.js";export{a as Agent};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __swiftyCreateRequire } from "node:module";
|
|
3
3
|
const require = __swiftyCreateRequire(import.meta.url);
|
|
4
|
-
import{a as Z}from"./chunk-
|
|
4
|
+
import{a as Z}from"./chunk-JMF2DWGY.js";import{a as Q}from"./chunk-TCQ4EB4G.js";import{g as M}from"./chunk-TKQ5T5VO.js";import{A as J,B as V,C as q,E as X,k as B,m as O,n as U,o as j,p as $,q as K,r as F,t as C,u as E,y as D,z as I}from"./chunk-S35E7OYL.js";import"./chunk-2EV72T5X.js";import{D as w,I as N,J as H,K as z,L as G,M as d,N as W,R as Y,g as R}from"./chunk-BWWNI2FK.js";import"./chunk-X3UA5OZL.js";function oe(o){for(let t=o.length-1;t>=0;t--){let e=o[t];if(e.defer_loading!==!0){e.cache_control={type:"ephemeral"};return}}}function ne(o){return o.some(t=>"defer_loading"in t&&t.defer_loading===!0)}var re="computer-use-2025-11-24";function se(o){if("type"in o&&o.type==="computer_20251124")return{...o};if("input_schema"in o){let t=o,{cache_control:e,...n}=t;return{...n,type:"custom",...t.defer_loading!==!0&&e?{cache_control:e}:{}}}throw new Error("Anthropic received a tool schema serialized for another protocol.")}var T=N({module:"llm"});var ie=3e3,ae=w.object({max_input_tokens:w.coerce.number()});async function Te(o){if(o.protocol!=="anthropic")return 0;let t=E(o),n=`${o.base_url.replace(/\/+$/,"")}/v1/models/${encodeURIComponent(o.model)}`,r=new AbortController,s=setTimeout(()=>{r.abort()},ie);try{let c=await fetch(n,{method:"GET",headers:{"anthropic-version":"2023-06-01",...t?{"x-api-key":t}:{}},signal:r.signal});if(!c.ok)return 0;let v=await c.json(),{success:p,error:u,data:h}=await R(ae,v);if(!p)return T.warn({message:u.message},"model context window schema validation failed"),0;let m=h.max_input_tokens;return Math.max(m,0)}catch(c){return T.error({err:c},"failed to fetch model context window"),0}finally{clearTimeout(s)}}function y(o){return typeof o=="string"?[{type:"text",text:o}]:o.map(t=>{let e=Q(t);if(!e||e.type==="tool_reference")throw new Error(`Unsupported user content block: ${Y(t,"type","unknown")}`);return e})}function le(o){let t=[];for(let e of o)if(e.role==="assistant"){let n=[];if(e.thinkingBlocks)for(let s of e.thinkingBlocks)n.push({type:"thinking",thinking:s.thinking,signature:s.signature});let r=typeof e.content=="string"?e.content:H(e.content);if(r&&n.push({type:"text",text:r}),e.toolUses)for(let s of e.toolUses)n.push({type:"tool_use",id:s.toolUseId,name:s.toolName==="ComputerUse"?"computer":s.toolName,input:s.arguments});n.length===0&&n.push({type:"text",text:""}),t.push({role:"assistant",content:n})}else if(e.toolResults&&e.toolResults.length>0){let n=[];for(let r of e.toolResults)n.push({type:"tool_result",tool_use_id:r.toolUseId,is_error:r.isError,content:r.contentBlocks?.length?r.contentBlocks:r.content});e.content.length>0&&n.push(...y(e.content)),t.push({role:"user",content:n})}else{if(t.length===0){t.push({role:"user",content:y(e.content)});continue}let n=!1,r=t[t.length-1],s=r.content;r.role==="user"&&(typeof s=="string"||Array.isArray(s)&&s.length>0&&(s[0].type==="text"||s[0].type==="image"))&&(n=!0),n?(typeof s=="string"&&(s=r.content=s.trim().length>0?[{type:"text",text:s}]:[]),s.push(...y(e.content))):t.push({role:"user",content:y(e.content)})}return t}var ee=class{protocol="anthropic";client;model;thinkingLevel;systemPrompt;maxOutputTokens;config;constructor(t,e){let n=E(t);if(!n)throw new I("Anthropic API key not found, set ANTHROPIC_API_KEY in ~/.swifty/config.yaml, or via ANTHROPIC_API_KEY env variable.");this.client=new M({apiKey:n,baseURL:t.base_url}),this.model=t.model,this.config={...t},this.thinkingLevel=O(t),this.systemPrompt=e,this.maxOutputTokens=C(t)}setSystemPrompt(t){this.systemPrompt=t}setMaxOutputTokens(t){this.config={...this.config,max_output_tokens:t},this.maxOutputTokens=C(this.config),this.setThinkingLevel(this.thinkingLevel)}setThinkingLevel(t){return this.thinkingLevel=F(this.config,t),this.thinkingLevel}getThinkingLevel(){return this.thinkingLevel}getSupportedThinkingLevels(){return K(this.config)}async*stream(t,e,n){let r=le(X(t.getMessages())),s=ne(e),c=e.map(se),v=c.some(l=>"type"in l&&l.type==="computer_20251124");oe(c),ce(r);let p={model:this.model,max_tokens:this.maxOutputTokens,stream:!0,system:[{type:"text",text:this.systemPrompt,cache_control:{type:"ephemeral"}}],messages:r,...c.length>0?{tools:c}:{}},u=this.getThinkingLevel();if(this.config.reasoning!==!1)if(u==="off")p.thinking={type:"disabled"};else if(this.config.thinking_mode==="adaptive"){let l=$(u,this.config);l!==null&&(p.thinking={type:"adaptive"},p.output_config={effort:l})}else{let l=j(u,this.config);l!==null&&l!=="none"&&(p.thinking={type:"enabled",budget_tokens:Math.min(U(l),this.maxOutputTokens-B)})}let h=0,m=0,x=0,A=0,S="end_turn",b="",L="",P=!1;try{let l=[...s?[Z]:[],...v?[re]:[]],te=this.client.messages.stream(p,{...n?{signal:n}:{},...l.length>0?{headers:{"anthropic-beta":l.join(",")}}:{}}),g="",k="",f="";for await(let a of te)switch(a.type){case"content_block_start":{let i=a.content_block;i.type==="thinking"?(P=!0,b="",L=""):i.type==="tool_use"&&(k=i.id,g=i.name==="computer"?"ComputerUse":i.name,f="",yield{type:"tool_call_start",toolName:g,toolId:k});break}case"content_block_delta":{let i=a.delta;i.type==="thinking_delta"?(b+=i.thinking,yield{type:"thinking_delta",text:i.thinking}):i.type==="signature_delta"?L+=i.signature:i.type==="text_delta"?yield{type:"text_delta",text:i.text}:i.type==="input_json_delta"&&(f+=i.partial_json,yield{type:"tool_call_delta",text:i.partial_json});break}case"content_block_stop":{if(P&&(yield{type:"thinking_complete",thinking:b,signature:L},P=!1),g){let i={};if(f)try{let _=JSON.parse(f);i=z(_)?G(_):{}}catch(_){T.error({err:_},"llm operation failed"),i={}}yield{type:"tool_call_complete",toolId:k,toolName:g,arguments:i},g="",k="",f=""}break}case"message_delta":{a.delta.stop_reason&&(S=a.delta.stop_reason),a.usage.output_tokens&&(m=a.usage.output_tokens,a.usage.input_tokens&&(h=a.usage.input_tokens),a.usage.cache_read_input_tokens&&(x=a.usage.cache_read_input_tokens),a.usage.cache_creation_input_tokens&&(A=a.usage.cache_creation_input_tokens));break}case"message_start":{h=a.message.usage.input_tokens,m=a.message.usage.output_tokens,x=a.message.usage.cache_read_input_tokens??0,A=a.message.usage.cache_creation_input_tokens??0;break}}yield{type:"stream_end",stopReason:S,usage:{inputTokens:h,outputTokens:m,cacheReadInputTokens:x,cacheCreationInputTokens:A}}}catch(l){throw T.error({err:l},"llm operation failed"),pe(l)}}};function ce(o){for(let t=o.length-1;t>=0;t--){if(o[t].role!=="user")continue;let e=o[t].content;if(typeof e=="string"&&e.length===0||Array.isArray(e)&&e.length===0)return;typeof e=="string"&&(e=o[t].content=[{type:"text",text:e}]);let n=e[e.length-1];for(let r=e.length-1;r>=0;r--)if(e[r].type!=="image"){n=e[r];break}Reflect.set(n,"cache_control",{type:"ephemeral"});return}}function pe(o){if(o instanceof M.APIError){if(o.status===413||/prompts?\s+too\s+long/i.test(o.message))return new q(`Prompt too long: ${o.message}`);if(o.status===401)return new I(`Invalid API key: ${o.message}`);if(o.status===429){let t=o.headers,e=t instanceof Headers?t.get("retry-after"):void 0,n="Rate Limited";if(e){let r=Number.parseInt(d(e));Number.isNaN(r)?n+=", please wait.":n+=`, retry after ${d(r)}s.`}else n+=", please wait.";return new J(n,e?d(e):void 0)}return new D(`Anthropic API error (${d(o.status)}): ${o.message}`)}return new V(`Network error: ${W(o)}`)}export{ee as AnthropicClient,le as buildAnthropicMessages,Te as fetchModelContextWindow,ce as markLastUserTailForCache,oe as markToolsForCache,ne as needsToolSearchBeta};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __swiftyCreateRequire } from "node:module";
|
|
3
3
|
const require = __swiftyCreateRequire(import.meta.url);
|
|
4
|
-
import{c as a,d as b,e as c,f as d,g as e,h as f}from"./chunk-
|
|
4
|
+
import{c as a,d as b,e as c,f as d,g as e,h as f}from"./chunk-4YVJP2CO.js";import"./chunk-2EV72T5X.js";import"./chunk-BWWNI2FK.js";import"./chunk-X3UA5OZL.js";export{b as PathSandbox,f as PermissionChecker,d as RuleEngine,c as evaluateRules,a as extractContent,e as isSafeCommand};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __swiftyCreateRequire } from "node:module";
|
|
3
3
|
const require = __swiftyCreateRequire(import.meta.url);
|
|
4
|
-
import{I as d,L as f,N as y,R as l}from"./chunk-
|
|
4
|
+
import{I as d,L as f,N as y,R as l}from"./chunk-BWWNI2FK.js";var S=d({module:"mcp"}),u="mcp__",p="__";function a(e){return e.replace(/[^a-zA-Z0-9_]/g,"_")}function M(e){return u+a(e)+p}function g(e,t){return M(e)+a(t)}var T=class{name;description;category="command";deferred=!0;mcpServerName;client;originalName;inputSchema;constructor(t,r,n){this.name=g(r,n.name),this.description=n.description,this.originalName=n.name,this.client=t,this.inputSchema=n.inputSchema,this.mcpServerName=r}mcpInputSchema(){return this.inputSchema??{}}setDeferLoading(t){this.deferred=t}schema(){return{name:this.name,description:this.description,input_schema:this.inputSchema}}async execute(t,r){try{return await this.client.callTool(this.originalName,r,t.abortSignal)}catch(n){return S.error({err:n},"mcp operation failed"),{output:`MCP tool error: ${y(n)}`,isError:!0}}}};function P(e,t){if(t==="string"&&typeof e=="number"&&Number.isFinite(e))return String(e);if((t==="integer"||t==="number")&&typeof e=="string"){let r=e.trim();if(r===""||!(t==="integer"?/^[+-]?\d+$/:/^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/).test(r))return e;let s=t==="integer"?Number.parseInt(r,10):Number.parseFloat(r);return Number.isFinite(s)?s:e}if(t==="boolean"&&typeof e=="string"){let r=e.trim().toLowerCase();if(r==="true")return!0;if(r==="false")return!1}return e}function h(e,t){if(typeof t!="object"||t===null)return e;let r=f(t),n=l(r,"type","");if(n==="object"&&typeof e=="object"&&e!==null&&!Array.isArray(e)){let s=f(r.properties??{}),o={};for(let[i,c]of Object.entries(e))o[i]=i in s?h(c,s[i]):c;return o}if(n==="array"){let s=r.items??{},o=e;if(typeof o=="object"&&o!==null&&!Array.isArray(o)){let i=Object.values(o);i.length===1&&Array.isArray(i[0])&&(o=i[0])}else typeof o=="string"&&(o=o.split(",").map(i=>i.trim()).filter(i=>i!==""));return Array.isArray(o)?o.map(i=>h(i,s)):o}return n!==""?P(e,n):e}function A(e,t){if(t.startsWith(u)){let r=t.slice(u.length),n=r.indexOf(p);if(n>=0)return a(r.slice(0,n))+p+a(r.slice(n+p.length))}return a(e)+p+a(t)}function b(e){return"mcpInputSchema"in e&&typeof e.mcpInputSchema=="function"}var C=class{constructor(t){this.registry=t}registry;name="McpCall";description="Invoke a tool on a connected MCP server. Call ToolSearch first to load the tool's schema, then pass its arguments here exactly as that schema requires, using the same JSON types.";category="command";deferred=!1;schema(){return{name:this.name,description:this.description,input_schema:{type:"object",properties:{server:{type:"string",description:"MCP server name, e.g. 'linear'."},tool:{type:"string",description:"Full tool name as returned by ToolSearch, e.g. 'mcp__linear__create_issue'."},arguments:{type:"object",description:"The target tool's arguments. Must match that tool's input_schema exactly, including JSON types: bare numbers for integer fields, bare true/false for boolean fields, quoted strings for string fields, and plain JSON arrays for array fields."}},required:["server","tool","arguments"]}}}resolveTarget(t){let r=l(t,"server"),n=l(t,"tool");if(!r||!n)return;let s=n.startsWith(u)?n:g(r,n),o=this.registry.get(s);return o&&b(o)&&a(o.mcpServerName)===a(r)?o:void 0}availableNames(){return this.registry.listTools().filter(t=>t.name.startsWith(u)).map(t=>t.name).sort()}async execute(t,r){let n=l(r,"server",""),s=l(r,"tool","");if(s==="")return{output:"McpCall requires a 'tool' name",isError:!0};let o=this.resolveTarget(r);if(!o){let c=this.availableNames(),m=c.length>0?c.join(", "):"(none connected)";return{output:`Unknown MCP tool '${s}' on server '${n}'. Available tools: ${m}`,isError:!0}}if(typeof r.arguments!="object"||r.arguments===null||Array.isArray(r.arguments))return{output:"McpCall requires an 'arguments' object matching the target schema",isError:!0};let i=f(r.arguments);if(b(o)){let c=o.mcpInputSchema();if(Object.keys(c).length>0){let m=h(i,c);typeof m=="object"&&m!==null&&!Array.isArray(m)&&(i=f(m))}}return t.abortSignal?.throwIfAborted(),o.execute(t,i)}};export{u as a,T as b,A as c,b as d,C as e};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __swiftyCreateRequire } from "node:module";
|
|
3
3
|
const require = __swiftyCreateRequire(import.meta.url);
|
|
4
|
-
import{c as C}from"./chunk-OQCEP2F5.js";import{D as p,I as D,K as j,R as c,d as y,e as S}from"./chunk-OTVZGPHD.js";import{readFileSync as U,writeFileSync as q,mkdirSync as V,statSync as z}from"fs";import{homedir as G,tmpdir as Y}from"os";import{join as g,resolve as f,dirname as I}from"path";import{realpathSync as O}from"fs";import{basename as T,dirname as M,isAbsolute as _,join as N,relative as L,resolve as A,sep as H}from"path";function d(n){let e=A(n),s=[];for(;;)try{return N(O(e),...s)}catch(t){if(!(t instanceof Error)||!("code"in t)||t.code!=="ENOENT"&&t.code!=="ENOTDIR")throw t;let r=M(e);if(r===e)return A(n);s.unshift(T(e)),e=r}}function m(n,e){let s=L(n,e);return s===""||s!==".."&&!s.startsWith(`..${H}`)&&!_(s)}var k=D({module:"permissions"}),Z=[],B=["basename","cat","cksum","cmp","column","comm","cut","df","dirname","du","echo","expr","false","fold","fmt","grep","groups","head","id","jq","locate","ls","md5","md5sum","nl","od","paste","pgrep","printenv","printf","ps","pwd","readlink","realpath","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shasum","stat","strings","tac","tail","tr","true","tty","type","uname","uptime","w","wc","whereis","which","who","whoami","ack","ag","alias","arch","base64","bat","bzcat","cal","col","cloc","diff","diff3","dig","dmesg","expand","factor","free","help","hexdump","host","iconv","info","locale","lscpu","lsblk","lsof","lspci","lsusb","man","mdfind","mdls","ncal","netstat","nproc","nslookup","objdump","otool","pbpaste","ping","readelf","rev","sdiff","seq","sum","sw_vers","tldr","traceroute","unexpand","vm_stat","whois","xxd","xzcat","zcat","zgrep","zipinfo",/^command\s+(?:-v|-V)\s+\S+(?:\s+\S+)*$/,/^date(?!.*\s(?:-s|--set)(?:=|\s|$))(?:\s.*)?$/,/^file(?!.*(?:\s--compile(?:=|\s|$)|\s-[^-\s]*C))(?:\s.*)?$/,/^find(?!.*\s(?:-delete|-exec(?:dir)?|-ok(?:dir)?|-fls|-fprint(?:0)?|-fprintf)(?:\s|$))(?:\s.*)?$/,/^fd(?!.*\s(?:-x|-X|--exec|--exec-batch)(?:=|\s|$))(?:\s.*)?$/,/^hostname(?:\s+(?:-[adfFiIsyVh]|--(?:alias|all-fqdns|all-ip-addresses|domain|fqdn|help|ip-address|long|nis|short|version|yp)))*$/,/^rg(?!.*\s(?:--pre|--pre-glob|--hostname-bin)(?:=|\s|$))(?:\s.*)?$/,/^sort(?!.*\s(?:-o|--output|--compress-program)(?:=|\s|$))(?:\s.*)?$/,/^ss(?!.*\s(?:--kill|-[^-\s]*K)(?:\s|$))(?:\s.*)?$/,/^tree(?!.*\s(?:-o|--output)(?:=|\s|$))(?:\s.*)?$/,/^git\s+(?:--version|version)$/,/^git\s+(?:blame|cat-file|count-objects|describe|for-each-ref|ls-files|ls-tree|merge-base|name-rev|rev-parse|shortlog|show-ref|status|verify-pack)(?:\s.*)?$/,/^git\s+(?:diff|log|show)(?!.*\s(?:--ext-diff|--output)(?:=|\s|$))(?:\s.*)?$/,/^git\s+branch$/,/^git\s+branch(?=.*\s(?:-a|--all|-r|--remotes|--list|--show-current|--contains|--no-contains|--merged|--no-merged)(?:=|\s|$))(?!.*\s(?:-[dDmMcCf]|--(?:copy|create-reflog|delete|edit-description|move|set-upstream-to|unset-upstream))(?:=|\s|$))(?:\s.*)?$/,/^git\s+config(?:\s+(?:--blob(?:=|\s)\S+|--file(?:=|\s)\S+|--fixed-value|--global|--local|--null|--show-names|--show-origin|--show-scope|--system|--worktree|-z))*\s+(?:--get|--get-all|--get-regexp|--get-urlmatch|--list|-l)(?:\s.*)?$/,/^git\s+notes\s+(?:list|show)(?:\s.*)?$/,/^git\s+reflog\s+show(?:\s.*)?$/,/^git\s+remote(?:\s+-v)?$/,/^git\s+remote\s+get-url(?:\s+(?:--all|--push))*\s+\S+$/,/^git\s+remote\s+show(?:\s+-n)?(?:\s+\S+)?$/,/^git\s+stash\s+(?:list|show)(?:\s.*)?$/,/^git\s+submodule\s+(?:status|summary)(?:\s.*)?$/,/^git\s+tag(?:\s+(?:-l|--list)(?:\s.*)?)?$/,/^git\s+worktree\s+list(?:\s.*)?$/,/^(?:bun|npm|pnpm|yarn)\s+(?:explain|help|info|list|ls|outdated|prefix|query|root|search|show|view|why)(?:\s.*)?$/,/^(?:npm|pnpm|yarn)\s+config\s+(?:get|list)(?:\s.*)?$/,/^npm\s+pkg\s+get(?:\s.*)?$/,/^bun\s+pm\s+ls(?:\s.*)?$/,/^(?:bun|cargo|clang|cmake|composer|deno|gcc|gem|node|npm|php|pip|pip3|pnpm|python|python3|ruby|rustc|swift|yarn)\s+(?:--version|-V)$/,/^(?:go|helm|kubectl|podman|terraform)\s+version(?:\s.*)?$/,/^(?:java|javac)\s+-version$/,/^dotnet\s+(?:--info|--list-runtimes|--list-sdks|--version)$/,/^(?:docker|podman)\s+(?:diff|events|images|info|inspect|logs|port|ps|stats|top|version)(?:\s.*)?$/,/^(?:docker|podman)\s+(?:container|image|network|volume)\s+(?:inspect|ls)(?:\s.*)?$/,/^docker\s+compose\s+(?:config|images|logs|ps|top|version)(?:\s.*)?$/,/^kubectl\s+(?:api-resources|api-versions|cluster-info|describe|explain|get|logs|top|version)(?:\s.*)?$/,/^kubectl\s+config\s+(?:current-context|get-contexts|view)(?:\s.*)?$/,/^helm\s+(?:env|get|history|list|search|show|status|version)(?:\s.*)?$/,/^terraform\s+(?:output|providers|show|version)(?:\s.*)?$/,/^terraform\s+workspace\s+(?:list|show)(?:\s.*)?$/,/^systemctl\s+(?:is-active|is-enabled|is-failed|list-dependencies|list-jobs|list-sockets|list-timers|list-unit-files|list-units|show|show-environment|status)(?:\s.*)?$/,/^launchctl\s+(?:error|hostinfo|list|managername|managerpid|manageruid|print|print-cache|procinfo|variant|version)(?:\s.*)?$/,/^journalctl(?!.*\s--(?:rotate|vacuum|flush|sync))(?:\s.*)?$/,/^defaults\s+read(?:\s.*)?$/,/^ifconfig$/,/^ipconfig(?:\s+\/(?:all|allcompartments|displaydns))?\s*$/,/^ip\s+(?:addr(?:ess)?|route)$/,/^ip\s+(?:addr(?:ess)?|link|route|neigh(?:bor)?)\s+(?:show|list)\b(?:\s.*)?$/,/^tar\s+(?:--list\b|-[a-zA-Z]*t[a-zA-Z]*)(?:\s.*)?$/,/^unzip\s+-[a-zA-Z]*l(?:\s.*)?$/,/^git\s+(?:grep|fsck|rev-list|whatchanged|help|diff-tree|diff-index|diff-files|ls-remote|verify-tag|verify-commit)(?:\s.*)?$/,/^git\s+archive(?!.*\s(?:-o|--output)(?:=|\s|$))(?:\s.*)?$/,/^svn\s+(?:status|stat|st|diff|di|log|info|list|ls|cat|blame|ann|annotate|proplist|propget|pg)(?:\s.*)?$/,/^hg\s+(?:status|st|log|diff|summary|id|identify|branches|tags|manifest|cat|files|locate|heads|tip|parents|paths|root)(?:\s.*)?$/,/^cargo\s+(?:tree|search|locate-project|verify-project|config\s+get)(?:\s.*)?$/,/^gem\s+(?:list|search|info|env|dependency|contents|specification|sources\s+(?:-l|--list))(?:\s.*)?$/,/^brew\s+(?:--version|-v|list|info|search|outdated|deps|uses|config|leaves|doctor)(?:\s.*)?$/,/^choco\s+(?:--version|list|info|search|outdated)(?:\s.*)?$/,/^apt(?:-get)?\s+list(?:\s.*)?$/,/^apt-cache\s+(?:search|show|showpkg|policy|depends|rdepends|pkgnames)(?:\s.*)?$/,/^dpkg\s+(?:-l|-L|-s|-S|--list|--listfiles|--status|--search)\b(?:\s.*)?$/,/^rpm\s+-q[a-zA-Z]*(?:\s.*)?$/,/^(?:aws|gh|gcloud|az)\s+--version$/,/^aws\s+(?:\S+\s+)?(?:describe|list|get|wait)-\S+(?:\s.*)?$/,/^aws\s+s3\s+ls(?:\s.*)?$/,/^gcloud\s+\S+(?:\s+\S+)*\s+(?:list|describe)(?:\s.*)?$/,/^az\s+\S+(?:\s+\S+)*\s+(?:list|show)(?:\s.*)?$/,/^gh\s+(?:pr|issue|repo|run|release|gist)\s+(?:view|list|status|checks|diff)(?:\s.*)?$/,/^(?:docker|podman)\s+(?:system\s+(?:df|info)|history|context\s+(?:ls|list|show|inspect))(?:\s.*)?$/,/^(?:Get-(?:Acl|Alias|AuthenticodeSignature|ChildItem|CimInstance|Clipboard|Command|ComputerInfo|Content|Counter|Culture|Date|DnsClientCache|EventLog|ExecutionPolicy|FileHash|Help|History|Host|HotFix|Item|ItemProperty|Location|Member|Module|NetAdapter|NetIPAddress|NetNeighbor|NetIPConfiguration|NetRoute|NetTCPConnection|NetUDPEndpoint|Package|PackageProvider|PnpDevice|Printer|Process|PSDrive|PSProvider|PSRepository|PSSnapin|ScheduledTask|Service|TimeZone|UICulture|Variable|Verb|WinEvent|WmiObject)|Compare-Object|Format-(?:Custom|Hex|List|Table|Wide)|Group-Object|Measure-Object|Out-String|Resolve-Path|Select-Object|Select-String|Sort-Object|Test-Path|Where-Object|Write-(?:Debug|Error|Host|Information|Output|Progress|Verbose|Warning))(?:\s.*)?$/i],X={Bash:"command",PowerShell:"command",ComputerUse:"action",ReadFile:"file_path",WriteFile:"file_path",EditFile:"file_path",Glob:"pattern",Grep:"pattern",InstallSkill:"source"},J=[];function v(n,e){if(n==="McpCall")return C(c(e,"server",""),c(e,"tool",""));let s=X[n];if(!s)return"";let t=e[s];return typeof t=="string"?t:n==="ComputerUse"&&Array.isArray(e.actions)?e.actions.map(r=>j(r)?c(r,"type"):"").filter(Boolean).join(","):""}var P=class{allowedRoots;denyWritePaths;projectDir;constructor(e){this.projectDir=f(e),this.allowedRoots=[this.projectDir,Y()],this.denyWritePaths=J.map(s=>g(this.projectDir,s))}addRoot(e){this.allowedRoots.push(f(e))}addDenyWrite(e){this.denyWritePaths.push(f(e))}checkDenyWrite(e){let s=f(this.projectDir,e),t=d(s);for(let r of this.denyWritePaths)if(m(r,s)||m(d(r),t))return{effect:"deny",reason:`Path ${e} is in deny-write list`};return null}check(e){let s=d(f(this.projectDir,e));for(let t of this.allowedRoots)if(m(d(t),s))return null;return{effect:"deny",reason:`Path ${e} is outside allowed directories`}}};function K(n,e){let s="^"+n.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$";try{return new RegExp(s).test(e)}catch(t){return k.error({err:t},"permissions operation failed"),!1}}var Q=/^(\w+)\((.+)\)$/;function F(n){let e;try{e=U(n,"utf-8")}catch(i){return i.code!=="ENOENT"&&k.error({err:i},"permissions operation failed"),[]}let s=p.object({rule:p.string().optional(),effect:p.string().optional()}),t;try{let i=y.load(e);t=S(p.array(s),i)}catch(i){return k.error({err:i},"permissions operation failed"),[]}let r=[];for(let i of t){if(i.effect!=="allow"&&i.effect!=="deny"&&i.effect!=="ask")continue;let o=Q.exec((i.rule??"").trim());o&&r.push({tool:o[1],pattern:o[2],effect:i.effect})}return r}function h(n,e,s){let t=null;for(let r of n)if(!(r.tool!==e&&r.tool!=="*")&&K(r.pattern,s)){if(r.effect==="deny")return"deny";r.effect==="ask"?t="ask":t??="allow"}return t}var E=class{userPath;projectPath;cache=new Map;constructor(e){this.userPath=g(G(),".swifty","permissions.yaml"),this.projectPath=g(e,".swifty","permissions.yaml")}rulesFor(e){let s;try{s=z(e,{bigint:!0})}catch{return this.cache.delete(e),[]}let t=this.cache.get(e);if(t?.mtimeNs===s.mtimeNs&&t.size===s.size)return t.rules;let r=F(e);return this.cache.set(e,{mtimeNs:s.mtimeNs,size:s.size,rules:r}),r}snapshot(){return[this.userPath,this.projectPath].flatMap(e=>this.rulesFor(e))}evaluate(e,s){return h(this.snapshot(),e,s)}appendProjectRule(e){V(I(this.projectPath),{recursive:!0});let s=F(this.projectPath);if(s.some(i=>i.tool===e.tool&&i.pattern===e.pattern&&i.effect===e.effect))return;s.push(e);let r=s.map(i=>({rule:`${i.tool}(${i.pattern})`,effect:i.effect}));q(this.projectPath,y.dump(r),"utf-8")}};function ee(n){for(let e of Z)if(e.re.test(n))return e.reason;return""}function se(n){let e=n.trim();return/[\r\n&|;<>`(){}[\]]/.test(e)?!1:B.some(s=>typeof s=="string"?e===s||e.startsWith(s+" ")||e.startsWith(s+" "):(s.lastIndex=0,s.test(e)))}function te(n,e){switch(n){case"bypassPermissions":return"allow";case"plan":return e==="read"?"allow":"ask";case"acceptEdits":return e==="command"?"ask":"allow";default:return e==="read"?"allow":"ask"}}var W=class n{constructor(e,s="default"){this.workDir=e;this.mode=s,this.sandbox=new P(e),this.ruleEngine=new E(e)}workDir;mode;planFilePath="";sandboxEnabled=!1;sandboxAutoAllow=!1;sandbox;ruleEngine;forWorkDir(e){let s=new n(e,this.mode);return s.ruleEngine=this.ruleEngine,s.sandboxEnabled=this.sandboxEnabled,s.sandboxAutoAllow=this.sandboxAutoAllow,s}check(e,s,t){let r=v(e,t),i=null,o=()=>i??=this.ruleEngine.snapshot(),a=h(o(),e,r);if(a==="deny"||a==="ask")return{effect:a,reason:`Permission rule: ${a}`};if(this.mode==="plan"&&(e==="WriteFile"||e==="EditFile")){let u=c(t,"file_path","");if(this.planFilePath&&d(f(this.workDir,u))===d(f(this.workDir,this.planFilePath))&&!this.sandbox.checkDenyWrite(u))return{effect:"allow",reason:"Plan file write allowed in plan mode"}}if(s==="command"&&se(r))return{effect:"allow",reason:"Safe read-only command"};let x=s==="command"?ee(r):"";if(x)return{effect:"deny",reason:`Dangerous command blocked: ${x}`};if(this.sandboxEnabled&&this.sandboxAutoAllow&&e==="Bash"){let u=c(t,"command").split(/\s*(?:&&|\|\||[;|])\s*/).map(w=>w.trim()).filter(Boolean),l=!1;for(let w of u){let R=h(o(),e,w);if(R==="deny")return{effect:"deny",reason:"Permission rule: deny"};R==="ask"&&(l=!0)}return l?{effect:"ask",reason:"Permission rule: ask (sandbox does not override)"}:{effect:"allow",reason:"Sandbox auto-allow: OS sandbox active"}}let b=c(t,"file_path",c(t,"path",""));if((s==="read"||s==="write")&&b){if(s==="write"){let l=this.sandbox.checkDenyWrite(b);if(l)return l}let u=this.sandbox.check(b);if(u&&this.mode!=="bypassPermissions"){let l=this.ruleEngine.evaluate(e,r);return l?{effect:l,reason:`Permission rule: ${l}`}:{effect:"ask",reason:u.reason}}}let $=h(o(),e,r);return $?{effect:$,reason:`Permission rule: ${$}`}:{effect:te(this.mode,s),reason:`Mode: ${this.mode}`}}allowExtraRoot(e){this.sandbox.addRoot(e)}allowAlways(e,s){let t=v(e,s),r=e==="ReadFile"||e==="WriteFile"||e==="EditFile",i;if(r&&t){let o=f(this.workDir,t),a=!1;try{a=z(o).isDirectory()}catch{}i=g(a?o:I(o),"*")}else i=t.trim().split(/\s+/).slice(0,2).join(" ")+"*";this.ruleEngine.appendProjectRule({tool:e,pattern:i,effect:"allow"})}describeToolAction(e,s){let t=v(e,s);if(t)return t;let r=[];for(let[i,o]of Object.entries(s)){let a=String(o);a.length>80&&(a=a.slice(0,80)+"..."),r.push(`${i}: ${a}`)}return r.join(", ")}};export{d as a,m as b,v as c,P as d,h as e,E as f,se as g,W as h};
|
|
4
|
+
import{c as C}from"./chunk-2EV72T5X.js";import{D as p,I as D,K as j,R as c,d as y,e as S}from"./chunk-BWWNI2FK.js";import{readFileSync as U,writeFileSync as q,mkdirSync as V,statSync as z}from"fs";import{homedir as G,tmpdir as Y}from"os";import{join as g,resolve as f,dirname as I}from"path";import{realpathSync as O}from"fs";import{basename as T,dirname as M,isAbsolute as _,join as N,relative as L,resolve as A,sep as H}from"path";function d(n){let e=A(n),s=[];for(;;)try{return N(O(e),...s)}catch(t){if(!(t instanceof Error)||!("code"in t)||t.code!=="ENOENT"&&t.code!=="ENOTDIR")throw t;let r=M(e);if(r===e)return A(n);s.unshift(T(e)),e=r}}function m(n,e){let s=L(n,e);return s===""||s!==".."&&!s.startsWith(`..${H}`)&&!_(s)}var k=D({module:"permissions"}),Z=[],B=["basename","cat","cksum","cmp","column","comm","cut","df","dirname","du","echo","expr","false","fold","fmt","grep","groups","head","id","jq","locate","ls","md5","md5sum","nl","od","paste","pgrep","printenv","printf","ps","pwd","readlink","realpath","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shasum","stat","strings","tac","tail","tr","true","tty","type","uname","uptime","w","wc","whereis","which","who","whoami","ack","ag","alias","arch","base64","bat","bzcat","cal","col","cloc","diff","diff3","dig","dmesg","expand","factor","free","help","hexdump","host","iconv","info","locale","lscpu","lsblk","lsof","lspci","lsusb","man","mdfind","mdls","ncal","netstat","nproc","nslookup","objdump","otool","pbpaste","ping","readelf","rev","sdiff","seq","sum","sw_vers","tldr","traceroute","unexpand","vm_stat","whois","xxd","xzcat","zcat","zgrep","zipinfo",/^command\s+(?:-v|-V)\s+\S+(?:\s+\S+)*$/,/^date(?!.*\s(?:-s|--set)(?:=|\s|$))(?:\s.*)?$/,/^file(?!.*(?:\s--compile(?:=|\s|$)|\s-[^-\s]*C))(?:\s.*)?$/,/^find(?!.*\s(?:-delete|-exec(?:dir)?|-ok(?:dir)?|-fls|-fprint(?:0)?|-fprintf)(?:\s|$))(?:\s.*)?$/,/^fd(?!.*\s(?:-x|-X|--exec|--exec-batch)(?:=|\s|$))(?:\s.*)?$/,/^hostname(?:\s+(?:-[adfFiIsyVh]|--(?:alias|all-fqdns|all-ip-addresses|domain|fqdn|help|ip-address|long|nis|short|version|yp)))*$/,/^rg(?!.*\s(?:--pre|--pre-glob|--hostname-bin)(?:=|\s|$))(?:\s.*)?$/,/^sort(?!.*\s(?:-o|--output|--compress-program)(?:=|\s|$))(?:\s.*)?$/,/^ss(?!.*\s(?:--kill|-[^-\s]*K)(?:\s|$))(?:\s.*)?$/,/^tree(?!.*\s(?:-o|--output)(?:=|\s|$))(?:\s.*)?$/,/^git\s+(?:--version|version)$/,/^git\s+(?:blame|cat-file|count-objects|describe|for-each-ref|ls-files|ls-tree|merge-base|name-rev|rev-parse|shortlog|show-ref|status|verify-pack)(?:\s.*)?$/,/^git\s+(?:diff|log|show)(?!.*\s(?:--ext-diff|--output)(?:=|\s|$))(?:\s.*)?$/,/^git\s+branch$/,/^git\s+branch(?=.*\s(?:-a|--all|-r|--remotes|--list|--show-current|--contains|--no-contains|--merged|--no-merged)(?:=|\s|$))(?!.*\s(?:-[dDmMcCf]|--(?:copy|create-reflog|delete|edit-description|move|set-upstream-to|unset-upstream))(?:=|\s|$))(?:\s.*)?$/,/^git\s+config(?:\s+(?:--blob(?:=|\s)\S+|--file(?:=|\s)\S+|--fixed-value|--global|--local|--null|--show-names|--show-origin|--show-scope|--system|--worktree|-z))*\s+(?:--get|--get-all|--get-regexp|--get-urlmatch|--list|-l)(?:\s.*)?$/,/^git\s+notes\s+(?:list|show)(?:\s.*)?$/,/^git\s+reflog\s+show(?:\s.*)?$/,/^git\s+remote(?:\s+-v)?$/,/^git\s+remote\s+get-url(?:\s+(?:--all|--push))*\s+\S+$/,/^git\s+remote\s+show(?:\s+-n)?(?:\s+\S+)?$/,/^git\s+stash\s+(?:list|show)(?:\s.*)?$/,/^git\s+submodule\s+(?:status|summary)(?:\s.*)?$/,/^git\s+tag(?:\s+(?:-l|--list)(?:\s.*)?)?$/,/^git\s+worktree\s+list(?:\s.*)?$/,/^(?:bun|npm|pnpm|yarn)\s+(?:explain|help|info|list|ls|outdated|prefix|query|root|search|show|view|why)(?:\s.*)?$/,/^(?:npm|pnpm|yarn)\s+config\s+(?:get|list)(?:\s.*)?$/,/^npm\s+pkg\s+get(?:\s.*)?$/,/^bun\s+pm\s+ls(?:\s.*)?$/,/^(?:bun|cargo|clang|cmake|composer|deno|gcc|gem|node|npm|php|pip|pip3|pnpm|python|python3|ruby|rustc|swift|yarn)\s+(?:--version|-V)$/,/^(?:go|helm|kubectl|podman|terraform)\s+version(?:\s.*)?$/,/^(?:java|javac)\s+-version$/,/^dotnet\s+(?:--info|--list-runtimes|--list-sdks|--version)$/,/^(?:docker|podman)\s+(?:diff|events|images|info|inspect|logs|port|ps|stats|top|version)(?:\s.*)?$/,/^(?:docker|podman)\s+(?:container|image|network|volume)\s+(?:inspect|ls)(?:\s.*)?$/,/^docker\s+compose\s+(?:config|images|logs|ps|top|version)(?:\s.*)?$/,/^kubectl\s+(?:api-resources|api-versions|cluster-info|describe|explain|get|logs|top|version)(?:\s.*)?$/,/^kubectl\s+config\s+(?:current-context|get-contexts|view)(?:\s.*)?$/,/^helm\s+(?:env|get|history|list|search|show|status|version)(?:\s.*)?$/,/^terraform\s+(?:output|providers|show|version)(?:\s.*)?$/,/^terraform\s+workspace\s+(?:list|show)(?:\s.*)?$/,/^systemctl\s+(?:is-active|is-enabled|is-failed|list-dependencies|list-jobs|list-sockets|list-timers|list-unit-files|list-units|show|show-environment|status)(?:\s.*)?$/,/^launchctl\s+(?:error|hostinfo|list|managername|managerpid|manageruid|print|print-cache|procinfo|variant|version)(?:\s.*)?$/,/^journalctl(?!.*\s--(?:rotate|vacuum|flush|sync))(?:\s.*)?$/,/^defaults\s+read(?:\s.*)?$/,/^ifconfig$/,/^ipconfig(?:\s+\/(?:all|allcompartments|displaydns))?\s*$/,/^ip\s+(?:addr(?:ess)?|route)$/,/^ip\s+(?:addr(?:ess)?|link|route|neigh(?:bor)?)\s+(?:show|list)\b(?:\s.*)?$/,/^tar\s+(?:--list\b|-[a-zA-Z]*t[a-zA-Z]*)(?:\s.*)?$/,/^unzip\s+-[a-zA-Z]*l(?:\s.*)?$/,/^git\s+(?:grep|fsck|rev-list|whatchanged|help|diff-tree|diff-index|diff-files|ls-remote|verify-tag|verify-commit)(?:\s.*)?$/,/^git\s+archive(?!.*\s(?:-o|--output)(?:=|\s|$))(?:\s.*)?$/,/^svn\s+(?:status|stat|st|diff|di|log|info|list|ls|cat|blame|ann|annotate|proplist|propget|pg)(?:\s.*)?$/,/^hg\s+(?:status|st|log|diff|summary|id|identify|branches|tags|manifest|cat|files|locate|heads|tip|parents|paths|root)(?:\s.*)?$/,/^cargo\s+(?:tree|search|locate-project|verify-project|config\s+get)(?:\s.*)?$/,/^gem\s+(?:list|search|info|env|dependency|contents|specification|sources\s+(?:-l|--list))(?:\s.*)?$/,/^brew\s+(?:--version|-v|list|info|search|outdated|deps|uses|config|leaves|doctor)(?:\s.*)?$/,/^choco\s+(?:--version|list|info|search|outdated)(?:\s.*)?$/,/^apt(?:-get)?\s+list(?:\s.*)?$/,/^apt-cache\s+(?:search|show|showpkg|policy|depends|rdepends|pkgnames)(?:\s.*)?$/,/^dpkg\s+(?:-l|-L|-s|-S|--list|--listfiles|--status|--search)\b(?:\s.*)?$/,/^rpm\s+-q[a-zA-Z]*(?:\s.*)?$/,/^(?:aws|gh|gcloud|az)\s+--version$/,/^aws\s+(?:\S+\s+)?(?:describe|list|get|wait)-\S+(?:\s.*)?$/,/^aws\s+s3\s+ls(?:\s.*)?$/,/^gcloud\s+\S+(?:\s+\S+)*\s+(?:list|describe)(?:\s.*)?$/,/^az\s+\S+(?:\s+\S+)*\s+(?:list|show)(?:\s.*)?$/,/^gh\s+(?:pr|issue|repo|run|release|gist)\s+(?:view|list|status|checks|diff)(?:\s.*)?$/,/^(?:docker|podman)\s+(?:system\s+(?:df|info)|history|context\s+(?:ls|list|show|inspect))(?:\s.*)?$/,/^(?:Get-(?:Acl|Alias|AuthenticodeSignature|ChildItem|CimInstance|Clipboard|Command|ComputerInfo|Content|Counter|Culture|Date|DnsClientCache|EventLog|ExecutionPolicy|FileHash|Help|History|Host|HotFix|Item|ItemProperty|Location|Member|Module|NetAdapter|NetIPAddress|NetNeighbor|NetIPConfiguration|NetRoute|NetTCPConnection|NetUDPEndpoint|Package|PackageProvider|PnpDevice|Printer|Process|PSDrive|PSProvider|PSRepository|PSSnapin|ScheduledTask|Service|TimeZone|UICulture|Variable|Verb|WinEvent|WmiObject)|Compare-Object|Format-(?:Custom|Hex|List|Table|Wide)|Group-Object|Measure-Object|Out-String|Resolve-Path|Select-Object|Select-String|Sort-Object|Test-Path|Where-Object|Write-(?:Debug|Error|Host|Information|Output|Progress|Verbose|Warning))(?:\s.*)?$/i],X={Bash:"command",PowerShell:"command",ComputerUse:"action",ReadFile:"file_path",WriteFile:"file_path",EditFile:"file_path",Glob:"pattern",Grep:"pattern",InstallSkill:"source"},J=[];function v(n,e){if(n==="McpCall")return C(c(e,"server",""),c(e,"tool",""));let s=X[n];if(!s)return"";let t=e[s];return typeof t=="string"?t:n==="ComputerUse"&&Array.isArray(e.actions)?e.actions.map(r=>j(r)?c(r,"type"):"").filter(Boolean).join(","):""}var P=class{allowedRoots;denyWritePaths;projectDir;constructor(e){this.projectDir=f(e),this.allowedRoots=[this.projectDir,Y()],this.denyWritePaths=J.map(s=>g(this.projectDir,s))}addRoot(e){this.allowedRoots.push(f(e))}addDenyWrite(e){this.denyWritePaths.push(f(e))}checkDenyWrite(e){let s=f(this.projectDir,e),t=d(s);for(let r of this.denyWritePaths)if(m(r,s)||m(d(r),t))return{effect:"deny",reason:`Path ${e} is in deny-write list`};return null}check(e){let s=d(f(this.projectDir,e));for(let t of this.allowedRoots)if(m(d(t),s))return null;return{effect:"deny",reason:`Path ${e} is outside allowed directories`}}};function K(n,e){let s="^"+n.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$";try{return new RegExp(s).test(e)}catch(t){return k.error({err:t},"permissions operation failed"),!1}}var Q=/^(\w+)\((.+)\)$/;function F(n){let e;try{e=U(n,"utf-8")}catch(i){return i.code!=="ENOENT"&&k.error({err:i},"permissions operation failed"),[]}let s=p.object({rule:p.string().optional(),effect:p.string().optional()}),t;try{let i=y.load(e);t=S(p.array(s),i)}catch(i){return k.error({err:i},"permissions operation failed"),[]}let r=[];for(let i of t){if(i.effect!=="allow"&&i.effect!=="deny"&&i.effect!=="ask")continue;let o=Q.exec((i.rule??"").trim());o&&r.push({tool:o[1],pattern:o[2],effect:i.effect})}return r}function h(n,e,s){let t=null;for(let r of n)if(!(r.tool!==e&&r.tool!=="*")&&K(r.pattern,s)){if(r.effect==="deny")return"deny";r.effect==="ask"?t="ask":t??="allow"}return t}var E=class{userPath;projectPath;cache=new Map;constructor(e){this.userPath=g(G(),".swifty","permissions.yaml"),this.projectPath=g(e,".swifty","permissions.yaml")}rulesFor(e){let s;try{s=z(e,{bigint:!0})}catch{return this.cache.delete(e),[]}let t=this.cache.get(e);if(t?.mtimeNs===s.mtimeNs&&t.size===s.size)return t.rules;let r=F(e);return this.cache.set(e,{mtimeNs:s.mtimeNs,size:s.size,rules:r}),r}snapshot(){return[this.userPath,this.projectPath].flatMap(e=>this.rulesFor(e))}evaluate(e,s){return h(this.snapshot(),e,s)}appendProjectRule(e){V(I(this.projectPath),{recursive:!0});let s=F(this.projectPath);if(s.some(i=>i.tool===e.tool&&i.pattern===e.pattern&&i.effect===e.effect))return;s.push(e);let r=s.map(i=>({rule:`${i.tool}(${i.pattern})`,effect:i.effect}));q(this.projectPath,y.dump(r),"utf-8")}};function ee(n){for(let e of Z)if(e.re.test(n))return e.reason;return""}function se(n){let e=n.trim();return/[\r\n&|;<>`(){}[\]]/.test(e)?!1:B.some(s=>typeof s=="string"?e===s||e.startsWith(s+" ")||e.startsWith(s+" "):(s.lastIndex=0,s.test(e)))}function te(n,e){switch(n){case"bypassPermissions":return"allow";case"plan":return e==="read"?"allow":"ask";case"acceptEdits":return e==="command"?"ask":"allow";default:return e==="read"?"allow":"ask"}}var W=class n{constructor(e,s="default"){this.workDir=e;this.mode=s,this.sandbox=new P(e),this.ruleEngine=new E(e)}workDir;mode;planFilePath="";sandboxEnabled=!1;sandboxAutoAllow=!1;sandbox;ruleEngine;forWorkDir(e){let s=new n(e,this.mode);return s.ruleEngine=this.ruleEngine,s.sandboxEnabled=this.sandboxEnabled,s.sandboxAutoAllow=this.sandboxAutoAllow,s}check(e,s,t){let r=v(e,t),i=null,o=()=>i??=this.ruleEngine.snapshot(),a=h(o(),e,r);if(a==="deny"||a==="ask")return{effect:a,reason:`Permission rule: ${a}`};if(this.mode==="plan"&&(e==="WriteFile"||e==="EditFile")){let u=c(t,"file_path","");if(this.planFilePath&&d(f(this.workDir,u))===d(f(this.workDir,this.planFilePath))&&!this.sandbox.checkDenyWrite(u))return{effect:"allow",reason:"Plan file write allowed in plan mode"}}if(s==="command"&&se(r))return{effect:"allow",reason:"Safe read-only command"};let x=s==="command"?ee(r):"";if(x)return{effect:"deny",reason:`Dangerous command blocked: ${x}`};if(this.sandboxEnabled&&this.sandboxAutoAllow&&e==="Bash"){let u=c(t,"command").split(/\s*(?:&&|\|\||[;|])\s*/).map(w=>w.trim()).filter(Boolean),l=!1;for(let w of u){let R=h(o(),e,w);if(R==="deny")return{effect:"deny",reason:"Permission rule: deny"};R==="ask"&&(l=!0)}return l?{effect:"ask",reason:"Permission rule: ask (sandbox does not override)"}:{effect:"allow",reason:"Sandbox auto-allow: OS sandbox active"}}let b=c(t,"file_path",c(t,"path",""));if((s==="read"||s==="write")&&b){if(s==="write"){let l=this.sandbox.checkDenyWrite(b);if(l)return l}let u=this.sandbox.check(b);if(u&&this.mode!=="bypassPermissions"){let l=this.ruleEngine.evaluate(e,r);return l?{effect:l,reason:`Permission rule: ${l}`}:{effect:"ask",reason:u.reason}}}let $=h(o(),e,r);return $?{effect:$,reason:`Permission rule: ${$}`}:{effect:te(this.mode,s),reason:`Mode: ${this.mode}`}}allowExtraRoot(e){this.sandbox.addRoot(e)}allowAlways(e,s){let t=v(e,s),r=e==="ReadFile"||e==="WriteFile"||e==="EditFile",i;if(r&&t){let o=f(this.workDir,t),a=!1;try{a=z(o).isDirectory()}catch{}i=g(a?o:I(o),"*")}else i=t.trim().split(/\s+/).slice(0,2).join(" ")+"*";this.ruleEngine.appendProjectRule({tool:e,pattern:i,effect:"allow"})}describeToolAction(e,s){let t=v(e,s);if(t)return t;let r=[];for(let[i,o]of Object.entries(s)){let a=String(o);a.length>80&&(a=a.slice(0,80)+"..."),r.push(`${i}: ${a}`)}return r.join(", ")}};export{d as a,m as b,v as c,P as d,h as e,E as f,se as g,W as h};
|