@grackle-ai/server 0.0.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 +5 -0
- package/dist/adapter-manager.d.ts +18 -0
- package/dist/adapter-manager.d.ts.map +1 -0
- package/dist/adapter-manager.js +67 -0
- package/dist/adapter-manager.js.map +1 -0
- package/dist/adapters/adapter.d.ts +40 -0
- package/dist/adapters/adapter.d.ts.map +1 -0
- package/dist/adapters/adapter.js +2 -0
- package/dist/adapters/adapter.js.map +1 -0
- package/dist/adapters/docker.d.ts +26 -0
- package/dist/adapters/docker.d.ts.map +1 -0
- package/dist/adapters/docker.js +274 -0
- package/dist/adapters/docker.js.map +1 -0
- package/dist/adapters/local.d.ts +15 -0
- package/dist/adapters/local.d.ts.map +1 -0
- package/dist/adapters/local.js +57 -0
- package/dist/adapters/local.js.map +1 -0
- package/dist/adapters/powerline-transport.d.ts +7 -0
- package/dist/adapters/powerline-transport.d.ts.map +1 -0
- package/dist/adapters/powerline-transport.js +22 -0
- package/dist/adapters/powerline-transport.js.map +1 -0
- package/dist/api-key.d.ts +8 -0
- package/dist/api-key.d.ts.map +1 -0
- package/dist/api-key.js +58 -0
- package/dist/api-key.js.map +1 -0
- package/dist/crypto.d.ts +5 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +74 -0
- package/dist/crypto.js.map +1 -0
- package/dist/db.d.ts +11 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +140 -0
- package/dist/db.js.map +1 -0
- package/dist/env-registry.d.ts +20 -0
- package/dist/env-registry.d.ts.map +1 -0
- package/dist/env-registry.js +55 -0
- package/dist/env-registry.js.map +1 -0
- package/dist/finding-store.d.ts +9 -0
- package/dist/finding-store.d.ts.map +1 -0
- package/dist/finding-store.js +68 -0
- package/dist/finding-store.js.map +1 -0
- package/dist/grpc-service.d.ts +4 -0
- package/dist/grpc-service.d.ts.map +1 -0
- package/dist/grpc-service.js +594 -0
- package/dist/grpc-service.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +108 -0
- package/dist/index.js.map +1 -0
- package/dist/json-helpers.d.ts +7 -0
- package/dist/json-helpers.d.ts.map +1 -0
- package/dist/json-helpers.js +22 -0
- package/dist/json-helpers.js.map +1 -0
- package/dist/log-writer.d.ts +18 -0
- package/dist/log-writer.d.ts.map +1 -0
- package/dist/log-writer.js +44 -0
- package/dist/log-writer.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +10 -0
- package/dist/logger.js.map +1 -0
- package/dist/paths.d.ts +7 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +12 -0
- package/dist/paths.js.map +1 -0
- package/dist/project-store.d.ts +11 -0
- package/dist/project-store.d.ts.map +1 -0
- package/dist/project-store.js +32 -0
- package/dist/project-store.js.map +1 -0
- package/dist/schema.d.ts +1199 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +82 -0
- package/dist/schema.js.map +1 -0
- package/dist/session-store.d.ts +22 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +73 -0
- package/dist/session-store.js.map +1 -0
- package/dist/stream-hub.d.ts +14 -0
- package/dist/stream-hub.d.ts.map +1 -0
- package/dist/stream-hub.js +95 -0
- package/dist/stream-hub.js.map +1 -0
- package/dist/task-store.d.ts +28 -0
- package/dist/task-store.d.ts.map +1 -0
- package/dist/task-store.js +121 -0
- package/dist/task-store.js.map +1 -0
- package/dist/token-broker.d.ts +27 -0
- package/dist/token-broker.d.ts.map +1 -0
- package/dist/token-broker.js +76 -0
- package/dist/token-broker.js.map +1 -0
- package/dist/transcript.d.ts +5 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +51 -0
- package/dist/transcript.js.map +1 -0
- package/dist/utils/exec.d.ts +17 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +21 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/ports.d.ts +3 -0
- package/dist/utils/ports.d.ts.map +1 -0
- package/dist/utils/ports.js +19 -0
- package/dist/utils/ports.js.map +1 -0
- package/dist/utils/sleep.d.ts +3 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +5 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/ws-bridge.d.ts +10 -0
- package/dist/ws-bridge.d.ts.map +1 -0
- package/dist/ws-bridge.js +846 -0
- package/dist/ws-bridge.js.map +1 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { connectNodeAdapter } from "@connectrpc/connect-node";
|
|
2
|
+
import { ConnectError, Code } from "@connectrpc/connect";
|
|
3
|
+
import http2 from "node:http2";
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
import { registerGrackleRoutes } from "./grpc-service.js";
|
|
6
|
+
import { registerAdapter, startHeartbeat } from "./adapter-manager.js";
|
|
7
|
+
import { updateEnvironmentStatus, resetAllStatuses } from "./env-registry.js";
|
|
8
|
+
import { DockerAdapter } from "./adapters/docker.js";
|
|
9
|
+
import { LocalAdapter } from "./adapters/local.js";
|
|
10
|
+
import { createWsBridge } from "./ws-bridge.js";
|
|
11
|
+
import { DEFAULT_SERVER_PORT, DEFAULT_WEB_PORT } from "@grackle-ai/common";
|
|
12
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
13
|
+
import { join, extname } from "node:path";
|
|
14
|
+
import { loadOrCreateApiKey, verifyApiKey } from "./api-key.js";
|
|
15
|
+
import { logger } from "./logger.js";
|
|
16
|
+
// Import db to ensure tables are created
|
|
17
|
+
import "./db.js";
|
|
18
|
+
const MIME_TYPES = {
|
|
19
|
+
".html": "text/html",
|
|
20
|
+
".js": "application/javascript",
|
|
21
|
+
".css": "text/css",
|
|
22
|
+
".json": "application/json",
|
|
23
|
+
".svg": "image/svg+xml",
|
|
24
|
+
".png": "image/png",
|
|
25
|
+
".ico": "image/x-icon",
|
|
26
|
+
};
|
|
27
|
+
function createWebHandler(apiKey) {
|
|
28
|
+
return (req, res) => {
|
|
29
|
+
const webDistDir = process.env.GRACKLE_WEB_DIR || join(import.meta.dirname, "../../web/dist");
|
|
30
|
+
let filePath = join(webDistDir, req.url === "/" ? "index.html" : (req.url || "index.html").split("?")[0]);
|
|
31
|
+
if (!existsSync(filePath)) {
|
|
32
|
+
// SPA fallback
|
|
33
|
+
filePath = join(webDistDir, "index.html");
|
|
34
|
+
}
|
|
35
|
+
if (!existsSync(filePath)) {
|
|
36
|
+
res.writeHead(404);
|
|
37
|
+
res.end("Not found");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const ext = extname(filePath);
|
|
41
|
+
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
42
|
+
try {
|
|
43
|
+
let content = readFileSync(filePath);
|
|
44
|
+
// Inject API key into HTML pages — safe because only localhost can access
|
|
45
|
+
if (ext === ".html") {
|
|
46
|
+
const html = content.toString("utf8");
|
|
47
|
+
const injected = html.replace("</head>", `<script>window.__GRACKLE_API_KEY__="${apiKey}";</script>\n</head>`);
|
|
48
|
+
content = Buffer.from(injected, "utf8");
|
|
49
|
+
}
|
|
50
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
51
|
+
res.end(content);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
res.writeHead(500);
|
|
55
|
+
res.end("Server error");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function main() {
|
|
60
|
+
// Reset all environment statuses on startup — in-memory connections are lost
|
|
61
|
+
resetAllStatuses();
|
|
62
|
+
// Load (or generate) the API key on startup
|
|
63
|
+
const apiKey = loadOrCreateApiKey();
|
|
64
|
+
// Register adapters
|
|
65
|
+
registerAdapter(new DockerAdapter());
|
|
66
|
+
registerAdapter(new LocalAdapter());
|
|
67
|
+
// Start heartbeat
|
|
68
|
+
startHeartbeat((environmentId) => {
|
|
69
|
+
updateEnvironmentStatus(environmentId, "disconnected");
|
|
70
|
+
});
|
|
71
|
+
// --- gRPC server (HTTP/2) ---
|
|
72
|
+
const grpcPort = parseInt(process.env.GRACKLE_PORT || String(DEFAULT_SERVER_PORT), 10);
|
|
73
|
+
const grpcHandler = connectNodeAdapter({
|
|
74
|
+
routes: registerGrackleRoutes,
|
|
75
|
+
interceptors: [
|
|
76
|
+
(next) => async (req) => {
|
|
77
|
+
const authHeader = req.header.get("authorization") || "";
|
|
78
|
+
const token = authHeader.replace(/^Bearer\s+/i, "");
|
|
79
|
+
if (!verifyApiKey(token)) {
|
|
80
|
+
throw new ConnectError("Unauthorized", Code.Unauthenticated);
|
|
81
|
+
}
|
|
82
|
+
return next(req);
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
const grpcServer = http2.createServer(grpcHandler);
|
|
87
|
+
grpcServer.listen(grpcPort, "127.0.0.1", () => {
|
|
88
|
+
logger.info({ port: grpcPort }, "gRPC server listening on http://127.0.0.1:%d", grpcPort);
|
|
89
|
+
});
|
|
90
|
+
// --- Web + WebSocket server (HTTP/1.1) ---
|
|
91
|
+
const webPort = parseInt(process.env.GRACKLE_WEB_PORT || String(DEFAULT_WEB_PORT), 10);
|
|
92
|
+
const webServer = http.createServer(createWebHandler(apiKey));
|
|
93
|
+
createWsBridge(webServer, verifyApiKey);
|
|
94
|
+
webServer.listen(webPort, "127.0.0.1", () => {
|
|
95
|
+
logger.info({ port: webPort }, "Web UI + WebSocket on http://127.0.0.1:%d", webPort);
|
|
96
|
+
});
|
|
97
|
+
// Graceful shutdown
|
|
98
|
+
function shutdown() {
|
|
99
|
+
logger.info("Shutting down...");
|
|
100
|
+
grpcServer.close();
|
|
101
|
+
webServer.close();
|
|
102
|
+
process.exit(0);
|
|
103
|
+
}
|
|
104
|
+
process.on("SIGINT", shutdown);
|
|
105
|
+
process.on("SIGTERM", shutdown);
|
|
106
|
+
}
|
|
107
|
+
main();
|
|
108
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely parse a JSON string that is expected to contain an array of strings.
|
|
3
|
+
* Returns the parsed array on success, or an empty array if the value is
|
|
4
|
+
* null, undefined, empty, or contains malformed JSON.
|
|
5
|
+
*/
|
|
6
|
+
export declare function safeParseJsonArray(value: string | null | undefined): string[];
|
|
7
|
+
//# sourceMappingURL=json-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-helpers.d.ts","sourceRoot":"","sources":["../src/json-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAa7E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely parse a JSON string that is expected to contain an array of strings.
|
|
3
|
+
* Returns the parsed array on success, or an empty array if the value is
|
|
4
|
+
* null, undefined, empty, or contains malformed JSON.
|
|
5
|
+
*/
|
|
6
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
7
|
+
export function safeParseJsonArray(value) {
|
|
8
|
+
if (!value) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(value);
|
|
13
|
+
if (Array.isArray(parsed)) {
|
|
14
|
+
return parsed.filter((item) => typeof item === "string");
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=json-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-helpers.js","sourceRoot":"","sources":["../src/json-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,kDAAkD;AAClD,MAAM,UAAU,kBAAkB,CAAC,KAAgC;IACjE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { grackle } from "@grackle-ai/common";
|
|
2
|
+
/** Initialize a JSONL log stream for a session at the given directory path. */
|
|
3
|
+
export declare function initLog(logPath: string): void;
|
|
4
|
+
/** Append a session event as a JSON line to the session's log file. */
|
|
5
|
+
export declare function writeEvent(logPath: string, event: grackle.SessionEvent): void;
|
|
6
|
+
/** Close the write stream for a session log. */
|
|
7
|
+
export declare function endSession(logPath: string): void;
|
|
8
|
+
/** Deserialized shape of a single line in a session's `stream.jsonl` log. */
|
|
9
|
+
export interface LogEntry {
|
|
10
|
+
session_id: string;
|
|
11
|
+
type: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
content: string;
|
|
14
|
+
raw?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Read and parse all log entries from a session's JSONL log file. */
|
|
17
|
+
export declare function readLog(logPath: string): LogEntry[];
|
|
18
|
+
//# sourceMappingURL=log-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-writer.d.ts","sourceRoot":"","sources":["../src/log-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIlD,+EAA+E;AAC/E,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAK7C;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,GAAG,IAAI,CAa7E;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMhD;AAED,6EAA6E;AAC7E,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,sEAAsE;AACtE,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CASnD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createWriteStream, mkdirSync, readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const openStreams = new Map();
|
|
4
|
+
/** Initialize a JSONL log stream for a session at the given directory path. */
|
|
5
|
+
export function initLog(logPath) {
|
|
6
|
+
mkdirSync(logPath, { recursive: true });
|
|
7
|
+
const streamPath = join(logPath, "stream.jsonl");
|
|
8
|
+
const ws = createWriteStream(streamPath, { flags: "a" });
|
|
9
|
+
openStreams.set(logPath, ws);
|
|
10
|
+
}
|
|
11
|
+
/** Append a session event as a JSON line to the session's log file. */
|
|
12
|
+
export function writeEvent(logPath, event) {
|
|
13
|
+
const ws = openStreams.get(logPath);
|
|
14
|
+
if (!ws)
|
|
15
|
+
return;
|
|
16
|
+
const line = JSON.stringify({
|
|
17
|
+
session_id: event.sessionId,
|
|
18
|
+
type: event.type,
|
|
19
|
+
timestamp: event.timestamp,
|
|
20
|
+
content: event.content,
|
|
21
|
+
raw: event.raw || undefined,
|
|
22
|
+
});
|
|
23
|
+
ws.write(line + "\n");
|
|
24
|
+
}
|
|
25
|
+
/** Close the write stream for a session log. */
|
|
26
|
+
export function endSession(logPath) {
|
|
27
|
+
const ws = openStreams.get(logPath);
|
|
28
|
+
if (ws) {
|
|
29
|
+
ws.end();
|
|
30
|
+
openStreams.delete(logPath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Read and parse all log entries from a session's JSONL log file. */
|
|
34
|
+
export function readLog(logPath) {
|
|
35
|
+
const streamPath = join(logPath, "stream.jsonl");
|
|
36
|
+
if (!existsSync(streamPath))
|
|
37
|
+
return [];
|
|
38
|
+
const content = readFileSync(streamPath, "utf-8");
|
|
39
|
+
return content
|
|
40
|
+
.split("\n")
|
|
41
|
+
.filter((line) => line.trim())
|
|
42
|
+
.map((line) => JSON.parse(line));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=log-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-writer.js","sourceRoot":"","sources":["../src/log-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAoB,MAAM,SAAS,CAAC;AACnG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,WAAW,GAA6B,IAAI,GAAG,EAAuB,CAAC;AAE7E,+EAA+E;AAC/E,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,iBAAiB,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACzD,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,KAA2B;IACrE,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,EAAE;QAAE,OAAO;IAEhB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,UAAU,EAAE,KAAK,CAAC,SAAS;QAC3B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,SAAS;KAC5B,CAAC,CAAC;IAEH,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,EAAE,EAAE,CAAC;QACP,EAAE,CAAC,GAAG,EAAE,CAAC;QACT,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAWD,sEAAsE;AACtE,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvC,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,OAAO;SACX,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC7B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAa,CAAC,CAAC;AACjD,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAEzC,iDAAiD;AACjD,eAAO,MAAM,MAAM,EAAE,MAMnB,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
/** Application logger for the Grackle server. */
|
|
3
|
+
export const logger = pino({
|
|
4
|
+
name: "grackle-server",
|
|
5
|
+
level: process.env.LOG_LEVEL || "info",
|
|
6
|
+
transport: process.env.NODE_ENV !== "production"
|
|
7
|
+
? { target: "pino/file", options: { destination: 1 } }
|
|
8
|
+
: undefined,
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAqB,MAAM,MAAM,CAAC;AAEzC,iDAAiD;AACjD,MAAM,CAAC,MAAM,MAAM,GAAW,IAAI,CAAC;IACjC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IACtC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QAC9C,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,EAAE;QACtD,CAAC,CAAC,SAAS;CACd,CAAC,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the root Grackle data directory. Uses `GRACKLE_HOME` env var if set,
|
|
3
|
+
* otherwise falls back to `~/.grackle`. This allows test isolation by pointing
|
|
4
|
+
* to a temp directory.
|
|
5
|
+
*/
|
|
6
|
+
export declare const grackleHome: string;
|
|
7
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,MAGQ,CAAC"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { GRACKLE_DIR } from "@grackle-ai/common";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the root Grackle data directory. Uses `GRACKLE_HOME` env var if set,
|
|
6
|
+
* otherwise falls back to `~/.grackle`. This allows test isolation by pointing
|
|
7
|
+
* to a temp directory.
|
|
8
|
+
*/
|
|
9
|
+
export const grackleHome = process.env.GRACKLE_HOME
|
|
10
|
+
? join(process.env.GRACKLE_HOME, GRACKLE_DIR)
|
|
11
|
+
: join(homedir(), GRACKLE_DIR);
|
|
12
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GACtB,OAAO,CAAC,GAAG,CAAC,YAAY;IACtB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC;IAC7C,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ProjectRow } from "./schema.js";
|
|
2
|
+
export type { ProjectRow };
|
|
3
|
+
/** Insert a new project record. */
|
|
4
|
+
export declare function createProject(id: string, name: string, description: string, repoUrl: string, defaultEnvironmentId: string): void;
|
|
5
|
+
/** Retrieve a single project by ID. */
|
|
6
|
+
export declare function getProject(id: string): ProjectRow | undefined;
|
|
7
|
+
/** Return all active projects, newest first. */
|
|
8
|
+
export declare function listProjects(): ProjectRow[];
|
|
9
|
+
/** Mark a project as archived. */
|
|
10
|
+
export declare function archiveProject(id: string): void;
|
|
11
|
+
//# sourceMappingURL=project-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-store.d.ts","sourceRoot":"","sources":["../src/project-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAGxD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,mCAAmC;AACnC,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAQhI;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAE7D;AAED,gDAAgD;AAChD,wBAAgB,YAAY,IAAI,UAAU,EAAE,CAK3C;AAED,kCAAkC;AAClC,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAK/C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import db from "./db.js";
|
|
2
|
+
import { projects } from "./schema.js";
|
|
3
|
+
import { eq, desc, sql } from "drizzle-orm";
|
|
4
|
+
/** Insert a new project record. */
|
|
5
|
+
export function createProject(id, name, description, repoUrl, defaultEnvironmentId) {
|
|
6
|
+
db.insert(projects).values({
|
|
7
|
+
id,
|
|
8
|
+
name,
|
|
9
|
+
description,
|
|
10
|
+
repoUrl,
|
|
11
|
+
defaultEnvironmentId,
|
|
12
|
+
}).run();
|
|
13
|
+
}
|
|
14
|
+
/** Retrieve a single project by ID. */
|
|
15
|
+
export function getProject(id) {
|
|
16
|
+
return db.select().from(projects).where(eq(projects.id, id)).get();
|
|
17
|
+
}
|
|
18
|
+
/** Return all active projects, newest first. */
|
|
19
|
+
export function listProjects() {
|
|
20
|
+
return db.select().from(projects)
|
|
21
|
+
.where(eq(projects.status, "active"))
|
|
22
|
+
.orderBy(desc(projects.createdAt))
|
|
23
|
+
.all();
|
|
24
|
+
}
|
|
25
|
+
/** Mark a project as archived. */
|
|
26
|
+
export function archiveProject(id) {
|
|
27
|
+
db.update(projects)
|
|
28
|
+
.set({ status: "archived", updatedAt: sql `datetime('now')` })
|
|
29
|
+
.where(eq(projects.id, id))
|
|
30
|
+
.run();
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=project-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-store.js","sourceRoot":"","sources":["../src/project-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAmB,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAI5C,mCAAmC;AACnC,MAAM,UAAU,aAAa,CAAC,EAAU,EAAE,IAAY,EAAE,WAAmB,EAAE,OAAe,EAAE,oBAA4B;IACxH,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;QACzB,EAAE;QACF,IAAI;QACJ,WAAW;QACX,OAAO;QACP,oBAAoB;KACrB,CAAC,CAAC,GAAG,EAAE,CAAC;AACX,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACrE,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;SAC9B,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;SACpC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;SACjC,GAAG,EAAE,CAAC;AACX,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;SAChB,GAAG,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,CAAA,iBAAiB,EAAE,CAAC;SAC5D,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;SAC1B,GAAG,EAAE,CAAC;AACX,CAAC"}
|