@swifty.js/swifty 0.0.26 → 0.0.28
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 +14 -6
- package/dist/agent-3NON2EXE.js +4 -0
- package/dist/anthropic-BJ5GN2VT.js +4 -0
- package/dist/checker-N5TIJEN5.js +4 -0
- package/dist/{chunk-H7VXSMJR.js → chunk-C3WGLVVZ.js} +10 -10
- package/dist/chunk-D34FUVGU.js +4 -0
- package/dist/chunk-FPQ2LBL4.js +10 -0
- package/dist/chunk-JGSIQXEN.js +4 -0
- package/dist/{chunk-5KXBVL2A.js → chunk-K5ZK27BX.js} +1 -1
- package/dist/chunk-LZBOXJX2.js +301 -0
- package/dist/chunk-OTVZGPHD.js +121 -0
- package/dist/chunk-QCKJLO6X.js +4 -0
- package/dist/chunk-R63ASIIW.js +407 -0
- package/dist/chunk-WX3B64R4.js +4 -0
- package/dist/chunk-Y6SQB5FG.js +4 -0
- package/dist/{devtools-3OAJUZGE.js → devtools-OJ75EP3T.js} +1 -1
- package/dist/glob.wasm +0 -0
- package/dist/lib/agent-XYO2MXXK.js +11 -0
- package/dist/lib/{anthropic-RYPJDHQM.js → anthropic-TGJGAP5R.js} +4 -5
- package/dist/lib/{checker-6BW4222R.js → checker-AXHPKVBY.js} +2 -2
- package/dist/lib/{chunk-HK2Z6WP4.js → chunk-2IVEVG5N.js} +5 -1
- package/dist/lib/{chunk-2AUSNVIB.js → chunk-ALJAVRRX.js} +28 -34
- package/dist/lib/{chunk-GNI7YX6F.js → chunk-DJ6AILPN.js} +70 -24
- package/dist/lib/chunk-DV6RV5WU.js +2345 -0
- package/dist/lib/{chunk-3LU4APFB.js → chunk-FBSPZQGC.js} +126 -73
- package/dist/lib/chunk-IB5IQK2S.js +136 -0
- package/dist/lib/{chunk-PZ42NAFA.js → chunk-KG4MJGKQ.js} +19 -21
- package/dist/lib/{chunk-XFSN4LMA.js → chunk-P4F46PEF.js} +43 -14
- package/dist/lib/glob.wasm +0 -0
- package/dist/lib/index.d.ts +145 -123
- package/dist/lib/index.js +2186 -1726
- package/dist/lib/{openai-VX5VBXZ4.js → openai-5UCIIDPO.js} +2 -3
- package/dist/lib/{tool-filter-VF7TZRE5.js → tool-filter-R6HDDJHE.js} +1 -1
- package/dist/main.js +226 -196
- package/dist/{node-OES65R33.js → node-4LTSRXL2.js} +1 -1
- package/dist/{openai-6MXNADYN.js → openai-YLS2LUAI.js} +14 -14
- package/dist/server-GX72MJQF.js +244 -0
- package/dist/{tool-filter-NO7I3HFD.js → tool-filter-VBP6WOGO.js} +1 -1
- package/package.json +36 -32
- package/dist/agent-GAABBZRW.js +0 -4
- package/dist/anthropic-7QRAPLOY.js +0 -4
- package/dist/checker-3RWAYF2U.js +0 -4
- package/dist/chunk-7MHXMDYC.js +0 -35
- package/dist/chunk-A2VR3BC4.js +0 -4
- package/dist/chunk-FZPTNGTU.js +0 -4
- package/dist/chunk-MWZIARZE.js +0 -130
- package/dist/chunk-NR62AA5K.js +0 -4
- package/dist/chunk-QN27QEFS.js +0 -4
- package/dist/chunk-RMMK4PO5.js +0 -389
- package/dist/chunk-SIWLMWHH.js +0 -93
- package/dist/chunk-VC6OXOMP.js +0 -238
- package/dist/chunk-W37Y53LX.js +0 -4
- package/dist/chunk-XBHVVB5A.js +0 -10
- package/dist/lib/agent-U7MIUCKT.js +0 -9
- package/dist/lib/chunk-2QILP24G.js +0 -1120
- package/dist/lib/chunk-OO2CLOEE.js +0 -88
- package/dist/lib/chunk-RKJYTYQM.js +0 -1285
- package/dist/server-P2VE5HLJ.js +0 -244
|
@@ -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{D as n,I as S,b as g,c as _,d as b}from"./chunk-OTVZGPHD.js";import{existsSync as D,readFileSync as $}from"fs";import{homedir as L}from"os";import{join as h}from"path";function m(e){return!!e._zod}function l(e,o){return m(e)?g(e,o):e.safeParse(o)}async function pe(e,o){return m(e)?await _(e,o):await e.safeParseAsync(o)}function ue(e){if(!e)return;let o;if(m(e)?o=e._zod?.def?.shape:o=e.shape,!!o){if(typeof o=="function")try{return o()}catch{return}return o}}function de(e){if(m(e)){let i=e._zod?.def;if(i){if(i.value!==void 0)return i.value;if(Array.isArray(i.values)&&i.values.length>0)return i.values[0]}}let t=e._def;if(t){if(t.value!==void 0)return t.value;if(Array.isArray(t.values)&&t.values.length>0)return t.values[0]}let r=e.value;if(r!==void 0)return r}var w=S({module:"config"}),j={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY","openai-compat":"OPENAI_API_KEY"};function V(e){return y.has(e)}var y=new Set(Object.keys(j)),p=class extends Error{constructor(o){super(o),this.name="ConfigError"}},T=n.object({name:n.string(),protocol:n.enum(["anthropic","openai","openai-compat"]),base_url:n.string(),model:n.string(),api_key:n.string().optional(),thinking:n.boolean().optional(),context_window:n.coerce.number().optional(),max_output_tokens:n.coerce.number().optional()}),K=!0,k=1e6,P=128e3;function A(e){return{...e,thinking:e.thinking??K,context_window:Y(e),max_output_tokens:F(e)}}function Y(e){return Number.isSafeInteger(e.context_window)&&(e.context_window??0)>0?e.context_window??k:k}function F(e){return Number.isSafeInteger(e.max_output_tokens)&&(e.max_output_tokens??0)>0?e.max_output_tokens??P:P}function Se(e){if(e.api_key)return e.api_key;let o=V(e.protocol)?j[e.protocol]:"";return o?process.env[o]??"":""}var O=n.object({name:n.string(),command:n.string().optional(),args:n.array(n.string()).optional(),url:n.string().optional(),transport:n.string().optional(),headers:n.record(n.string(),n.string()).optional(),env:n.record(n.string(),n.string()).optional()}),M=n.object({id:n.string().optional(),event:n.string(),condition:n.string().optional(),action:n.object({type:n.string(),command:n.string().optional(),url:n.string().optional(),method:n.string().optional(),prompt:n.string().optional()}),reject:n.boolean().optional(),once:n.boolean().optional(),async:n.boolean().optional(),on_error:n.string().optional()}),z=n.object({enabled:n.boolean().optional(),auto_allow:n.boolean().optional(),network_enabled:n.boolean().optional()}),H=n.looseObject({providers:n.array(T),permission_mode:n.string().optional(),mcp_servers:n.array(O).default([]),hooks:n.array(M).default([]),sandbox:z.optional(),enable_coordinator_mode:n.boolean().optional(),enable_fork:n.boolean().optional()});function we(e){return e.enable_fork!==!1}function B(e){return typeof e=="object"&&e!==null}function C(e){let o=$(e,"utf-8"),t=b.load(o);if(!B(t))return w.error({path:e},"invalid yaml"),{providers:[],mcp_servers:[],hooks:[]};let r=l(H,t);if(r.success){let f=r.data;return{...f,providers:f.providers.map(A)}}w.error({error:r.error},"config error");let a=[],i,c=[],s=[],d,v=!1,x=!0;if("providers"in t){let f=l(n.array(T),t.providers);f.success&&(a=f.data.map(A))}if("permission_mode"in t&&typeof t.permission_mode=="string"&&(i=t.permission_mode),"mcp_servers"in t){let f=l(n.array(O),t.mcp_servers);f.success&&(c=f.data)}if("hooks"in t){let f=l(n.array(M),t.hooks);f.success&&(s=f.data)}if("sandbox"in t){let f=l(z,t.sandbox);f.success&&(d=f.data)}return"enable_coordinator_mode"in t&&(v=!!t.enable_coordinator_mode),"enable_fork"in t&&(x=!!t.enable_fork),{providers:a,permission_mode:i,mcp_servers:c,hooks:s,sandbox:d,enable_coordinator_mode:v,enable_fork:x}}function W(e,o){if(o.providers.length>0&&(e.providers=o.providers),o.permission_mode&&(e.permission_mode=o.permission_mode),o.mcp_servers.length>0){let t=new Map;for(let r=0;r<e.mcp_servers.length;r++){let a=e.mcp_servers[r];t.set(a.name,r)}for(let r of o.mcp_servers){let a=t.get(r.name);a!==void 0?e.mcp_servers[a]=r:(e.mcp_servers.push(r),t.set(r.name,e.mcp_servers.length-1))}}return e.hooks=[...e.hooks,...o.hooks],o.sandbox&&(e.sandbox={...e.sandbox,...o.sandbox}),o.enable_coordinator_mode&&(e.enable_coordinator_mode=!0),o.enable_fork!==void 0&&(e.enable_fork=o.enable_fork),e}function E(e){if(e.providers.length===0)throw new p("At least one provider MUST be configured.");let o=["name","protocol","base_url","model"];for(let t=0;t<e.providers.length;t++){let r=e.providers[t],a={name:r.name,protocol:r.protocol,base_url:r.base_url,model:r.model},i=o.filter(c=>!a[c].trim());if(i.length>0)throw new p(`Provider #${String(t+1)}: missing fields: ${i.join(", ")}`);if(!y.has(r.protocol))throw new p(`Provider #${String(t+1)}: invalid protocol '${r.protocol}', MUST be one of: ${Array.from(y).join(", ")}`)}}function ke(e,o={}){if(e){let c=C(e);return(!o.allowEmptyProviders||c.providers.length>0)&&E(c),c}let t=process.cwd(),r=L(),a=[h(r,".swifty","config.yaml"),h(t,".swifty","config.yaml"),h(t,".swifty","config.local.yaml")],i=null;for(let c of a){if(!D(c))continue;let s=C(c);i?i=W(i,s):i=s}if(!i){if(o.allowEmptyProviders)return{providers:[],mcp_servers:[],hooks:[]};throw new p("No config file found, expected .swifty/config.y(a)ml under project or $HOME/.swifty/config.y(a)ml.")}return(!o.allowEmptyProviders||i.providers.length>0)&&E(i),i}var u=class extends Error{constructor(o){super(o),this.name="LLMError"}},I=class extends u{constructor(o){super(o),this.name="AuthenticationError"}},R=class extends u{retryAfter;constructor(o,t){super(o),this.name="RateLimitError",this.retryAfter=t}},N=class extends u{constructor(o){super(o),this.name="NetworkError"}},U=class extends u{constructor(o){super(o),this.name="ContextTooLongError"}};var Z="Tool execution was interrupted. The tool may or may not have completed; verify before relying on its effects.",Ce="The user rejected this tool use. Nothing was changed (for file edits, the new content was NOT written).";function Ee(e){let o=[];for(let t=0;t<e.length;t++){let r=e[t];if(r.role==="assistant"&&r.toolUses?.length){o.push(r);let a=new Set(r.toolUses.map(s=>s.toolUseId)),i=[],c=[];for(;t+1<e.length;){let s=e[t+1];if(s.role!=="user"||!s.toolResults?.length||s.toolUses?.length)break;t++,c.push(s);for(let d of s.toolResults)a.delete(d.toolUseId)&&i.push(d)}for(let s of a)i.push({toolUseId:s,content:Z,isError:!0});o.push({...c[0]??{role:"user",content:""},toolResults:i});for(let s of c.slice(1))(s.content.length>0||s.thinkingBlocks?.length)&&o.push({...s,toolResults:[]});continue}if((r.toolResults?.length??0)>0){if(r.content.length===0&&!r.toolUses?.length&&!r.thinkingBlocks?.length)continue;o.push({...r,toolResults:[]})}else o.push(r)}return o}export{l as a,pe as b,ue as c,de as d,T as e,K as f,k as g,P as h,Y as i,F as j,Se as k,we as l,ke as m,u as n,I as o,R as p,N as q,U as r,Ce as s,Ee as t};
|
|
@@ -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{a as T,b as f}from"./chunk-E55KH72M.js";var c=class{tools=new Map;discovered=new Set;mcpLoadingMode="eager";exposeToolSearch=!1;exposeMcpCall=!1;register(e){this.tools.set(e.name,e)}get(e){return this.tools.get(e)}listTools(){return[...this.tools.values()]}getAllSchemas(e="anthropic"){let o=e==="openai"||e==="openai-compat",t=this.mcpLoadingMode==="native"&&!o,n=[];for(let s of this.tools.values()){if(s.name===T&&!this.exposeToolSearch||s.name===f&&!this.exposeMcpCall)continue;let a=!!s.deferred&&!this.discovered.has(s.name);if(a&&!t)continue;let r=s.schema();o?n.push({strict:!1,type:"function",name:r.name,description:r.description,parameters:r.input_schema,function:{name:r.name,description:r.description,parameters:r.input_schema}}):n.push(a?{...r,type:"custom",defer_loading:!0}:{...r,type:"custom"})}return n}getDeferredToolNames(){let e=[];for(let o of this.tools.values())o.deferred&&!this.discovered.has(o.name)&&e.push(o.name);return e.sort()}getDeferredTools(){return[...this.tools.values()].filter(e=>e.deferred&&!this.discovered.has(e.name))}searchDeferred(e,o=5){let t=e.toLowerCase(),n=[];for(let s of this.tools.values())if(!(!s.deferred||this.discovered.has(s.name))&&(s.name.toLowerCase().includes(t)||s.description.toLowerCase().includes(t))&&(n.push(s),n.length>=o))break;return n}findDeferredByNames(e){let o=new Map;for(let[t,n]of this.tools)o.set(t.toLowerCase(),n);return e.map(t=>o.get(t.toLowerCase())).filter(t=>t?.deferred??!1)}markDiscovered(e){this.discovered.add(e)}isDiscovered(e){return this.discovered.has(e)}};var h=new Set(["ExitPlanMode","Agent","AskUserQuestion","TaskStop"]),M=new Set(["TeamCreate","TeamDelete"]),m=new Set(["ExitPlanMode","Agent","AskUserQuestion","TaskStop"]),u=new Set(["ReadFile","Grep","Glob","Bash","PowerShell","EditFile","WriteFile","LoadSkill","SyntheticOutput","ToolSearch","EnterWorktree","ExitWorktree","McpCall"]);function g(i){return i.startsWith("mcp__")}function w(i,e,o,t,n=!1){let s=new Set(o??[]),a=new Set(e??[]),r=a.size>0&&!(a.size===1&&a.has("*")),p=new c;p.mcpLoadingMode=i.mcpLoadingMode;for(let d of i.listTools()){let l=d.name;if(g(l)){!s.has(l)&&(!r||a.has(l))&&p.register(d);continue}h.has(l)||n&&m.has(l)||t&&!u.has(l)||s.has(l)||r&&!a.has(l)||p.register(d)}return p}var A="agent:builtin:fork";function k(i){let e=new c;e.mcpLoadingMode=i.mcpLoadingMode;for(let o of i.listTools())if(o.name==="Agent"&&"querySource"in o){let t=Object.create(Object.getPrototypeOf(o),Object.getOwnPropertyDescriptors(o));t.querySource=A,e.register(t)}else e.register(o);return e}export{c as a,h as b,M as c,m as d,u as e,w as f,A as g,k as h};
|
|
@@ -1,7 +1,7 @@
|
|
|
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 t}from"./chunk-
|
|
4
|
+
import{c as t}from"./chunk-FPQ2LBL4.js";import"./chunk-X3UA5OZL.js";var n=globalThis;n.WebSocket||=t;n.window||=globalThis;n.self||=globalThis;n.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__=[{type:1,value:7,isEnabled:!0},{type:2,value:"InternalApp",isEnabled:!0,isValid:!0},{type:2,value:"InternalAppContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalStdoutContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalStderrContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalStdinContext",isEnabled:!0,isValid:!0},{type:2,value:"InternalFocusContext",isEnabled:!0,isValid:!0}];import a from"react-devtools-core";var l=async()=>new Promise(o=>{let e=new t("ws://localhost:8097"),i=setTimeout(()=>{e.terminate(),o(!1)},2e3);i.unref(),e.on("open",()=>{clearTimeout(i),e.terminate(),o(!0)}),e.on("error",()=>{clearTimeout(i),e.terminate(),o(!1)})});await l()?(a.initialize(),a.connectToDevTools()):console.warn(`DEV is set to true, but the React DevTools server is not running. Start it with:
|
|
5
5
|
|
|
6
6
|
$ npx react-devtools
|
|
7
7
|
`);
|
package/dist/glob.wasm
CHANGED
|
Binary file
|
|
@@ -5,11 +5,10 @@ import {
|
|
|
5
5
|
markLastUserTailForCache,
|
|
6
6
|
markToolsForCache,
|
|
7
7
|
needsToolSearchBeta
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-PZ42NAFA.js";
|
|
8
|
+
} from "./chunk-ALJAVRRX.js";
|
|
9
|
+
import "./chunk-IB5IQK2S.js";
|
|
10
|
+
import "./chunk-FBSPZQGC.js";
|
|
11
|
+
import "./chunk-KG4MJGKQ.js";
|
|
13
12
|
import "./chunk-EY7HE52Q.js";
|
|
14
13
|
import "./chunk-GHF2PSEW.js";
|
|
15
14
|
export {
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
evaluateRules,
|
|
6
6
|
extractContent,
|
|
7
7
|
isSafeCommand
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-DJ6AILPN.js";
|
|
9
|
+
import "./chunk-KG4MJGKQ.js";
|
|
10
10
|
import "./chunk-EY7HE52Q.js";
|
|
11
11
|
import "./chunk-GHF2PSEW.js";
|
|
12
12
|
export {
|
|
@@ -167,10 +167,13 @@ function filterToolsForAgent(registry, allowedTools, disallowedTools, isAsync, i
|
|
|
167
167
|
const allowed = new Set(allowedTools ?? []);
|
|
168
168
|
const hasWhitelist = allowed.size > 0 && !(allowed.size === 1 && allowed.has("*"));
|
|
169
169
|
const filtered = new ToolRegistry();
|
|
170
|
+
filtered.mcpLoadingMode = registry.mcpLoadingMode;
|
|
170
171
|
for (const tool of registry.listTools()) {
|
|
171
172
|
const name = tool.name;
|
|
172
173
|
if (isMCPTool(name)) {
|
|
173
|
-
|
|
174
|
+
if (!disallowed.has(name) && (!hasWhitelist || allowed.has(name))) {
|
|
175
|
+
filtered.register(tool);
|
|
176
|
+
}
|
|
174
177
|
continue;
|
|
175
178
|
}
|
|
176
179
|
if (SUBAGENT_DISALLOWED_TOOLS.has(name)) {
|
|
@@ -195,6 +198,7 @@ function filterToolsForAgent(registry, allowedTools, disallowedTools, isAsync, i
|
|
|
195
198
|
var FORK_QUERY_SOURCE = "agent:builtin:fork";
|
|
196
199
|
function cloneRegistryForFork(registry) {
|
|
197
200
|
const forked = new ToolRegistry();
|
|
201
|
+
forked.mcpLoadingMode = registry.mcpLoadingMode;
|
|
198
202
|
for (const tool of registry.listTools()) {
|
|
199
203
|
if (tool.name === "Agent" && "querySource" in tool) {
|
|
200
204
|
const clone = Object.create(
|
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import {
|
|
5
|
-
getContextWindow,
|
|
6
|
-
getMaxOutputTokens,
|
|
7
|
-
resolveAPIKey
|
|
8
|
-
} from "./chunk-3LU4APFB.js";
|
|
2
|
+
normalizeToolResultContentBlock
|
|
3
|
+
} from "./chunk-IB5IQK2S.js";
|
|
9
4
|
import {
|
|
10
5
|
AuthenticationError,
|
|
11
6
|
ContextTooLongError,
|
|
7
|
+
DEFAULT_PROVIDER_THINKING,
|
|
12
8
|
LLMError,
|
|
13
9
|
NetworkError,
|
|
14
10
|
RateLimitError,
|
|
15
|
-
ensureToolPairing
|
|
16
|
-
|
|
11
|
+
ensureToolPairing,
|
|
12
|
+
getMaxOutputTokens,
|
|
13
|
+
resolveAPIKey
|
|
14
|
+
} from "./chunk-FBSPZQGC.js";
|
|
17
15
|
import {
|
|
18
16
|
MCP_TOOL_PREFIX,
|
|
19
17
|
isMcpToolLike
|
|
20
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KG4MJGKQ.js";
|
|
21
19
|
import {
|
|
22
20
|
asErrorString,
|
|
23
21
|
asRecord,
|
|
24
22
|
asString,
|
|
25
23
|
contentToText,
|
|
26
24
|
createChildLogger,
|
|
27
|
-
isRecord
|
|
25
|
+
isRecord,
|
|
26
|
+
strArg
|
|
28
27
|
} from "./chunk-EY7HE52Q.js";
|
|
29
28
|
|
|
30
29
|
// src/llm/anthropic.ts
|
|
@@ -152,14 +151,17 @@ async function fetchModelContextWindow(config) {
|
|
|
152
151
|
clearTimeout(timer);
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
|
-
function supportsAdaptiveThinking() {
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
154
|
function userBlocksFor(content) {
|
|
159
155
|
if (typeof content === "string") {
|
|
160
156
|
return [{ type: "text", text: content }];
|
|
161
157
|
}
|
|
162
|
-
return content
|
|
158
|
+
return content.map((raw) => {
|
|
159
|
+
const block = normalizeToolResultContentBlock(raw);
|
|
160
|
+
if (!block || block.type === "tool_reference") {
|
|
161
|
+
throw new Error(`Unsupported user content block: ${strArg(raw, "type", "unknown")}`);
|
|
162
|
+
}
|
|
163
|
+
return block;
|
|
164
|
+
});
|
|
163
165
|
}
|
|
164
166
|
function buildAnthropicMessages(messages) {
|
|
165
167
|
const result = [];
|
|
@@ -208,6 +210,9 @@ function buildAnthropicMessages(messages) {
|
|
|
208
210
|
content: tr.contentBlocks?.length ? tr.contentBlocks : tr.content
|
|
209
211
|
});
|
|
210
212
|
}
|
|
213
|
+
if (m.content.length > 0) {
|
|
214
|
+
blocks.push(...userBlocksFor(m.content));
|
|
215
|
+
}
|
|
211
216
|
result.push({ role: "user", content: blocks });
|
|
212
217
|
} else {
|
|
213
218
|
if (result.length === 0) {
|
|
@@ -254,7 +259,6 @@ var AnthropicClient = class {
|
|
|
254
259
|
systemPrompt;
|
|
255
260
|
maxOutputTokens;
|
|
256
261
|
/** Currently not used */
|
|
257
|
-
contextWindow;
|
|
258
262
|
constructor(config, systemPrompt) {
|
|
259
263
|
const apiKey = resolveAPIKey(config);
|
|
260
264
|
if (!apiKey) {
|
|
@@ -267,10 +271,9 @@ var AnthropicClient = class {
|
|
|
267
271
|
baseURL: config.base_url
|
|
268
272
|
});
|
|
269
273
|
this.model = config.model;
|
|
270
|
-
this.thinking = config.thinking ??
|
|
274
|
+
this.thinking = config.thinking ?? DEFAULT_PROVIDER_THINKING;
|
|
271
275
|
this.systemPrompt = systemPrompt;
|
|
272
276
|
this.maxOutputTokens = getMaxOutputTokens(config);
|
|
273
|
-
this.contextWindow = getContextWindow(config);
|
|
274
277
|
}
|
|
275
278
|
setSystemPrompt(prompt) {
|
|
276
279
|
this.systemPrompt = prompt;
|
|
@@ -316,19 +319,7 @@ var AnthropicClient = class {
|
|
|
316
319
|
messages,
|
|
317
320
|
...antToolSchemas.length > 0 ? { tools: antToolSchemas } : {}
|
|
318
321
|
};
|
|
319
|
-
|
|
320
|
-
if (supportsAdaptiveThinking()) {
|
|
321
|
-
params.thinking = {
|
|
322
|
-
type: "enabled",
|
|
323
|
-
budget_tokens: computeCompactThreshold(this.contextWindow, this.maxOutputTokens)
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
params.thinking = {
|
|
328
|
-
type: "enabled",
|
|
329
|
-
budget_tokens: computeCompactThreshold(this.contextWindow, this.maxOutputTokens)
|
|
330
|
-
};
|
|
331
|
-
}
|
|
322
|
+
params.thinking = this.thinking && this.maxOutputTokens > 1024 ? { type: "enabled", budget_tokens: Math.min(16384, this.maxOutputTokens - 1) } : { type: "disabled" };
|
|
332
323
|
let inputTokens = 0;
|
|
333
324
|
let outputTokens = 0;
|
|
334
325
|
let cacheReadInputTokens = 0;
|
|
@@ -377,7 +368,7 @@ var AnthropicClient = class {
|
|
|
377
368
|
text: delta.thinking
|
|
378
369
|
};
|
|
379
370
|
} else if (delta.type === "signature_delta") {
|
|
380
|
-
thinkingSignature
|
|
371
|
+
thinkingSignature += delta.signature;
|
|
381
372
|
} else if (delta.type === "text_delta") {
|
|
382
373
|
yield {
|
|
383
374
|
type: "text_delta",
|
|
@@ -497,6 +488,7 @@ function markLastUserTailForCache(messages) {
|
|
|
497
488
|
Reflect.set(last, "cache_control", {
|
|
498
489
|
type: "ephemeral"
|
|
499
490
|
});
|
|
491
|
+
return;
|
|
500
492
|
}
|
|
501
493
|
}
|
|
502
494
|
function classifyAnthropicError(err) {
|
|
@@ -508,14 +500,16 @@ function classifyAnthropicError(err) {
|
|
|
508
500
|
return new AuthenticationError(`Invalid API key: ${err.message}`);
|
|
509
501
|
}
|
|
510
502
|
if (err.status === 429 /* RateLimitError */) {
|
|
511
|
-
const
|
|
503
|
+
const headers = err.headers;
|
|
504
|
+
const retryAfter = headers instanceof Headers ? headers.get("retry-after") : void 0;
|
|
512
505
|
let message = "Rate Limited";
|
|
513
506
|
if (retryAfter) {
|
|
514
507
|
const s = Number.parseInt(asString(retryAfter));
|
|
515
508
|
if (Number.isNaN(s)) {
|
|
516
509
|
message += ", please wait.";
|
|
510
|
+
} else {
|
|
511
|
+
message += `, retry after ${asString(s)}s.`;
|
|
517
512
|
}
|
|
518
|
-
message += `, retry after ${asString(s)}s.`;
|
|
519
513
|
} else {
|
|
520
514
|
message += ", please wait.";
|
|
521
515
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mcpCallPermissionContent
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KG4MJGKQ.js";
|
|
4
4
|
import {
|
|
5
5
|
createChildLogger,
|
|
6
6
|
strArg
|
|
@@ -12,9 +12,38 @@ import {
|
|
|
12
12
|
// src/permissions/checker.ts
|
|
13
13
|
import { readFileSync, writeFileSync, mkdirSync, statSync } from "fs";
|
|
14
14
|
import { homedir, tmpdir } from "os";
|
|
15
|
-
import { join, resolve, dirname } from "path";
|
|
15
|
+
import { join as join2, resolve as resolve2, dirname as dirname2 } from "path";
|
|
16
16
|
import yaml from "js-yaml";
|
|
17
17
|
import z, { parse } from "zod";
|
|
18
|
+
|
|
19
|
+
// src/utils/paths.ts
|
|
20
|
+
import { realpathSync } from "fs";
|
|
21
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "path";
|
|
22
|
+
function canonicalPath(path) {
|
|
23
|
+
let current = resolve(path);
|
|
24
|
+
const missing = [];
|
|
25
|
+
for (; ; ) {
|
|
26
|
+
try {
|
|
27
|
+
return join(realpathSync(current), ...missing);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT" && error.code !== "ENOTDIR") {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
const parent = dirname(current);
|
|
33
|
+
if (parent === current) {
|
|
34
|
+
return resolve(path);
|
|
35
|
+
}
|
|
36
|
+
missing.unshift(basename(current));
|
|
37
|
+
current = parent;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isPathWithin(root, path) {
|
|
42
|
+
const child = relative(root, path);
|
|
43
|
+
return child === "" || child !== ".." && !child.startsWith(`..${sep}`) && !isAbsolute(child);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/permissions/checker.ts
|
|
18
47
|
var log = createChildLogger({ module: "permissions" });
|
|
19
48
|
var DANGEROUS_PATTERNS = [];
|
|
20
49
|
var SAFE_PREFIXES = [
|
|
@@ -56,7 +85,8 @@ var CONTENT_FIELDS = {
|
|
|
56
85
|
WriteFile: "file_path",
|
|
57
86
|
EditFile: "file_path",
|
|
58
87
|
Glob: "pattern",
|
|
59
|
-
Grep: "pattern"
|
|
88
|
+
Grep: "pattern",
|
|
89
|
+
InstallSkill: "source"
|
|
60
90
|
};
|
|
61
91
|
var DEFAULT_DENY_WRITE = [
|
|
62
92
|
".swifty/config.yaml",
|
|
@@ -79,25 +109,26 @@ var PathSandbox = class {
|
|
|
79
109
|
denyWritePaths;
|
|
80
110
|
projectDir;
|
|
81
111
|
constructor(projectDir) {
|
|
82
|
-
this.projectDir =
|
|
112
|
+
this.projectDir = resolve2(projectDir);
|
|
83
113
|
this.allowedRoots = [this.projectDir, tmpdir()];
|
|
84
|
-
this.denyWritePaths = DEFAULT_DENY_WRITE.map((p) =>
|
|
114
|
+
this.denyWritePaths = DEFAULT_DENY_WRITE.map((p) => join2(this.projectDir, p));
|
|
85
115
|
}
|
|
86
116
|
addRoot(root) {
|
|
87
|
-
this.allowedRoots.push(
|
|
117
|
+
this.allowedRoots.push(resolve2(root));
|
|
88
118
|
}
|
|
89
119
|
// Add custom deny-write paths
|
|
90
120
|
addDenyWrite(path) {
|
|
91
|
-
this.denyWritePaths.push(
|
|
121
|
+
this.denyWritePaths.push(resolve2(path));
|
|
92
122
|
}
|
|
93
123
|
/**
|
|
94
124
|
* Check whether a path is in the deny-write list.
|
|
95
125
|
* denyWrite has the highest priority — even if the path is within an allowed root, writes are still denied.
|
|
96
126
|
*/
|
|
97
127
|
checkDenyWrite(filePath) {
|
|
98
|
-
const absolute =
|
|
128
|
+
const absolute = resolve2(this.projectDir, filePath);
|
|
129
|
+
const canonical = canonicalPath(absolute);
|
|
99
130
|
for (const denied of this.denyWritePaths) {
|
|
100
|
-
if (absolute
|
|
131
|
+
if (isPathWithin(denied, absolute) || isPathWithin(canonicalPath(denied), canonical)) {
|
|
101
132
|
return {
|
|
102
133
|
effect: "deny",
|
|
103
134
|
reason: `Path ${filePath} is in deny-write list`
|
|
@@ -107,9 +138,9 @@ var PathSandbox = class {
|
|
|
107
138
|
return null;
|
|
108
139
|
}
|
|
109
140
|
check(filePath) {
|
|
110
|
-
const absolute =
|
|
141
|
+
const absolute = canonicalPath(resolve2(this.projectDir, filePath));
|
|
111
142
|
for (const root of this.allowedRoots) {
|
|
112
|
-
if (
|
|
143
|
+
if (isPathWithin(canonicalPath(root), absolute)) {
|
|
113
144
|
return null;
|
|
114
145
|
}
|
|
115
146
|
}
|
|
@@ -190,9 +221,9 @@ var RuleEngine = class {
|
|
|
190
221
|
localPath;
|
|
191
222
|
cache = /* @__PURE__ */ new Map();
|
|
192
223
|
constructor(workDir) {
|
|
193
|
-
this.userPath =
|
|
194
|
-
this.projectPath =
|
|
195
|
-
this.localPath =
|
|
224
|
+
this.userPath = join2(homedir(), ".swifty", "permissions.yaml");
|
|
225
|
+
this.projectPath = join2(workDir, ".swifty", "permissions.yaml");
|
|
226
|
+
this.localPath = join2(workDir, ".swifty", "permissions.local.yaml");
|
|
196
227
|
}
|
|
197
228
|
// Read a single rules file; skips disk I/O and parsing on cache hit.
|
|
198
229
|
rulesFor(path) {
|
|
@@ -229,7 +260,7 @@ var RuleEngine = class {
|
|
|
229
260
|
// Persists a rule to the project-local YAML file in the `Tool(pattern)`
|
|
230
261
|
// format so "allow always" survives a restart.
|
|
231
262
|
appendLocalRule(rule) {
|
|
232
|
-
mkdirSync(
|
|
263
|
+
mkdirSync(dirname2(this.localPath), { recursive: true });
|
|
233
264
|
const rules = loadRulesFile(this.localPath);
|
|
234
265
|
const exists = rules.some(
|
|
235
266
|
(r) => r.tool === rule.tool && r.pattern === rule.pattern && r.effect === rule.effect
|
|
@@ -255,7 +286,7 @@ function detectDangerous(command) {
|
|
|
255
286
|
}
|
|
256
287
|
function isSafeCommand(command) {
|
|
257
288
|
const trimmed = command.trim();
|
|
258
|
-
if (trimmed.includes(">") || trimmed.includes("|") || trimmed.includes(";") || trimmed.includes("&&") || trimmed.includes("$(") || trimmed.includes("`")) {
|
|
289
|
+
if (trimmed.includes(">") || trimmed.includes("<") || /[\r\n&]/.test(trimmed) || trimmed.includes("|") || trimmed.includes(";") || trimmed.includes("&&") || trimmed.includes("$(") || trimmed.includes("`")) {
|
|
259
290
|
return false;
|
|
260
291
|
}
|
|
261
292
|
return SAFE_PREFIXES.some(
|
|
@@ -275,7 +306,14 @@ function modeDecide(mode, category) {
|
|
|
275
306
|
return category === "read" ? "allow" : "ask";
|
|
276
307
|
}
|
|
277
308
|
}
|
|
278
|
-
var PermissionChecker = class {
|
|
309
|
+
var PermissionChecker = class _PermissionChecker {
|
|
310
|
+
constructor(workDir, mode = "default") {
|
|
311
|
+
this.workDir = workDir;
|
|
312
|
+
this.mode = mode;
|
|
313
|
+
this.sandbox = new PathSandbox(workDir);
|
|
314
|
+
this.ruleEngine = new RuleEngine(workDir);
|
|
315
|
+
}
|
|
316
|
+
workDir;
|
|
279
317
|
mode;
|
|
280
318
|
planFilePath = "";
|
|
281
319
|
// Sandbox mode: when enabled, command-category tools run through OS sandbox isolation, with optional auto-allow
|
|
@@ -283,18 +321,24 @@ var PermissionChecker = class {
|
|
|
283
321
|
sandboxAutoAllow = false;
|
|
284
322
|
sandbox;
|
|
285
323
|
ruleEngine;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
324
|
+
forWorkDir(workDir) {
|
|
325
|
+
const checker = new _PermissionChecker(workDir, this.mode);
|
|
326
|
+
checker.ruleEngine = this.ruleEngine;
|
|
327
|
+
checker.sandboxEnabled = this.sandboxEnabled;
|
|
328
|
+
checker.sandboxAutoAllow = this.sandboxAutoAllow;
|
|
329
|
+
return checker;
|
|
290
330
|
}
|
|
291
331
|
check(toolName, category, args) {
|
|
292
332
|
const content = extractContent(toolName, args);
|
|
293
333
|
let snapshot = null;
|
|
294
334
|
const rules = () => snapshot ??= this.ruleEngine.snapshot();
|
|
335
|
+
const explicitEffect = evaluateRules(rules(), toolName, content);
|
|
336
|
+
if (explicitEffect === "deny" || explicitEffect === "ask") {
|
|
337
|
+
return { effect: explicitEffect, reason: `Permission rule: ${explicitEffect}` };
|
|
338
|
+
}
|
|
295
339
|
if (this.mode === "plan" && (toolName === "WriteFile" || toolName === "EditFile")) {
|
|
296
340
|
const path = strArg(args, "file_path", "");
|
|
297
|
-
if (
|
|
341
|
+
if (this.planFilePath && canonicalPath(resolve2(this.workDir, path)) === canonicalPath(resolve2(this.workDir, this.planFilePath)) && !this.sandbox.checkDenyWrite(path)) {
|
|
298
342
|
return {
|
|
299
343
|
effect: "allow",
|
|
300
344
|
reason: "Plan file write allowed in plan mode"
|
|
@@ -377,13 +421,13 @@ var PermissionChecker = class {
|
|
|
377
421
|
const isFilePath = toolName === "ReadFile" || toolName === "WriteFile" || toolName === "EditFile";
|
|
378
422
|
let pattern;
|
|
379
423
|
if (isFilePath && content) {
|
|
380
|
-
const abs =
|
|
424
|
+
const abs = resolve2(this.workDir, content);
|
|
381
425
|
let isDir = false;
|
|
382
426
|
try {
|
|
383
427
|
isDir = statSync(abs).isDirectory();
|
|
384
428
|
} catch {
|
|
385
429
|
}
|
|
386
|
-
pattern =
|
|
430
|
+
pattern = join2(isDir ? abs : dirname2(abs), "*");
|
|
387
431
|
} else {
|
|
388
432
|
const words = content.trim().split(/\s+/).slice(0, 2);
|
|
389
433
|
pattern = words.join(" ") + "*";
|
|
@@ -417,6 +461,8 @@ var PermissionChecker = class {
|
|
|
417
461
|
};
|
|
418
462
|
|
|
419
463
|
export {
|
|
464
|
+
canonicalPath,
|
|
465
|
+
isPathWithin,
|
|
420
466
|
extractContent,
|
|
421
467
|
PathSandbox,
|
|
422
468
|
evaluateRules,
|