peri-fuse 0.1.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.
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.logsCommand = logsCommand;
37
+ /**
38
+ * `peri-fuse logs` — view the background server's log output.
39
+ *
40
+ * Default: print the last N lines. With -f/--follow: stream new lines as they
41
+ * are appended (Node-based tail, cross-platform, no system `tail` dependency).
42
+ */
43
+ const fs = __importStar(require("node:fs"));
44
+ const output_1 = require("../lib/output");
45
+ const paths_1 = require("../lib/paths");
46
+ /** Read the last `n` lines of a file efficiently enough for our log sizes. */
47
+ function tailLines(file, n) {
48
+ const content = fs.readFileSync(file, "utf8");
49
+ const lines = content.split("\n");
50
+ // Drop a trailing empty element from a final newline.
51
+ if (lines.length > 0 && lines[lines.length - 1] === "")
52
+ lines.pop();
53
+ return lines.slice(-n);
54
+ }
55
+ async function logsCommand(opts) {
56
+ const state = (0, paths_1.readState)();
57
+ const file = state?.logFile ?? (0, paths_1.logFile)();
58
+ if (!fs.existsSync(file)) {
59
+ output_1.output.info("No log file yet. Start the server first: peri-fuse start");
60
+ return;
61
+ }
62
+ const n = opts.lines ? parseInt(opts.lines, 10) : 50;
63
+ const count = Number.isFinite(n) && n > 0 ? n : 50;
64
+ // Print the initial tail.
65
+ for (const line of tailLines(file, count)) {
66
+ output_1.output.plain(line);
67
+ }
68
+ if (!opts.follow)
69
+ return;
70
+ // Follow mode: watch for appends and print new content incrementally.
71
+ output_1.output.dim(`\n--- following ${file} (Ctrl+C to stop) ---\n`);
72
+ let offset = fs.statSync(file).size;
73
+ const printNew = () => {
74
+ const stat = fs.statSync(file);
75
+ if (stat.size < offset) {
76
+ // File was truncated/rotated — reset.
77
+ offset = 0;
78
+ }
79
+ if (stat.size > offset) {
80
+ const fd = fs.openSync(file, "r");
81
+ const buf = Buffer.alloc(stat.size - offset);
82
+ fs.readSync(fd, buf, 0, buf.length, offset);
83
+ fs.closeSync(fd);
84
+ offset = stat.size;
85
+ process.stdout.write(buf.toString("utf8"));
86
+ }
87
+ };
88
+ fs.watch(file, () => {
89
+ try {
90
+ printNew();
91
+ }
92
+ catch {
93
+ /* file may be mid-write; ignore */
94
+ }
95
+ });
96
+ // Keep the process alive until interrupted.
97
+ await new Promise((resolve) => {
98
+ process.on("SIGINT", () => resolve());
99
+ process.on("SIGTERM", () => resolve());
100
+ });
101
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.restartCommand = restartCommand;
4
+ /**
5
+ * `peri-fuse restart` — stop then start the background server.
6
+ */
7
+ const daemon_1 = require("../lib/daemon");
8
+ const output_1 = require("../lib/output");
9
+ async function restartCommand() {
10
+ const { wasRunning } = await (0, daemon_1.stopServer)();
11
+ if (wasRunning) {
12
+ output_1.output.success("Server stopped.");
13
+ }
14
+ let result;
15
+ try {
16
+ result = (0, daemon_1.startServer)();
17
+ }
18
+ catch (err) {
19
+ output_1.output.error(err instanceof Error ? err.message : String(err));
20
+ process.exitCode = 1;
21
+ return;
22
+ }
23
+ const { state } = result;
24
+ output_1.output.info(`Starting server (pid ${state.pid}, port ${state.port})…`);
25
+ const healthy = await (0, daemon_1.waitForHealthy)(state.port);
26
+ if (healthy) {
27
+ output_1.output.success(`Server is up at http://localhost:${state.port}`);
28
+ }
29
+ else {
30
+ output_1.output.warn(`Server process started (pid ${state.pid}) but health check did not respond.`);
31
+ output_1.output.dim(` Check the logs: peri-fuse logs -n 50`);
32
+ }
33
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startCommand = startCommand;
4
+ /**
5
+ * `peri-fuse start` — launch the server as a background daemon.
6
+ */
7
+ const daemon_1 = require("../lib/daemon");
8
+ const output_1 = require("../lib/output");
9
+ async function startCommand() {
10
+ let result;
11
+ try {
12
+ result = (0, daemon_1.startServer)();
13
+ }
14
+ catch (err) {
15
+ output_1.output.error(err instanceof Error ? err.message : String(err));
16
+ process.exitCode = 1;
17
+ return;
18
+ }
19
+ const { state, alreadyRunning } = result;
20
+ if (alreadyRunning) {
21
+ output_1.output.info(`Server already running (pid ${state.pid}, port ${state.port}).`);
22
+ return;
23
+ }
24
+ output_1.output.info(`Starting server (pid ${state.pid}, port ${state.port})…`);
25
+ const healthy = await (0, daemon_1.waitForHealthy)(state.port);
26
+ if (healthy) {
27
+ output_1.output.success(`Server is up at http://localhost:${state.port}`);
28
+ output_1.output.dim(` logs: peri-fuse logs -f`);
29
+ output_1.output.dim(` stop: peri-fuse stop`);
30
+ }
31
+ else {
32
+ output_1.output.warn(`Server process started (pid ${state.pid}) but health check did not respond.`);
33
+ output_1.output.dim(` Check the logs: peri-fuse logs -n 50`);
34
+ }
35
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.statusCommand = statusCommand;
7
+ /**
8
+ * `peri-fuse status` — show whether the background server is running.
9
+ */
10
+ const picocolors_1 = __importDefault(require("picocolors"));
11
+ const daemon_1 = require("../lib/daemon");
12
+ const output_1 = require("../lib/output");
13
+ const paths_1 = require("../lib/paths");
14
+ async function statusCommand() {
15
+ const state = (0, paths_1.readState)();
16
+ if (!state) {
17
+ output_1.output.info(`Server is ${picocolors_1.default.bold("not running")}.`);
18
+ output_1.output.dim(" Start it with: peri-fuse start");
19
+ return;
20
+ }
21
+ if (!(0, daemon_1.isAlive)(state.pid)) {
22
+ output_1.output.warn(`Server is ${picocolors_1.default.bold("not running")} (stale state for pid ${state.pid} removed).`);
23
+ (0, paths_1.clearState)();
24
+ return;
25
+ }
26
+ const healthy = await (0, daemon_1.checkHealth)(state.port);
27
+ const uptime = (0, output_1.formatUptime)(Date.now() - state.startedAt);
28
+ output_1.output.success(`Server is ${picocolors_1.default.bold("running")}.`);
29
+ output_1.output.plain(` pid: ${state.pid}`);
30
+ output_1.output.plain(` port: ${state.port}`);
31
+ output_1.output.plain(` url: http://localhost:${state.port}`);
32
+ output_1.output.plain(` uptime: ${uptime}`);
33
+ output_1.output.plain(` health: ${healthy ? picocolors_1.default.green("ok") : picocolors_1.default.yellow("not responding")}`);
34
+ output_1.output.plain(` log: ${state.logFile}`);
35
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stopCommand = stopCommand;
4
+ /**
5
+ * `peri-fuse stop` — stop the background server.
6
+ */
7
+ const daemon_1 = require("../lib/daemon");
8
+ const output_1 = require("../lib/output");
9
+ async function stopCommand() {
10
+ output_1.output.info("Stopping server…");
11
+ const { stopped, wasRunning } = await (0, daemon_1.stopServer)();
12
+ if (!wasRunning) {
13
+ output_1.output.info("Server is not running.");
14
+ return;
15
+ }
16
+ if (stopped) {
17
+ output_1.output.success("Server stopped.");
18
+ }
19
+ else {
20
+ output_1.output.warn("Server may not have stopped cleanly.");
21
+ }
22
+ }
@@ -0,0 +1,160 @@
1
+ CREATE TABLE `ApiKey` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `publicKey` text NOT NULL,
4
+ `keyName` text,
5
+ `spend` real DEFAULT 0 NOT NULL,
6
+ `models` text DEFAULT '[]' NOT NULL,
7
+ `metadata` text DEFAULT '{}' NOT NULL,
8
+ `maxParallel` integer,
9
+ `tpmLimit` integer,
10
+ `rpmLimit` integer,
11
+ `maxBudget` real,
12
+ `budgetId` text,
13
+ `isEnabled` integer DEFAULT true NOT NULL,
14
+ `lastActive` text,
15
+ `createdAt` text NOT NULL,
16
+ `updatedAt` text NOT NULL,
17
+ FOREIGN KEY (`budgetId`) REFERENCES `Budget`(`id`) ON UPDATE no action ON DELETE no action
18
+ );
19
+ --> statement-breakpoint
20
+ CREATE UNIQUE INDEX `ApiKey_publicKey_unique` ON `ApiKey` (`publicKey`);--> statement-breakpoint
21
+ CREATE INDEX `ApiKey_publicKey_idx` ON `ApiKey` (`publicKey`);--> statement-breakpoint
22
+ CREATE TABLE `AuditLog` (
23
+ `id` text PRIMARY KEY NOT NULL,
24
+ `action` text NOT NULL,
25
+ `tableName` text NOT NULL,
26
+ `objectId` text NOT NULL,
27
+ `beforeValue` text,
28
+ `afterValue` text,
29
+ `changedBy` text DEFAULT '' NOT NULL,
30
+ `createdAt` text NOT NULL
31
+ );
32
+ --> statement-breakpoint
33
+ CREATE INDEX `AuditLog_tableName_objectId_idx` ON `AuditLog` (`tableName`,`objectId`);--> statement-breakpoint
34
+ CREATE INDEX `AuditLog_createdAt_idx` ON `AuditLog` (`createdAt`);--> statement-breakpoint
35
+ CREATE TABLE `Budget` (
36
+ `id` text PRIMARY KEY NOT NULL,
37
+ `maxBudget` real,
38
+ `softBudget` real,
39
+ `maxParallel` integer,
40
+ `tpmLimit` integer,
41
+ `rpmLimit` integer,
42
+ `duration` text,
43
+ `resetAt` text,
44
+ `modelMaxBudget` text,
45
+ `createdAt` text NOT NULL,
46
+ `updatedAt` text NOT NULL
47
+ );
48
+ --> statement-breakpoint
49
+ CREATE TABLE `Credential` (
50
+ `id` text PRIMARY KEY NOT NULL,
51
+ `name` text NOT NULL,
52
+ `values` text NOT NULL,
53
+ `info` text,
54
+ `createdAt` text NOT NULL,
55
+ `updatedAt` text NOT NULL
56
+ );
57
+ --> statement-breakpoint
58
+ CREATE UNIQUE INDEX `Credential_name_unique` ON `Credential` (`name`);--> statement-breakpoint
59
+ CREATE TABLE `DailySpend` (
60
+ `id` text PRIMARY KEY NOT NULL,
61
+ `apiKey` text NOT NULL,
62
+ `date` text NOT NULL,
63
+ `model` text,
64
+ `modelGroup` text,
65
+ `provider` text,
66
+ `promptTokens` integer DEFAULT 0 NOT NULL,
67
+ `completionTokens` integer DEFAULT 0 NOT NULL,
68
+ `spend` real DEFAULT 0 NOT NULL,
69
+ `apiRequests` integer DEFAULT 0 NOT NULL,
70
+ `successfulRequests` integer DEFAULT 0 NOT NULL,
71
+ `failedRequests` integer DEFAULT 0 NOT NULL,
72
+ `createdAt` text NOT NULL,
73
+ `updatedAt` text NOT NULL
74
+ );
75
+ --> statement-breakpoint
76
+ CREATE UNIQUE INDEX `DailySpend_apiKey_date_model_provider_key` ON `DailySpend` (`apiKey`,`date`,`model`,`provider`);--> statement-breakpoint
77
+ CREATE INDEX `DailySpend_date_idx` ON `DailySpend` (`date`);--> statement-breakpoint
78
+ CREATE INDEX `DailySpend_apiKey_date_idx` ON `DailySpend` (`apiKey`,`date`);--> statement-breakpoint
79
+ CREATE INDEX `DailySpend_model_idx` ON `DailySpend` (`model`);--> statement-breakpoint
80
+ CREATE TABLE `ErrorLog` (
81
+ `id` text PRIMARY KEY NOT NULL,
82
+ `startTime` text NOT NULL,
83
+ `endTime` text NOT NULL,
84
+ `apiBase` text DEFAULT '' NOT NULL,
85
+ `modelGroup` text DEFAULT '' NOT NULL,
86
+ `providerModel` text DEFAULT '' NOT NULL,
87
+ `modelId` text DEFAULT '' NOT NULL,
88
+ `requestKwargs` text DEFAULT '{}' NOT NULL,
89
+ `exceptionType` text DEFAULT '' NOT NULL,
90
+ `exceptionString` text DEFAULT '' NOT NULL,
91
+ `statusCode` text DEFAULT '' NOT NULL
92
+ );
93
+ --> statement-breakpoint
94
+ CREATE INDEX `ErrorLog_startTime_idx` ON `ErrorLog` (`startTime`);--> statement-breakpoint
95
+ CREATE TABLE `ModelDeployment` (
96
+ `id` text PRIMARY KEY NOT NULL,
97
+ `modelName` text NOT NULL,
98
+ `providerId` text NOT NULL,
99
+ `providerModel` text NOT NULL,
100
+ `litellmParams` text DEFAULT '{}' NOT NULL,
101
+ `modelInfo` text,
102
+ `isEnabled` integer DEFAULT true NOT NULL,
103
+ `createdAt` text NOT NULL,
104
+ `updatedAt` text NOT NULL,
105
+ FOREIGN KEY (`providerId`) REFERENCES `Provider`(`id`) ON UPDATE no action ON DELETE no action
106
+ );
107
+ --> statement-breakpoint
108
+ CREATE INDEX `ModelDeployment_modelName_isEnabled_idx` ON `ModelDeployment` (`modelName`,`isEnabled`);--> statement-breakpoint
109
+ CREATE TABLE `Provider` (
110
+ `id` text PRIMARY KEY NOT NULL,
111
+ `name` text NOT NULL,
112
+ `type` text NOT NULL,
113
+ `credentialId` text,
114
+ `baseUrl` text NOT NULL,
115
+ `apiKeyEncrypted` text,
116
+ `isEnabled` integer DEFAULT true NOT NULL,
117
+ `budgetLimit` real,
118
+ `budgetPeriod` text,
119
+ `budgetSpend` real DEFAULT 0 NOT NULL,
120
+ `budgetResetAt` text,
121
+ `status` text DEFAULT 'healthy' NOT NULL,
122
+ `cooldownUntil` text,
123
+ `createdAt` text NOT NULL,
124
+ `updatedAt` text NOT NULL
125
+ );
126
+ --> statement-breakpoint
127
+ CREATE UNIQUE INDEX `Provider_name_unique` ON `Provider` (`name`);--> statement-breakpoint
128
+ CREATE TABLE `SpendLog` (
129
+ `id` text PRIMARY KEY NOT NULL,
130
+ `callType` text NOT NULL,
131
+ `apiKey` text DEFAULT '' NOT NULL,
132
+ `spend` real DEFAULT 0 NOT NULL,
133
+ `totalTokens` integer DEFAULT 0 NOT NULL,
134
+ `promptTokens` integer DEFAULT 0 NOT NULL,
135
+ `completionTokens` integer DEFAULT 0 NOT NULL,
136
+ `startTime` text NOT NULL,
137
+ `endTime` text NOT NULL,
138
+ `completionStartTime` text,
139
+ `requestDurationMs` integer,
140
+ `model` text DEFAULT '' NOT NULL,
141
+ `modelId` text,
142
+ `modelGroup` text,
143
+ `provider` text,
144
+ `apiBase` text,
145
+ `protocol` text,
146
+ `user` text,
147
+ `metadata` text DEFAULT '{}' NOT NULL,
148
+ `requestTags` text DEFAULT '[]' NOT NULL,
149
+ `sessionId` text,
150
+ `status` text,
151
+ `messages` text,
152
+ `response` text,
153
+ `errorMessage` text,
154
+ `traceId` text
155
+ );
156
+ --> statement-breakpoint
157
+ CREATE INDEX `SpendLog_startTime_idx` ON `SpendLog` (`startTime`);--> statement-breakpoint
158
+ CREATE INDEX `SpendLog_apiKey_startTime_idx` ON `SpendLog` (`apiKey`,`startTime`);--> statement-breakpoint
159
+ CREATE INDEX `SpendLog_model_startTime_idx` ON `SpendLog` (`model`,`startTime`);--> statement-breakpoint
160
+ CREATE INDEX `SpendLog_sessionId_idx` ON `SpendLog` (`sessionId`);