@swifty.js/swifty 0.0.21 → 0.0.23

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 (42) hide show
  1. package/dist/{agent-ZCMBUWLZ.js → agent-RABW3Z3R.js} +1 -1
  2. package/dist/anthropic-V22T6E6E.js +4 -0
  3. package/dist/{checker-OJFS2MZY.js → checker-3RWAYF2U.js} +1 -1
  4. package/dist/{chunk-Y5WGBAGP.js → chunk-5KXBVL2A.js} +1 -1
  5. package/dist/{chunk-MUPVOATV.js → chunk-CV7OKXYC.js} +1 -1
  6. package/dist/chunk-MJR2C7S7.js +130 -0
  7. package/dist/{chunk-GUXBLUNR.js → chunk-NR62AA5K.js} +1 -1
  8. package/dist/{chunk-S6ZADC7C.js → chunk-OCQ6TYLT.js} +21 -20
  9. package/dist/chunk-QN27QEFS.js +4 -0
  10. package/dist/{chunk-LX2LK3TF.js → chunk-SIWLMWHH.js} +12 -11
  11. package/dist/chunk-Y43POSIW.js +389 -0
  12. package/dist/lib/agent-GHXYOARN.js +9 -0
  13. package/dist/lib/anthropic-7YEN2QTU.js +22 -0
  14. package/dist/lib/bwrap-QRGPUP4J.js +6 -0
  15. package/dist/lib/checker-6BW4222R.js +19 -0
  16. package/dist/lib/chunk-7IZEK7X5.js +545 -0
  17. package/dist/lib/chunk-BN4Q54G2.js +1096 -0
  18. package/dist/lib/chunk-BO76JDFZ.js +617 -0
  19. package/dist/lib/chunk-CYDNMEBC.js +339 -0
  20. package/dist/lib/chunk-EY7HE52Q.js +384 -0
  21. package/dist/lib/chunk-GHF2PSEW.js +8 -0
  22. package/dist/lib/chunk-GNI7YX6F.js +426 -0
  23. package/dist/lib/chunk-HK2Z6WP4.js +223 -0
  24. package/dist/lib/chunk-MF3YLQDS.js +1277 -0
  25. package/dist/lib/chunk-OO2CLOEE.js +88 -0
  26. package/dist/lib/chunk-ORSYNBMM.js +38 -0
  27. package/dist/lib/chunk-PZ42NAFA.js +242 -0
  28. package/dist/lib/chunk-VUD72RTY.js +39 -0
  29. package/dist/lib/glob.wasm +0 -0
  30. package/dist/lib/index.d.ts +5347 -0
  31. package/dist/lib/index.js +11990 -0
  32. package/dist/lib/openai-RDHZFJUT.js +15 -0
  33. package/dist/lib/seatbelt-FT5IY73W.js +6 -0
  34. package/dist/lib/tool-filter-VF7TZRE5.js +19 -0
  35. package/dist/main.js +204 -466
  36. package/dist/{openai-HXD52MZB.js → openai-6NWVJ5LI.js} +15 -15
  37. package/dist/{server-VMHWEO2Y.js → server-KQTLAXC6.js} +17 -17
  38. package/package.json +18 -6
  39. package/dist/anthropic-4ZVG7AMA.js +0 -4
  40. package/dist/chunk-6E6UA7MT.js +0 -126
  41. package/dist/chunk-DDBH5AEN.js +0 -386
  42. package/dist/chunk-ZZQE743W.js +0 -4
