@velum-labs/cursorkit 0.1.0 → 0.1.2
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 +18 -17
- package/dist/src/ckLauncher.d.ts +16 -6
- package/dist/src/ckLauncher.js +334 -478
- package/dist/src/cli.d.ts +2 -1
- package/dist/src/cli.js +25 -253
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +129 -0
- package/dist/src/commands/maintenance.d.ts +2 -0
- package/dist/src/commands/maintenance.js +94 -0
- package/dist/src/commands/render.d.ts +14 -0
- package/dist/src/commands/render.js +17 -0
- package/dist/src/commands/serve.d.ts +2 -0
- package/dist/src/commands/serve.js +52 -0
- package/dist/src/cursorDesktopState.d.ts +10 -0
- package/dist/src/cursorDesktopState.js +204 -0
- package/dist/src/desktopConnectProxy.d.ts +10 -0
- package/dist/src/desktopConnectProxy.js +7 -1
- package/dist/src/server.js +35 -2
- package/dist/src/tools/releaseCheck.d.ts +1 -1
- package/dist/src/tools/releaseCheck.js +1 -6
- package/dist/src/ui/index.d.ts +8 -0
- package/dist/src/ui/index.js +6 -0
- package/dist/src/ui/prompt.d.ts +30 -0
- package/dist/src/ui/prompt.js +182 -0
- package/dist/src/ui/runtime.d.ts +14 -0
- package/dist/src/ui/runtime.js +35 -0
- package/dist/src/ui/spinner.d.ts +31 -0
- package/dist/src/ui/spinner.js +102 -0
- package/dist/src/ui/steps.d.ts +38 -0
- package/dist/src/ui/steps.js +154 -0
- package/dist/src/ui/theme.d.ts +35 -0
- package/dist/src/ui/theme.js +63 -0
- package/package.json +5 -3
- package/dist/src/ck.d.ts +0 -2
- package/dist/src/ck.js +0 -6
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { isInteractive, uiStream } from "./runtime.js";
|
|
2
|
+
import { SPINNER_FRAMES, cyan, dim, glyph, gray, green, red, yellow, } from "./theme.js";
|
|
3
|
+
/**
|
|
4
|
+
* A single-line spinner. On an interactive TTY it animates in place; otherwise
|
|
5
|
+
* it prints one line per state transition so logs stay readable and ordered.
|
|
6
|
+
*/
|
|
7
|
+
export class Spinner {
|
|
8
|
+
timer;
|
|
9
|
+
frame = 0;
|
|
10
|
+
text;
|
|
11
|
+
stream = uiStream();
|
|
12
|
+
interactive = isInteractive();
|
|
13
|
+
active = false;
|
|
14
|
+
constructor(text) {
|
|
15
|
+
this.text = text;
|
|
16
|
+
}
|
|
17
|
+
start() {
|
|
18
|
+
if (this.active)
|
|
19
|
+
return this;
|
|
20
|
+
this.active = true;
|
|
21
|
+
if (!this.interactive) {
|
|
22
|
+
this.stream.write(`${dim(glyph.arrow())} ${this.text}\n`);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
this.hideCursor();
|
|
26
|
+
this.render();
|
|
27
|
+
this.timer = setInterval(() => {
|
|
28
|
+
this.frame = (this.frame + 1) % SPINNER_FRAMES.length;
|
|
29
|
+
this.render();
|
|
30
|
+
}, 80);
|
|
31
|
+
this.timer.unref();
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
update(text) {
|
|
35
|
+
this.text = text;
|
|
36
|
+
if (this.active && this.interactive)
|
|
37
|
+
this.render();
|
|
38
|
+
else if (this.active)
|
|
39
|
+
this.stream.write(`${dim(glyph.arrow())} ${this.text}\n`);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
succeed(text) {
|
|
43
|
+
this.settle(green(glyph.tick()), text ?? this.text);
|
|
44
|
+
}
|
|
45
|
+
fail(text) {
|
|
46
|
+
this.settle(red(glyph.cross()), text ?? this.text);
|
|
47
|
+
}
|
|
48
|
+
warn(text) {
|
|
49
|
+
this.settle(yellow(glyph.warn()), text ?? this.text);
|
|
50
|
+
}
|
|
51
|
+
info(text) {
|
|
52
|
+
this.settle(cyan(glyph.bullet()), text ?? this.text);
|
|
53
|
+
}
|
|
54
|
+
stop() {
|
|
55
|
+
this.teardown();
|
|
56
|
+
}
|
|
57
|
+
settle(symbol, text) {
|
|
58
|
+
this.teardown();
|
|
59
|
+
this.stream.write(`${symbol} ${text}\n`);
|
|
60
|
+
}
|
|
61
|
+
render() {
|
|
62
|
+
const symbol = cyan(SPINNER_FRAMES[this.frame] ?? "-");
|
|
63
|
+
this.clearLine();
|
|
64
|
+
this.stream.write(`${symbol} ${this.text}`);
|
|
65
|
+
}
|
|
66
|
+
teardown() {
|
|
67
|
+
if (this.timer !== undefined) {
|
|
68
|
+
clearInterval(this.timer);
|
|
69
|
+
this.timer = undefined;
|
|
70
|
+
}
|
|
71
|
+
if (this.active && this.interactive) {
|
|
72
|
+
this.clearLine();
|
|
73
|
+
this.showCursor();
|
|
74
|
+
}
|
|
75
|
+
this.active = false;
|
|
76
|
+
}
|
|
77
|
+
clearLine() {
|
|
78
|
+
if (this.interactive)
|
|
79
|
+
this.stream.write("\r\u001b[2K");
|
|
80
|
+
}
|
|
81
|
+
hideCursor() {
|
|
82
|
+
if (this.interactive)
|
|
83
|
+
this.stream.write("\u001b[?25l");
|
|
84
|
+
}
|
|
85
|
+
showCursor() {
|
|
86
|
+
if (this.interactive)
|
|
87
|
+
this.stream.write("\u001b[?25h");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Run `work` under a spinner, settling to success/failure automatically. */
|
|
91
|
+
export async function withSpinner(text, work, options = {}) {
|
|
92
|
+
const spinner = new Spinner(text).start();
|
|
93
|
+
try {
|
|
94
|
+
const value = await work();
|
|
95
|
+
spinner.succeed(options.success ? options.success(value) : text);
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
spinner.fail(options.failure ? options.failure(error) : `${text} ${gray("(failed)")}`);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type StepStatus = "pending" | "active" | "done" | "failed" | "skipped";
|
|
2
|
+
export type StepInput = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* A live checklist of stages. On a TTY it re-renders in place with per-stage
|
|
8
|
+
* spinners and elapsed time; otherwise it prints one line per state transition
|
|
9
|
+
* so non-interactive logs stay ordered and readable.
|
|
10
|
+
*/
|
|
11
|
+
export declare class StepList {
|
|
12
|
+
private readonly steps;
|
|
13
|
+
private readonly stream;
|
|
14
|
+
private readonly interactive;
|
|
15
|
+
private readonly title;
|
|
16
|
+
private timer;
|
|
17
|
+
private frame;
|
|
18
|
+
private renderedLines;
|
|
19
|
+
private started;
|
|
20
|
+
constructor(steps: readonly StepInput[], options?: {
|
|
21
|
+
title?: string;
|
|
22
|
+
});
|
|
23
|
+
start(): this;
|
|
24
|
+
setActive(id: string, detail?: string): void;
|
|
25
|
+
setDone(id: string, detail?: string): void;
|
|
26
|
+
setFailed(id: string, detail?: string): void;
|
|
27
|
+
setSkipped(id: string, detail?: string): void;
|
|
28
|
+
setDetail(id: string, detail: string): void;
|
|
29
|
+
/** Stop animation and leave the final frame in place. */
|
|
30
|
+
stop(): void;
|
|
31
|
+
private transition;
|
|
32
|
+
private printLine;
|
|
33
|
+
private render;
|
|
34
|
+
private clear;
|
|
35
|
+
private find;
|
|
36
|
+
private hideCursor;
|
|
37
|
+
private showCursor;
|
|
38
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { isInteractive, uiStream } from "./runtime.js";
|
|
2
|
+
import { SPINNER_FRAMES, cyan, dim, glyph, gray, green, red, yellow, } from "./theme.js";
|
|
3
|
+
function elapsedLabel(step) {
|
|
4
|
+
if (step.startedAt === undefined)
|
|
5
|
+
return "";
|
|
6
|
+
const end = step.endedAt ?? Date.now();
|
|
7
|
+
const seconds = (end - step.startedAt) / 1000;
|
|
8
|
+
if (seconds < 0.05)
|
|
9
|
+
return "";
|
|
10
|
+
return gray(` ${seconds.toFixed(1)}s`);
|
|
11
|
+
}
|
|
12
|
+
function symbolFor(step, frame) {
|
|
13
|
+
switch (step.status) {
|
|
14
|
+
case "pending":
|
|
15
|
+
return gray(glyph.pending());
|
|
16
|
+
case "active":
|
|
17
|
+
return cyan(SPINNER_FRAMES[frame] ?? "-");
|
|
18
|
+
case "done":
|
|
19
|
+
return green(glyph.tick());
|
|
20
|
+
case "failed":
|
|
21
|
+
return red(glyph.cross());
|
|
22
|
+
case "skipped":
|
|
23
|
+
return yellow(glyph.bullet());
|
|
24
|
+
default: {
|
|
25
|
+
const exhaustive = step.status;
|
|
26
|
+
throw new Error(`unknown step status: ${String(exhaustive)}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A live checklist of stages. On a TTY it re-renders in place with per-stage
|
|
32
|
+
* spinners and elapsed time; otherwise it prints one line per state transition
|
|
33
|
+
* so non-interactive logs stay ordered and readable.
|
|
34
|
+
*/
|
|
35
|
+
export class StepList {
|
|
36
|
+
steps;
|
|
37
|
+
stream = uiStream();
|
|
38
|
+
interactive = isInteractive();
|
|
39
|
+
title;
|
|
40
|
+
timer;
|
|
41
|
+
frame = 0;
|
|
42
|
+
renderedLines = 0;
|
|
43
|
+
started = false;
|
|
44
|
+
constructor(steps, options = {}) {
|
|
45
|
+
this.steps = steps.map((step) => ({
|
|
46
|
+
id: step.id,
|
|
47
|
+
label: step.label,
|
|
48
|
+
status: "pending",
|
|
49
|
+
}));
|
|
50
|
+
this.title = options.title;
|
|
51
|
+
}
|
|
52
|
+
start() {
|
|
53
|
+
if (this.started)
|
|
54
|
+
return this;
|
|
55
|
+
this.started = true;
|
|
56
|
+
if (this.interactive) {
|
|
57
|
+
this.hideCursor();
|
|
58
|
+
this.render();
|
|
59
|
+
this.timer = setInterval(() => {
|
|
60
|
+
this.frame = (this.frame + 1) % SPINNER_FRAMES.length;
|
|
61
|
+
this.render();
|
|
62
|
+
}, 80);
|
|
63
|
+
this.timer.unref();
|
|
64
|
+
}
|
|
65
|
+
else if (this.title !== undefined) {
|
|
66
|
+
this.stream.write(`${this.title}\n`);
|
|
67
|
+
}
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
setActive(id, detail) {
|
|
71
|
+
this.transition(id, "active", detail);
|
|
72
|
+
}
|
|
73
|
+
setDone(id, detail) {
|
|
74
|
+
this.transition(id, "done", detail);
|
|
75
|
+
}
|
|
76
|
+
setFailed(id, detail) {
|
|
77
|
+
this.transition(id, "failed", detail);
|
|
78
|
+
}
|
|
79
|
+
setSkipped(id, detail) {
|
|
80
|
+
this.transition(id, "skipped", detail);
|
|
81
|
+
}
|
|
82
|
+
setDetail(id, detail) {
|
|
83
|
+
const step = this.find(id);
|
|
84
|
+
step.detail = detail;
|
|
85
|
+
if (this.interactive)
|
|
86
|
+
this.render();
|
|
87
|
+
}
|
|
88
|
+
/** Stop animation and leave the final frame in place. */
|
|
89
|
+
stop() {
|
|
90
|
+
if (this.timer !== undefined) {
|
|
91
|
+
clearInterval(this.timer);
|
|
92
|
+
this.timer = undefined;
|
|
93
|
+
}
|
|
94
|
+
if (this.interactive && this.started) {
|
|
95
|
+
this.render();
|
|
96
|
+
this.showCursor();
|
|
97
|
+
}
|
|
98
|
+
this.started = false;
|
|
99
|
+
}
|
|
100
|
+
transition(id, status, detail) {
|
|
101
|
+
const step = this.find(id);
|
|
102
|
+
if (status === "active" && step.startedAt === undefined)
|
|
103
|
+
step.startedAt = Date.now();
|
|
104
|
+
if ((status === "done" || status === "failed" || status === "skipped") &&
|
|
105
|
+
step.endedAt === undefined) {
|
|
106
|
+
step.endedAt = Date.now();
|
|
107
|
+
if (step.startedAt === undefined)
|
|
108
|
+
step.startedAt = step.endedAt;
|
|
109
|
+
}
|
|
110
|
+
step.status = status;
|
|
111
|
+
if (detail !== undefined)
|
|
112
|
+
step.detail = detail;
|
|
113
|
+
if (this.interactive)
|
|
114
|
+
this.render();
|
|
115
|
+
else
|
|
116
|
+
this.printLine(step);
|
|
117
|
+
}
|
|
118
|
+
printLine(step) {
|
|
119
|
+
const detail = step.detail !== undefined ? ` ${dim(step.detail)}` : "";
|
|
120
|
+
this.stream.write(`${symbolFor(step, 0)} ${step.label}${detail}\n`);
|
|
121
|
+
}
|
|
122
|
+
render() {
|
|
123
|
+
const lines = [];
|
|
124
|
+
if (this.title !== undefined)
|
|
125
|
+
lines.push(this.title);
|
|
126
|
+
for (const step of this.steps) {
|
|
127
|
+
const detail = step.detail !== undefined ? ` ${dim(step.detail)}` : "";
|
|
128
|
+
lines.push(`${symbolFor(step, this.frame)} ${step.label}${detail}${elapsedLabel(step)}`);
|
|
129
|
+
}
|
|
130
|
+
this.clear();
|
|
131
|
+
this.stream.write(lines.join("\n") + "\n");
|
|
132
|
+
this.renderedLines = lines.length;
|
|
133
|
+
}
|
|
134
|
+
clear() {
|
|
135
|
+
if (!this.interactive || this.renderedLines === 0)
|
|
136
|
+
return;
|
|
137
|
+
this.stream.write(`\u001b[${this.renderedLines}A`);
|
|
138
|
+
this.stream.write("\u001b[0J");
|
|
139
|
+
}
|
|
140
|
+
find(id) {
|
|
141
|
+
const step = this.steps.find((candidate) => candidate.id === id);
|
|
142
|
+
if (step === undefined)
|
|
143
|
+
throw new Error(`unknown step id: ${id}`);
|
|
144
|
+
return step;
|
|
145
|
+
}
|
|
146
|
+
hideCursor() {
|
|
147
|
+
if (this.interactive)
|
|
148
|
+
this.stream.write("\u001b[?25l");
|
|
149
|
+
}
|
|
150
|
+
showCursor() {
|
|
151
|
+
if (this.interactive)
|
|
152
|
+
this.stream.write("\u001b[?25h");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-dependency terminal theming. All color/format helpers no-op when color
|
|
3
|
+
* is not supported (not a TTY, `NO_COLOR` set, or a dumb terminal), so output
|
|
4
|
+
* stays clean when piped or captured. UI is written to stderr by convention so
|
|
5
|
+
* the bridge server's stdout (JSON logs) stays pristine.
|
|
6
|
+
*/
|
|
7
|
+
/** True when ANSI styling should be emitted to the given stream. */
|
|
8
|
+
export declare function supportsColor(stream?: NodeJS.WriteStream): boolean;
|
|
9
|
+
type Style = (text: string) => string;
|
|
10
|
+
export declare const bold: Style;
|
|
11
|
+
export declare const dim: Style;
|
|
12
|
+
export declare const italic: Style;
|
|
13
|
+
export declare const underline: Style;
|
|
14
|
+
export declare const red: Style;
|
|
15
|
+
export declare const green: Style;
|
|
16
|
+
export declare const yellow: Style;
|
|
17
|
+
export declare const blue: Style;
|
|
18
|
+
export declare const magenta: Style;
|
|
19
|
+
export declare const cyan: Style;
|
|
20
|
+
export declare const gray: Style;
|
|
21
|
+
/** Status glyphs, with ASCII fallbacks when color (≈ unicode-friendly TTY) is off. */
|
|
22
|
+
export declare const glyph: {
|
|
23
|
+
tick: () => "✔" | "[ok]";
|
|
24
|
+
cross: () => "✖" | "[x]";
|
|
25
|
+
bullet: () => "•" | "*";
|
|
26
|
+
arrow: () => "›" | ">";
|
|
27
|
+
pointer: () => ">" | "❯";
|
|
28
|
+
warn: () => "⚠" | "[!]";
|
|
29
|
+
pending: () => "○" | "( )";
|
|
30
|
+
};
|
|
31
|
+
/** Frames for the in-place spinner (braille dots when color is on). */
|
|
32
|
+
export declare const SPINNER_FRAMES: readonly string[];
|
|
33
|
+
/** The product banner shown atop interactive surfaces. */
|
|
34
|
+
export declare function brandHeader(subtitle?: string): string;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-dependency terminal theming. All color/format helpers no-op when color
|
|
3
|
+
* is not supported (not a TTY, `NO_COLOR` set, or a dumb terminal), so output
|
|
4
|
+
* stays clean when piped or captured. UI is written to stderr by convention so
|
|
5
|
+
* the bridge server's stdout (JSON logs) stays pristine.
|
|
6
|
+
*/
|
|
7
|
+
/** True when ANSI styling should be emitted to the given stream. */
|
|
8
|
+
export function supportsColor(stream = process.stderr) {
|
|
9
|
+
if (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== "")
|
|
10
|
+
return false;
|
|
11
|
+
if (process.env.FORCE_COLOR !== undefined && process.env.FORCE_COLOR !== "0")
|
|
12
|
+
return true;
|
|
13
|
+
if (process.env.TERM === "dumb")
|
|
14
|
+
return false;
|
|
15
|
+
return Boolean(stream.isTTY);
|
|
16
|
+
}
|
|
17
|
+
function wrap(open, close) {
|
|
18
|
+
return (text) => supportsColor() ? `\u001b[${open}m${text}\u001b[${close}m` : text;
|
|
19
|
+
}
|
|
20
|
+
export const bold = wrap(1, 22);
|
|
21
|
+
export const dim = wrap(2, 22);
|
|
22
|
+
export const italic = wrap(3, 23);
|
|
23
|
+
export const underline = wrap(4, 24);
|
|
24
|
+
export const red = wrap(31, 39);
|
|
25
|
+
export const green = wrap(32, 39);
|
|
26
|
+
export const yellow = wrap(33, 39);
|
|
27
|
+
export const blue = wrap(34, 39);
|
|
28
|
+
export const magenta = wrap(35, 39);
|
|
29
|
+
export const cyan = wrap(36, 39);
|
|
30
|
+
export const gray = wrap(90, 39);
|
|
31
|
+
/** Status glyphs, with ASCII fallbacks when color (≈ unicode-friendly TTY) is off. */
|
|
32
|
+
export const glyph = {
|
|
33
|
+
tick: () => (supportsColor() ? "\u2714" : "[ok]"),
|
|
34
|
+
cross: () => (supportsColor() ? "\u2716" : "[x]"),
|
|
35
|
+
bullet: () => (supportsColor() ? "\u2022" : "*"),
|
|
36
|
+
arrow: () => (supportsColor() ? "\u203a" : ">"),
|
|
37
|
+
pointer: () => (supportsColor() ? "\u276f" : ">"),
|
|
38
|
+
warn: () => (supportsColor() ? "\u26a0" : "[!]"),
|
|
39
|
+
pending: () => (supportsColor() ? "\u25cb" : "( )"),
|
|
40
|
+
};
|
|
41
|
+
/** Frames for the in-place spinner (braille dots when color is on). */
|
|
42
|
+
export const SPINNER_FRAMES = supportsColorFrames();
|
|
43
|
+
function supportsColorFrames() {
|
|
44
|
+
return [
|
|
45
|
+
"\u280b",
|
|
46
|
+
"\u2819",
|
|
47
|
+
"\u2839",
|
|
48
|
+
"\u2838",
|
|
49
|
+
"\u283c",
|
|
50
|
+
"\u2834",
|
|
51
|
+
"\u2826",
|
|
52
|
+
"\u2827",
|
|
53
|
+
"\u2807",
|
|
54
|
+
"\u280f",
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
/** The product banner shown atop interactive surfaces. */
|
|
58
|
+
export function brandHeader(subtitle) {
|
|
59
|
+
const title = bold(cyan("cursorkit"));
|
|
60
|
+
const tag = dim("local model bridge for Cursor");
|
|
61
|
+
const head = `${title} ${tag}`;
|
|
62
|
+
return subtitle === undefined ? head : `${head}\n${dim(subtitle)}`;
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velum-labs/cursorkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Unofficial research bridge for experimenting with Cursor's ConnectRPC protocol against a self-hosted OpenAI-compatible model.",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"bin": {
|
|
42
|
-
"ck": "./dist/src/ck.js",
|
|
43
42
|
"cursorkit": "./dist/src/cli.js"
|
|
44
43
|
},
|
|
45
44
|
"files": [
|
|
@@ -53,6 +52,7 @@
|
|
|
53
52
|
"@bufbuild/protobuf": "^2.12.0",
|
|
54
53
|
"@connectrpc/connect": "^2.1.2",
|
|
55
54
|
"@connectrpc/connect-node": "^2.1.2",
|
|
55
|
+
"commander": "14.0.3",
|
|
56
56
|
"protobufjs": "8.6.3",
|
|
57
57
|
"selfsigned": "5.5.0",
|
|
58
58
|
"undici": "8.5.0"
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"@bufbuild/protoc-gen-es": "^2.12.0",
|
|
63
63
|
"@types/node": "24.10.1",
|
|
64
64
|
"@velum-labs/model-fusion-protocol": "0.1.1",
|
|
65
|
+
"@vitest/coverage-v8": "4.1.8",
|
|
65
66
|
"prettier": "3.8.4",
|
|
66
67
|
"tsx": "4.22.4",
|
|
67
68
|
"typescript": "6.0.3",
|
|
@@ -78,6 +79,7 @@
|
|
|
78
79
|
"baseline:generate": "tsx src/tools/baselineInventory.ts",
|
|
79
80
|
"baseline:check": "tsx src/tools/baselineInventory.ts --check",
|
|
80
81
|
"test": "vitest run tests",
|
|
82
|
+
"test:coverage": "vitest run --coverage",
|
|
81
83
|
"e2e:cursor-agent": "python3 tests/e2e/cursor-agent-smoke.py",
|
|
82
84
|
"model-fusion:protocol:check": "tsx src/tools/checkModelFusionProtocol.ts",
|
|
83
85
|
"release:publish:check": "tsx src/tools/checkReleasePublishConfig.ts",
|
|
@@ -87,7 +89,7 @@
|
|
|
87
89
|
"release:check": "tsx src/tools/releaseCheck.ts",
|
|
88
90
|
"serve": "node dist/src/cli.js serve",
|
|
89
91
|
"dev": "tsx src/cli.ts serve",
|
|
90
|
-
"ck": "node dist/src/
|
|
92
|
+
"ck": "node dist/src/cli.js ck",
|
|
91
93
|
"test:harness": "node dist/src/testing/cli.js"
|
|
92
94
|
}
|
|
93
95
|
}
|
package/dist/src/ck.d.ts
DELETED