skalpel 2.0.23 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +103 -0
- package/LICENSE +201 -21
- package/README.md +12 -174
- package/design-tokens.json +51 -0
- package/npm-bin/colors.js +125 -0
- package/npm-bin/skalpel.js +200 -0
- package/npm-bin/skalpeld.js +20 -0
- package/package.json +50 -68
- package/postinstall/index.js +294 -0
- package/postinstall/launchd/com.skalpel.skalpeld.plist.tmpl +41 -0
- package/postinstall/lib/detect-prior.js +51 -0
- package/postinstall/lib/env-inject.js +121 -0
- package/postinstall/lib/launch.js +28 -0
- package/postinstall/lib/log.js +31 -0
- package/postinstall/lib/paths.js +186 -0
- package/postinstall/lib/rc-edit.js +167 -0
- package/postinstall/lib/rc-edit.test.js +196 -0
- package/postinstall/lib/service-register.js +293 -0
- package/postinstall/lib/sign-in.js +98 -0
- package/postinstall/lib/template.js +36 -0
- package/postinstall/snippets/bash.sh.tmpl +12 -0
- package/postinstall/snippets/fish.fish.tmpl +11 -0
- package/postinstall/snippets/powershell.ps1.tmpl +12 -0
- package/postinstall/snippets/zsh.sh.tmpl +13 -0
- package/postinstall/systemd/skalpeld.service.tmpl +33 -0
- package/postinstall/windows/Task.xml.tmpl +42 -0
- package/postinstall/windows/register-task.ps1.tmpl +45 -0
- package/dist/cli/index.js +0 -2899
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/proxy-runner.js +0 -1649
- package/dist/cli/proxy-runner.js.map +0 -1
- package/dist/index.cjs +0 -2333
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -165
- package/dist/index.d.ts +0 -165
- package/dist/index.js +0 -2287
- package/dist/index.js.map +0 -1
- package/dist/proxy/index.cjs +0 -1782
- package/dist/proxy/index.cjs.map +0 -1
- package/dist/proxy/index.d.cts +0 -39
- package/dist/proxy/index.d.ts +0 -39
- package/dist/proxy/index.js +0 -1748
- package/dist/proxy/index.js.map +0 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// colors.js — Catppuccin Frappé palette wrapper for the npm-side
|
|
4
|
+
// surfaces (npx wizard banner, postinstall success line). Reads the
|
|
5
|
+
// canonical hex values from design-tokens.json (Wave 1 artifact) and
|
|
6
|
+
// wraps Picocolors so NO_COLOR is honoured automatically. The box()
|
|
7
|
+
// helper draws a rounded Unicode-art frame around content; structure
|
|
8
|
+
// chars are emitted unconditionally, only the ANSI sequences are
|
|
9
|
+
// suppressed under NO_COLOR.
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const pc = require('picocolors');
|
|
13
|
+
|
|
14
|
+
const tokens = require(path.resolve(__dirname, '..', 'design-tokens.json'));
|
|
15
|
+
|
|
16
|
+
const palette = (tokens.themes && tokens.themes.frappe) || {};
|
|
17
|
+
|
|
18
|
+
function rgbFromHex(hex) {
|
|
19
|
+
const m = String(hex || '').replace('#', '').match(/^([0-9a-fA-F]{6})$/);
|
|
20
|
+
if (!m) return null;
|
|
21
|
+
const v = parseInt(m[1], 16);
|
|
22
|
+
return [(v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function colorize(hex) {
|
|
26
|
+
const rgb = rgbFromHex(hex);
|
|
27
|
+
if (!rgb) {
|
|
28
|
+
return (s) => String(s);
|
|
29
|
+
}
|
|
30
|
+
return (s) => {
|
|
31
|
+
if (process.env.NO_COLOR) return String(s);
|
|
32
|
+
return `\x1b[38;2;${rgb[0]};${rgb[1]};${rgb[2]}m${s}\x1b[39m`;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const theme = {};
|
|
37
|
+
for (const name of Object.keys(palette)) {
|
|
38
|
+
theme[name] = colorize(palette[name]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function attr(open, close) {
|
|
42
|
+
return (s) => {
|
|
43
|
+
if (process.env.NO_COLOR) return String(s);
|
|
44
|
+
return `\x1b[${open}m${s}\x1b[${close}m`;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
theme.bold = attr(1, 22);
|
|
49
|
+
theme.italic = attr(3, 23);
|
|
50
|
+
theme.dim = attr(2, 22);
|
|
51
|
+
|
|
52
|
+
const semantic = (tokens.semantic) || {};
|
|
53
|
+
|
|
54
|
+
function semanticHelper(key) {
|
|
55
|
+
const ref = semantic[key];
|
|
56
|
+
if (!ref) return (s) => String(s);
|
|
57
|
+
const parts = ref.split('.');
|
|
58
|
+
if (parts.length !== 2) return (s) => String(s);
|
|
59
|
+
const colorName = parts[1];
|
|
60
|
+
return theme[colorName] || ((s) => String(s));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function semanticKey(name) {
|
|
64
|
+
return name
|
|
65
|
+
.replace(/[^a-zA-Z0-9]+([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())
|
|
66
|
+
.replace(/^([A-Z])/, (m) => m.toLowerCase());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const k of Object.keys(semantic)) {
|
|
70
|
+
const camel = semanticKey(k);
|
|
71
|
+
theme[camel] = semanticHelper(k);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const BORDERS = {
|
|
75
|
+
topLeft: '╭',
|
|
76
|
+
topRight: '╮',
|
|
77
|
+
bottomLeft: '╰',
|
|
78
|
+
bottomRight: '╯',
|
|
79
|
+
horizontal: '─',
|
|
80
|
+
vertical: '│',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
function visibleLength(s) {
|
|
84
|
+
return String(s).replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function box(content, borderColor, options) {
|
|
88
|
+
const opts = options || {};
|
|
89
|
+
const padding = typeof opts.padding === 'number' ? opts.padding : 1;
|
|
90
|
+
const lines = String(content).split('\n');
|
|
91
|
+
|
|
92
|
+
let inner;
|
|
93
|
+
if (opts.width === 'fit' || opts.width == null) {
|
|
94
|
+
inner = 0;
|
|
95
|
+
for (const ln of lines) {
|
|
96
|
+
const len = visibleLength(ln);
|
|
97
|
+
if (len > inner) inner = len;
|
|
98
|
+
}
|
|
99
|
+
inner += padding * 2;
|
|
100
|
+
} else {
|
|
101
|
+
inner = Math.max(0, Number(opts.width) - 2);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const colorOK = pc.isColorSupported && !process.env.NO_COLOR;
|
|
105
|
+
const colorFn = (colorOK && typeof borderColor === 'string' && theme[borderColor])
|
|
106
|
+
? theme[borderColor]
|
|
107
|
+
: (s) => String(s);
|
|
108
|
+
|
|
109
|
+
const horiz = BORDERS.horizontal.repeat(inner);
|
|
110
|
+
const top = colorFn(BORDERS.topLeft + horiz + BORDERS.topRight);
|
|
111
|
+
const bottom = colorFn(BORDERS.bottomLeft + horiz + BORDERS.bottomRight);
|
|
112
|
+
const v = colorFn(BORDERS.vertical);
|
|
113
|
+
const pad = ' '.repeat(padding);
|
|
114
|
+
|
|
115
|
+
const rendered = [top];
|
|
116
|
+
for (const ln of lines) {
|
|
117
|
+
const visLen = visibleLength(ln);
|
|
118
|
+
const fill = ' '.repeat(Math.max(0, inner - padding * 2 - visLen));
|
|
119
|
+
rendered.push(`${v}${pad}${ln}${fill}${pad}${v}`);
|
|
120
|
+
}
|
|
121
|
+
rendered.push(bottom);
|
|
122
|
+
return rendered.join('\n');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = { theme, box, BORDERS, palette };
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Dispatch shim: locate the platform-specific `skalpel` binary that
|
|
3
|
+
// optionalDependencies installed, then exec it with the user's argv.
|
|
4
|
+
//
|
|
5
|
+
// On first interactive run we render a one-time welcome banner before
|
|
6
|
+
// dispatching. The "first run" predicate is the absence of a flag file
|
|
7
|
+
// at $XDG_STATE_HOME/skalpel/.installed (Unix) or
|
|
8
|
+
// %LOCALAPPDATA%\skalpel\.installed (Windows). If the flag-file write
|
|
9
|
+
// fails (perm denied) we log a single dim line and continue dispatch —
|
|
10
|
+
// banner repeats on every invocation under that condition.
|
|
11
|
+
//
|
|
12
|
+
// TTY/NO_COLOR rules:
|
|
13
|
+
// non-TTY (piped stdout) → suppress banner entirely
|
|
14
|
+
// TTY + NO_COLOR set → render box structure, no ANSI
|
|
15
|
+
// interactive TTY, NO_COLOR off → fully colored banner
|
|
16
|
+
//
|
|
17
|
+
// Reference banner (rendered by colors.js box helper):
|
|
18
|
+
//
|
|
19
|
+
// ╭───────────────────────────────────╮
|
|
20
|
+
// │ skalpel v0.0.1 │
|
|
21
|
+
// │ │
|
|
22
|
+
// │ ✓ Detecting platform… darwin-arm64│
|
|
23
|
+
// │ ✓ Resolving binary… found │
|
|
24
|
+
// ╰───────────────────────────────────╯
|
|
25
|
+
//
|
|
26
|
+
// On error a styled error block frames a ✗ glyph + title + body + hint.
|
|
27
|
+
|
|
28
|
+
'use strict';
|
|
29
|
+
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const fs = require('fs');
|
|
32
|
+
const os = require('os');
|
|
33
|
+
const { spawnSync } = require('child_process');
|
|
34
|
+
|
|
35
|
+
const colors = require('./colors.js');
|
|
36
|
+
const { theme, box } = colors;
|
|
37
|
+
|
|
38
|
+
const PLATFORM_PACKAGES = {
|
|
39
|
+
'darwin-arm64': '@skalpelai/skalpel-darwin-arm64',
|
|
40
|
+
'darwin-x64': '@skalpelai/skalpel-darwin-x64',
|
|
41
|
+
'linux-arm64': '@skalpelai/skalpel-linux-arm64',
|
|
42
|
+
'linux-x64': '@skalpelai/skalpel-linux-x64',
|
|
43
|
+
'win32-x64': '@skalpelai/skalpel-win32-x64',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function pkgVersion() {
|
|
47
|
+
try {
|
|
48
|
+
return require('../package.json').version || '0.0.0';
|
|
49
|
+
} catch (_) {
|
|
50
|
+
return '0.0.0';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function flagFilePath() {
|
|
55
|
+
if (os.platform() === 'win32') {
|
|
56
|
+
const root = process.env.LOCALAPPDATA;
|
|
57
|
+
if (!root) return null;
|
|
58
|
+
return path.join(root, 'skalpel', '.installed');
|
|
59
|
+
}
|
|
60
|
+
const root = process.env.XDG_STATE_HOME
|
|
61
|
+
|| (process.env.HOME ? path.join(process.env.HOME, '.local', 'state') : null);
|
|
62
|
+
if (!root) return null;
|
|
63
|
+
return path.join(root, 'skalpel', '.installed');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isFirstRun() {
|
|
67
|
+
const p = flagFilePath();
|
|
68
|
+
if (!p) return false;
|
|
69
|
+
try {
|
|
70
|
+
return !fs.existsSync(p);
|
|
71
|
+
} catch (_) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function markInstalled() {
|
|
77
|
+
const p = flagFilePath();
|
|
78
|
+
if (!p) return { ok: false, path: null };
|
|
79
|
+
try {
|
|
80
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
81
|
+
fs.writeFileSync(p, `${new Date().toISOString()}\n`);
|
|
82
|
+
return { ok: true, path: p };
|
|
83
|
+
} catch (err) {
|
|
84
|
+
return { ok: false, path: p, err };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function renderWelcome(version, platformLabel, opts) {
|
|
89
|
+
const colored = opts && opts.colored;
|
|
90
|
+
const v = colored ? theme.bold(theme.mauve(`skalpel v${version}`)) : `skalpel v${version}`;
|
|
91
|
+
const detect = colored
|
|
92
|
+
? `${theme.green('✓')} ${theme.text(`Detecting platform… ${platformLabel}`)}`
|
|
93
|
+
: `✓ Detecting platform… ${platformLabel}`;
|
|
94
|
+
const resolve = colored
|
|
95
|
+
? `${theme.green('✓')} ${theme.text('Resolving binary… found')}`
|
|
96
|
+
: `✓ Resolving binary… found`;
|
|
97
|
+
const body = [v, '', detect, resolve].join('\n');
|
|
98
|
+
return box(body, colored ? 'mauve' : null, { padding: 1 });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function renderError(title, body, hint, opts) {
|
|
102
|
+
const colored = opts && opts.colored;
|
|
103
|
+
const t = colored ? theme.bold(theme.red(`✗ ${title}`)) : `✗ ${title}`;
|
|
104
|
+
const b = colored ? theme.dim(theme.text(body)) : body;
|
|
105
|
+
const h = colored ? theme.mauve(hint) : hint;
|
|
106
|
+
const content = [t, '', b, '', h].join('\n');
|
|
107
|
+
return box(content, colored ? 'red' : null, { padding: 1 });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function emitBanner(stream, platformLabel) {
|
|
111
|
+
if (!stream.isTTY) return; // non-TTY: suppress entirely
|
|
112
|
+
const colored = !process.env.NO_COLOR;
|
|
113
|
+
const banner = renderWelcome(pkgVersion(), platformLabel, { colored });
|
|
114
|
+
stream.write(`${banner}\n`);
|
|
115
|
+
const m = markInstalled();
|
|
116
|
+
if (!m.ok && m.path) {
|
|
117
|
+
const dim = colored ? theme.dim : (s) => s;
|
|
118
|
+
stream.write(`${dim(`(welcome shown but flag file unwritable: ${m.path})`)}\n`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function emitError(stream, title, body, hint) {
|
|
123
|
+
const colored = stream.isTTY && !process.env.NO_COLOR;
|
|
124
|
+
const block = renderError(title, body, hint, { colored });
|
|
125
|
+
stream.write(`${block}\n`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function platformLabel() {
|
|
129
|
+
return `${os.platform()}-${os.arch()}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// isInfoArg returns true for argv shapes that only request info
|
|
133
|
+
// (--help / --version / -h / -v / help / version). When dispatch
|
|
134
|
+
// fails for those args (no platform binary) we render an error
|
|
135
|
+
// block and exit 0, since the shim succeeded at communicating.
|
|
136
|
+
function isInfoArg(argv) {
|
|
137
|
+
if (argv.length === 0) return false;
|
|
138
|
+
const a = argv[0];
|
|
139
|
+
return a === '--help' || a === '-h' || a === 'help' ||
|
|
140
|
+
a === '--version' || a === '-v' || a === 'version';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function resolveBinary(name, argv) {
|
|
144
|
+
const infoOnly = isInfoArg(argv || []);
|
|
145
|
+
const failExit = infoOnly ? 0 : 1;
|
|
146
|
+
const key = `${process.platform}-${process.arch}`;
|
|
147
|
+
const pkg = PLATFORM_PACKAGES[key];
|
|
148
|
+
if (!pkg) {
|
|
149
|
+
const supported = Object.keys(PLATFORM_PACKAGES).join(', ');
|
|
150
|
+
emitError(
|
|
151
|
+
process.stderr,
|
|
152
|
+
'Unsupported platform',
|
|
153
|
+
`skalpel does not ship a binary for ${key}.\nSupported: ${supported}.`,
|
|
154
|
+
`→ Install from GitHub Releases: https://github.com/skalpelai/Skalpelai_Client/releases`
|
|
155
|
+
);
|
|
156
|
+
process.exit(failExit);
|
|
157
|
+
}
|
|
158
|
+
const exe = process.platform === 'win32' ? `${name}.exe` : name;
|
|
159
|
+
let pkgRoot;
|
|
160
|
+
try {
|
|
161
|
+
pkgRoot = path.dirname(require.resolve(`${pkg}/package.json`));
|
|
162
|
+
} catch (_err) {
|
|
163
|
+
emitError(
|
|
164
|
+
process.stderr,
|
|
165
|
+
'Platform package missing',
|
|
166
|
+
`${pkg} is not installed.`,
|
|
167
|
+
`→ Re-run \`npm install -g skalpel\` or \`npx skalpel\``
|
|
168
|
+
);
|
|
169
|
+
process.exit(failExit);
|
|
170
|
+
}
|
|
171
|
+
const candidate = path.join(pkgRoot, 'bin', exe);
|
|
172
|
+
if (!fs.existsSync(candidate)) {
|
|
173
|
+
emitError(
|
|
174
|
+
process.stderr,
|
|
175
|
+
'Binary missing',
|
|
176
|
+
`Expected binary at ${candidate} but it does not exist.`,
|
|
177
|
+
`→ Reinstall: \`npm install -g skalpel\``
|
|
178
|
+
);
|
|
179
|
+
process.exit(failExit);
|
|
180
|
+
}
|
|
181
|
+
return candidate;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (require.main === module) {
|
|
185
|
+
if (isFirstRun()) {
|
|
186
|
+
emitBanner(process.stdout, platformLabel());
|
|
187
|
+
}
|
|
188
|
+
const argv = process.argv.slice(2);
|
|
189
|
+
const binary = resolveBinary('skalpel', argv);
|
|
190
|
+
const result = spawnSync(binary, argv, {
|
|
191
|
+
stdio: 'inherit',
|
|
192
|
+
});
|
|
193
|
+
if (result.error) {
|
|
194
|
+
emitError(process.stderr, 'Spawn failed', result.error.message, '→ Check that the binary is executable.');
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = { resolveBinary, PLATFORM_PACKAGES, renderWelcome, renderError, flagFilePath };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Dispatch shim for the daemon. See npm-bin/skalpel.js for the
|
|
3
|
+
// resolution rationale; this file delegates to the same lookup table.
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { spawnSync } = require('child_process');
|
|
8
|
+
const { resolveBinary } = require('./skalpel.js');
|
|
9
|
+
|
|
10
|
+
if (require.main === module) {
|
|
11
|
+
const binary = resolveBinary('skalpeld');
|
|
12
|
+
const result = spawnSync(binary, process.argv.slice(2), {
|
|
13
|
+
stdio: 'inherit',
|
|
14
|
+
});
|
|
15
|
+
if (result.error) {
|
|
16
|
+
process.stderr.write(`skalpeld: ${result.error.message}\n`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,81 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skalpel",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Skalpel — local proxy and TUI for coding agents (skalpel + skalpeld bundle).",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://skalpel.ai",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/skalpelai/Skalpelai_Client.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/skalpelai/Skalpelai_Client/issues"
|
|
13
|
+
},
|
|
14
|
+
"author": "SkalpelAI Inc.",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"coding-agent",
|
|
17
|
+
"proxy",
|
|
18
|
+
"tui",
|
|
19
|
+
"claude",
|
|
20
|
+
"cursor",
|
|
21
|
+
"codex"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
15
25
|
},
|
|
16
26
|
"bin": {
|
|
17
|
-
"skalpel": "
|
|
27
|
+
"skalpel": "npm-bin/skalpel.js",
|
|
28
|
+
"skalpeld": "npm-bin/skalpeld.js"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"postinstall": "node postinstall/index.js",
|
|
32
|
+
"preuninstall": "node postinstall/index.js --uninstall",
|
|
33
|
+
"test": "echo 'no top-level tests; run make test or npm run test:rc-edit' && exit 0",
|
|
34
|
+
"test:rc-edit": "node postinstall/lib/rc-edit.test.js"
|
|
18
35
|
},
|
|
19
36
|
"files": [
|
|
20
|
-
"
|
|
37
|
+
"npm-bin/",
|
|
38
|
+
"postinstall/",
|
|
39
|
+
"design-tokens.json",
|
|
40
|
+
"INSTALL.md",
|
|
21
41
|
"README.md",
|
|
22
42
|
"LICENSE"
|
|
23
43
|
],
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"test": "vitest run",
|
|
27
|
-
"test:watch": "vitest",
|
|
28
|
-
"typecheck": "tsc --noEmit",
|
|
29
|
-
"seed-demo-key": "node scripts/seed-demo-key.mjs",
|
|
30
|
-
"prepublishOnly": "npm run build"
|
|
31
|
-
},
|
|
32
|
-
"peerDependencies": {
|
|
33
|
-
"@anthropic-ai/sdk": ">=0.30.0",
|
|
34
|
-
"openai": ">=4.0.0"
|
|
35
|
-
},
|
|
36
|
-
"peerDependenciesMeta": {
|
|
37
|
-
"openai": {
|
|
38
|
-
"optional": true
|
|
39
|
-
},
|
|
40
|
-
"@anthropic-ai/sdk": {
|
|
41
|
-
"optional": true
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@anthropic-ai/sdk": "^0.30.0",
|
|
46
|
-
"@types/ws": "^8.18.1",
|
|
47
|
-
"@vitest/coverage-v8": "^2.0.0",
|
|
48
|
-
"fast-check": "^3.22.0",
|
|
49
|
-
"openai": "^4.0.0",
|
|
50
|
-
"pg": "^8.13.0",
|
|
51
|
-
"tsup": "^8.0.0",
|
|
52
|
-
"typescript": "^5.4.0",
|
|
53
|
-
"vitest": "^2.0.0"
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"picocolors": "^1.1.1"
|
|
54
46
|
},
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"api",
|
|
60
|
-
"gateway",
|
|
61
|
-
"proxy",
|
|
62
|
-
"cost-optimization",
|
|
63
|
-
"ai",
|
|
64
|
-
"sdk"
|
|
47
|
+
"os": [
|
|
48
|
+
"darwin",
|
|
49
|
+
"linux",
|
|
50
|
+
"win32"
|
|
65
51
|
],
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"commander": "^14.0.3",
|
|
77
|
-
"open": "^10.0.0",
|
|
78
|
-
"undici": "^6.24.1",
|
|
79
|
-
"ws": "^8.20.0"
|
|
52
|
+
"cpu": [
|
|
53
|
+
"arm64",
|
|
54
|
+
"x64"
|
|
55
|
+
],
|
|
56
|
+
"optionalDependencies": {
|
|
57
|
+
"@skalpelai/skalpel-darwin-arm64": "3.0.0",
|
|
58
|
+
"@skalpelai/skalpel-darwin-x64": "3.0.0",
|
|
59
|
+
"@skalpelai/skalpel-linux-arm64": "3.0.0",
|
|
60
|
+
"@skalpelai/skalpel-linux-x64": "3.0.0",
|
|
61
|
+
"@skalpelai/skalpel-win32-x64": "3.0.0"
|
|
80
62
|
}
|
|
81
63
|
}
|