@@ -0,0 +1,88 @@
1
+ // src/llm/errors.ts
2
+ var LLMError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "LLMError";
6
+ }
7
+ };
8
+ var AuthenticationError = class extends LLMError {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "AuthenticationError";
12
+ }
13
+ };
14
+ var RateLimitError = class extends LLMError {
15
+ retryAfter;
16
+ constructor(message, retryAfter) {
17
+ super(message);
18
+ this.name = "RateLimitError";
19
+ this.retryAfter = retryAfter;
20
+ }
21
+ };
22
+ var NetworkError = class extends LLMError {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = "NetworkError";
26
+ }
27
+ };
28
+ var ContextTooLongError = class extends LLMError {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = "ContextTooLongError";
32
+ }
33
+ };
34
+
35
+ // src/conversation/pairing.ts
36
+ var INTERRUPTED_TOOL_RESULT = "Tool execution was interrupted. The tool may or may not have completed; verify before relying on its effects.";
37
+ var REJECTED_TOOL_RESULT = "The user rejected this tool use. Nothing was changed (for file edits, the new content was NOT written).";
38
+ function ensureToolPairing(messages) {
39
+ const resolved = /* @__PURE__ */ new Set();
40
+ const issued = /* @__PURE__ */ new Set();
41
+ for (const m of messages) {
42
+ for (const tr of m.toolResults ?? []) {
43
+ resolved.add(tr.toolUseId);
44
+ }
45
+ for (const tu of m.toolUses ?? []) {
46
+ issued.add(tu.toolUseId);
47
+ }
48
+ }
49
+ const out = [];
50
+ for (const m of messages) {
51
+ let current = m;
52
+ if ((m.toolResults?.length ?? 0) > 0) {
53
+ const kept = (m.toolResults ?? []).filter((tr) => issued.has(tr.toolUseId));
54
+ if (kept.length === 0 && !m.content && !(m.toolUses?.length ?? 0)) {
55
+ continue;
56
+ }
57
+ current = { ...m, toolResults: kept };
58
+ }
59
+ out.push(current);
60
+ const missing = [];
61
+ for (const tu of m.toolUses ?? []) {
62
+ if (resolved.has(tu.toolUseId)) {
63
+ continue;
64
+ }
65
+ missing.push({
66
+ toolUseId: tu.toolUseId,
67
+ content: INTERRUPTED_TOOL_RESULT,
68
+ isError: true
69
+ });
70
+ resolved.add(tu.toolUseId);
71
+ }
72
+ if (missing.length > 0) {
73
+ out.push({ role: "user", content: "", toolResults: missing });
74
+ }
75
+ }
76
+ return out;
77
+ }
78
+
79
+ export {
80
+ LLMError,
81
+ AuthenticationError,
82
+ RateLimitError,
83
+ NetworkError,
84
+ ContextTooLongError,
85
+ INTERRUPTED_TOOL_RESULT,
86
+ REJECTED_TOOL_RESULT,
87
+ ensureToolPairing
88
+ };
@@ -0,0 +1,38 @@
1
+ // src/sandbox/bwrap.ts
2
+ import { execSync } from "child_process";
3
+ var BwrapSandbox = class {
4
+ available() {
5
+ try {
6
+ execSync("which bwrap", { stdio: "ignore" });
7
+ return true;
8
+ } catch {
9
+ return false;
10
+ }
11
+ }
12
+ wrap(command, config) {
13
+ const args = [];
14
+ args.push("bwrap", "--unshare-user", "--unshare-pid");
15
+ args.push("--ro-bind", "/", "/");
16
+ for (const path of config.allowWrite) {
17
+ args.push("--bind", path, path);
18
+ }
19
+ for (const path of config.denyWrite) {
20
+ args.push("--ro-bind", path, path);
21
+ }
22
+ if (!config.networkEnabled) {
23
+ args.push("--unshare-net");
24
+ }
25
+ args.push("--proc", "/proc");
26
+ args.push("--", "bash", "-c", command);
27
+ return args.map((arg) => {
28
+ if (/[ \t\n"'\\$`!]/.test(arg)) {
29
+ return `'${arg.replace(/'/g, "'\\''")}'`;
30
+ }
31
+ return arg;
32
+ }).join(" ");
33
+ }
34
+ };
35
+
36
+ export {
37
+ BwrapSandbox
38
+ };
@@ -0,0 +1,242 @@
1
+ import {
2
+ asErrorString,
3
+ asRecord,
4
+ createChildLogger,
5
+ strArg
6
+ } from "./chunk-EY7HE52Q.js";
7
+ import {
8
+ MCP_CALL_TOOL_NAME
9
+ } from "./chunk-GHF2PSEW.js";
10
+
11
+ // src/mcp/tool-wrapper.ts
12
+ var log = createChildLogger({ module: "mcp" });
13
+ var MCP_TOOL_PREFIX = "mcp__";
14
+ var MCP_NAME_SEP = "__";
15
+ function sanitizeSegment(s) {
16
+ return s.replace(/[^a-zA-Z0-9_]/g, "_");
17
+ }
18
+ function mcpToolNamePrefix(serverName) {
19
+ return MCP_TOOL_PREFIX + sanitizeSegment(serverName) + MCP_NAME_SEP;
20
+ }
21
+ function buildMcpToolName(serverName, toolName) {
22
+ return mcpToolNamePrefix(serverName) + sanitizeSegment(toolName);
23
+ }
24
+ var MCPToolWrapper = class {
25
+ name;
26
+ description;
27
+ category = "command";
28
+ // MCP tools are lazily loaded by default to avoid cramming all schemas into the prompt
29
+ deferred = true;
30
+ mcpServerName;
31
+ client;
32
+ originalName;
33
+ inputSchema;
34
+ constructor(client, serverName, tool) {
35
+ this.name = buildMcpToolName(serverName, tool.name);
36
+ this.description = tool.description;
37
+ this.originalName = tool.name;
38
+ this.client = client;
39
+ this.inputSchema = tool.inputSchema;
40
+ this.mcpServerName = serverName;
41
+ }
42
+ /** Original JSON schema. McpCall's argument coercion walks it layer by layer. */
43
+ mcpInputSchema() {
44
+ return this.inputSchema ?? {};
45
+ }
46
+ /** In eager mode the defer flag is cleared so MCP tools go straight into tools[]. */
47
+ setDeferLoading(on) {
48
+ this.deferred = on;
49
+ }
50
+ schema() {
51
+ return {
52
+ name: this.name,
53
+ description: this.description,
54
+ input_schema: this.inputSchema
55
+ };
56
+ }
57
+ async execute(_ctx, args) {
58
+ try {
59
+ return await this.client.callTool(this.originalName, args);
60
+ } catch (err) {
61
+ log.error({ err }, "mcp operation failed");
62
+ return {
63
+ output: `MCP tool error: ${asErrorString(err)}`,
64
+ isError: true
65
+ };
66
+ }
67
+ }
68
+ };
69
+
70
+ // src/tools/mcp-call.ts
71
+ function coerceScalar(value, want) {
72
+ if (want === "string" && typeof value === "number" && Number.isFinite(value)) {
73
+ return String(value);
74
+ }
75
+ if ((want === "integer" || want === "number") && typeof value === "string") {
76
+ const text = value.trim();
77
+ if (text === "") {
78
+ return value;
79
+ }
80
+ const shape = want === "integer" ? /^[+-]?\d+$/ : /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
81
+ if (!shape.test(text)) {
82
+ return value;
83
+ }
84
+ const parsed = want === "integer" ? Number.parseInt(text, 10) : Number.parseFloat(text);
85
+ return Number.isNaN(parsed) ? value : parsed;
86
+ }
87
+ if (want === "boolean" && typeof value === "string") {
88
+ const low = value.trim().toLowerCase();
89
+ if (low === "true") {
90
+ return true;
91
+ }
92
+ if (low === "false") {
93
+ return false;
94
+ }
95
+ }
96
+ return value;
97
+ }
98
+ function coerceBySchema(value, schema) {
99
+ if (typeof schema !== "object" || schema === null) {
100
+ return value;
101
+ }
102
+ const schemaObj = asRecord(schema);
103
+ const want = strArg(schemaObj, "type", "");
104
+ if (want === "object" && typeof value === "object" && value !== null && !Array.isArray(value)) {
105
+ const props = asRecord(schemaObj.properties ?? {});
106
+ const out = {};
107
+ for (const [key, item] of Object.entries(value)) {
108
+ out[key] = key in props ? coerceBySchema(item, props[key]) : item;
109
+ }
110
+ return out;
111
+ }
112
+ if (want === "array") {
113
+ const itemSchema = schemaObj.items ?? {};
114
+ let working = value;
115
+ if (typeof working === "object" && working !== null && !Array.isArray(working)) {
116
+ const entries = Object.values(working);
117
+ if (entries.length === 1 && Array.isArray(entries[0])) {
118
+ working = entries[0];
119
+ }
120
+ } else if (typeof working === "string") {
121
+ working = working.split(",").map((p) => p.trim()).filter((p) => p !== "");
122
+ }
123
+ if (Array.isArray(working)) {
124
+ return working.map((item) => coerceBySchema(item, itemSchema));
125
+ }
126
+ return working;
127
+ }
128
+ if (want !== "") {
129
+ return coerceScalar(value, want);
130
+ }
131
+ return value;
132
+ }
133
+ function mcpCallPermissionContent(server, tool) {
134
+ if (tool.startsWith(MCP_TOOL_PREFIX)) {
135
+ const rest = tool.slice(MCP_TOOL_PREFIX.length);
136
+ const idx = rest.indexOf(MCP_NAME_SEP);
137
+ if (idx >= 0) {
138
+ return sanitizeSegment(rest.slice(0, idx)) + MCP_NAME_SEP + sanitizeSegment(rest.slice(idx + MCP_NAME_SEP.length));
139
+ }
140
+ }
141
+ return sanitizeSegment(server) + MCP_NAME_SEP + sanitizeSegment(tool);
142
+ }
143
+ function isMcpToolLike(tool) {
144
+ return "mcpInputSchema" in tool && typeof tool.mcpInputSchema === "function";
145
+ }
146
+ var McpCallTool = class {
147
+ constructor(registry) {
148
+ this.registry = registry;
149
+ }
150
+ registry;
151
+ name = MCP_CALL_TOOL_NAME;
152
+ 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.";
153
+ category = "command";
154
+ // This tool must stay in tools[] itself, otherwise the model has no entry point
155
+ deferred = false;
156
+ schema() {
157
+ return {
158
+ name: this.name,
159
+ description: this.description,
160
+ input_schema: {
161
+ type: "object",
162
+ properties: {
163
+ server: {
164
+ type: "string",
165
+ description: "MCP server name, e.g. 'linear'."
166
+ },
167
+ tool: {
168
+ type: "string",
169
+ description: "Full tool name as returned by ToolSearch, e.g. 'mcp__linear__create_issue'."
170
+ },
171
+ arguments: {
172
+ type: "object",
173
+ 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."
174
+ }
175
+ },
176
+ required: ["server", "tool", "arguments"]
177
+ }
178
+ };
179
+ }
180
+ /**
181
+ * Try in order: full name / server+short name / unique short-name suffix match.
182
+ *
183
+ * The model very often passes only the short name (roughly three in ten calls in
184
+ * practice), so this must be tolerant — otherwise it needlessly costs a retry
185
+ * round.
186
+ */
187
+ resolve(server, tool) {
188
+ const direct = this.registry.get(tool) ?? this.registry.get(buildMcpToolName(server, tool));
189
+ if (direct) {
190
+ return direct;
191
+ }
192
+ const suffix = MCP_NAME_SEP + sanitizeSegment(tool);
193
+ const matches = this.registry.listTools().filter((t) => t.name.startsWith(MCP_TOOL_PREFIX) && t.name.endsWith(suffix));
194
+ return matches.length === 1 ? matches[0] : void 0;
195
+ }
196
+ availableNames() {
197
+ return this.registry.listTools().filter((t) => t.name.startsWith(MCP_TOOL_PREFIX)).map((t) => t.name).sort();
198
+ }
199
+ async execute(ctx, args) {
200
+ const server = strArg(args, "server", "");
201
+ const tool = strArg(args, "tool", "");
202
+ if (tool === "") {
203
+ return { output: "McpCall requires a 'tool' name", isError: true };
204
+ }
205
+ const target = this.resolve(server, tool);
206
+ if (!target) {
207
+ const names = this.availableNames();
208
+ const hint = names.length > 0 ? names.join(", ") : "(none connected)";
209
+ return {
210
+ output: `Unknown MCP tool '${tool}' on server '${server}'. Available tools: ${hint}`,
211
+ isError: true
212
+ };
213
+ }
214
+ let inner = {};
215
+ if (typeof args.arguments === "object" && args.arguments !== null && !Array.isArray(args.arguments)) {
216
+ inner = asRecord(args.arguments);
217
+ }
218
+ if (isMcpToolLike(target)) {
219
+ const schema = target.mcpInputSchema();
220
+ if (Object.keys(schema).length > 0) {
221
+ const fixed = coerceBySchema(inner, schema);
222
+ if (typeof fixed === "object" && fixed !== null && !Array.isArray(fixed)) {
223
+ inner = asRecord(fixed);
224
+ }
225
+ }
226
+ }
227
+ return target.execute(ctx, inner);
228
+ }
229
+ };
230
+
231
+ export {
232
+ MCP_TOOL_PREFIX,
233
+ MCP_NAME_SEP,
234
+ sanitizeSegment,
235
+ mcpToolNamePrefix,
236
+ buildMcpToolName,
237
+ MCPToolWrapper,
238
+ coerceBySchema,
239
+ mcpCallPermissionContent,
240
+ isMcpToolLike,
241
+ McpCallTool
242
+ };
@@ -0,0 +1,39 @@
1
+ // src/sandbox/seatbelt.ts
2
+ import { existsSync, statSync } from "fs";
3
+ var SANDBOX_EXEC_PATH = "/usr/bin/sandbox-exec";
4
+ var SeatbeltSandbox = class {
5
+ available() {
6
+ return existsSync(SANDBOX_EXEC_PATH);
7
+ }
8
+ wrap(command, config) {
9
+ const profile = buildProfile(config);
10
+ const escaped = command.replace(/'/g, "'\\''");
11
+ return `${SANDBOX_EXEC_PATH} -p '${profile}' bash -c '${escaped}'`;
12
+ }
13
+ };
14
+ function buildProfile(config) {
15
+ const lines = [];
16
+ lines.push("(version 1)");
17
+ lines.push("(deny default)");
18
+ lines.push("(allow process-exec)");
19
+ lines.push("(allow process-fork)");
20
+ lines.push("(allow sysctl-read)");
21
+ lines.push('(allow file-read* (subpath "/"))');
22
+ for (const path of config.allowWrite) {
23
+ lines.push(`(allow file-write* (subpath "${path}"))`);
24
+ }
25
+ for (const path of config.denyWrite) {
26
+ const matcher = existsSync(path) && statSync(path).isDirectory() ? "subpath" : "literal";
27
+ lines.push(`(deny file-write* (${matcher} "${path}"))`);
28
+ }
29
+ if (config.networkEnabled) {
30
+ lines.push("(allow network*)");
31
+ } else {
32
+ lines.push("(deny network*)");
33
+ }
34
+ return lines.join("\n");
35
+ }
36
+
37
+ export {
38
+ SeatbeltSandbox
39
+ };
Binary file