@promptprojectmanager/mcp-server 4.4.3 → 4.5.1

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,106 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/watcher/watcher_state.ts
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
5
+ import { join } from "path";
6
+ function getWatcherDir(workingDirectory) {
7
+ const dir = join(workingDirectory, ".ppm", "yolo");
8
+ if (!existsSync(dir)) {
9
+ mkdirSync(dir, { recursive: true });
10
+ }
11
+ return dir;
12
+ }
13
+ function getPidFile(workingDirectory) {
14
+ return join(getWatcherDir(workingDirectory), "watcher.pid");
15
+ }
16
+ function getStatusFile(workingDirectory) {
17
+ return join(getWatcherDir(workingDirectory), "status.json");
18
+ }
19
+ function writePid(workingDirectory, pid) {
20
+ const pidFile = getPidFile(workingDirectory);
21
+ writeFileSync(pidFile, pid.toString(), "utf-8");
22
+ }
23
+ function readPid(workingDirectory) {
24
+ const pidFile = getPidFile(workingDirectory);
25
+ if (!existsSync(pidFile)) {
26
+ return void 0;
27
+ }
28
+ try {
29
+ const content = readFileSync(pidFile, "utf-8").trim();
30
+ const pid = parseInt(content, 10);
31
+ return isNaN(pid) ? void 0 : pid;
32
+ } catch {
33
+ return void 0;
34
+ }
35
+ }
36
+ function removePid(workingDirectory) {
37
+ const pidFile = getPidFile(workingDirectory);
38
+ if (existsSync(pidFile)) {
39
+ try {
40
+ unlinkSync(pidFile);
41
+ } catch {
42
+ }
43
+ }
44
+ }
45
+ function isProcessRunning(pid) {
46
+ try {
47
+ process.kill(pid, 0);
48
+ return true;
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+ function isWatcherRunning(workingDirectory) {
54
+ const pid = readPid(workingDirectory);
55
+ if (pid === void 0) {
56
+ return false;
57
+ }
58
+ if (isProcessRunning(pid)) {
59
+ return true;
60
+ }
61
+ removePid(workingDirectory);
62
+ return false;
63
+ }
64
+ function writeStatus(workingDirectory, status) {
65
+ const statusFile = getStatusFile(workingDirectory);
66
+ writeFileSync(statusFile, JSON.stringify(status, null, 2), "utf-8");
67
+ }
68
+ function readStatus(workingDirectory) {
69
+ const statusFile = getStatusFile(workingDirectory);
70
+ if (!existsSync(statusFile)) {
71
+ return void 0;
72
+ }
73
+ try {
74
+ const content = readFileSync(statusFile, "utf-8");
75
+ return JSON.parse(content);
76
+ } catch {
77
+ return void 0;
78
+ }
79
+ }
80
+ function updateStatus(workingDirectory, updates) {
81
+ const current = readStatus(workingDirectory);
82
+ if (current) {
83
+ writeStatus(workingDirectory, { ...current, ...updates });
84
+ } else if (updates.state && updates.projectSlug && updates.config) {
85
+ writeStatus(workingDirectory, {
86
+ state: updates.state,
87
+ projectSlug: updates.projectSlug,
88
+ ticketsProcessed: updates.ticketsProcessed ?? 0,
89
+ currentlyExecuting: updates.currentlyExecuting ?? [],
90
+ config: updates.config,
91
+ ...updates
92
+ });
93
+ }
94
+ }
95
+
96
+ export {
97
+ writePid,
98
+ readPid,
99
+ removePid,
100
+ isProcessRunning,
101
+ isWatcherRunning,
102
+ writeStatus,
103
+ readStatus,
104
+ updateStatus
105
+ };
106
+ //# sourceMappingURL=chunk-POSCT6WJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/watcher/watcher_state.ts"],"sourcesContent":["/**\n * Watcher State Management\n *\n * Handles file-based state persistence for the YOLO watcher daemon.\n * State is stored in .ppm/yolo/ within the project directory.\n *\n * Files:\n * - watcher.pid: Process ID of running daemon\n * - status.json: Full watcher status\n * - watcher.log: Daemon log output\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from \"fs\";\nimport { join } from \"path\";\nimport type { WatcherStatus } from \"./watcher_types.js\";\n\n// ============================================================================\n// Path Utilities\n// ============================================================================\n\n/**\n * Get the watcher state directory for a project.\n * Creates the directory if it doesn't exist.\n *\n * @param workingDirectory - Project root directory\n * @returns Path to .ppm/yolo/ directory\n */\nexport function getWatcherDir(workingDirectory: string): string {\n const dir = join(workingDirectory, \".ppm\", \"yolo\");\n\n // Ensure directory exists\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n return dir;\n}\n\n/**\n * Get path to the PID file\n */\nexport function getPidFile(workingDirectory: string): string {\n return join(getWatcherDir(workingDirectory), \"watcher.pid\");\n}\n\n/**\n * Get path to the status JSON file\n */\nexport function getStatusFile(workingDirectory: string): string {\n return join(getWatcherDir(workingDirectory), \"status.json\");\n}\n\n/**\n * Get path to the log file\n */\nexport function getLogFile(workingDirectory: string): string {\n return join(getWatcherDir(workingDirectory), \"watcher.log\");\n}\n\n// ============================================================================\n// PID Management\n// ============================================================================\n\n/**\n * Write the daemon's PID to the PID file\n *\n * @param workingDirectory - Project root directory\n * @param pid - Process ID to write\n */\nexport function writePid(workingDirectory: string, pid: number): void {\n const pidFile = getPidFile(workingDirectory);\n writeFileSync(pidFile, pid.toString(), \"utf-8\");\n}\n\n/**\n * Read the daemon's PID from the PID file\n *\n * @param workingDirectory - Project root directory\n * @returns PID if file exists, undefined otherwise\n */\nexport function readPid(workingDirectory: string): number | undefined {\n const pidFile = getPidFile(workingDirectory);\n\n if (!existsSync(pidFile)) {\n return undefined;\n }\n\n try {\n const content = readFileSync(pidFile, \"utf-8\").trim();\n const pid = parseInt(content, 10);\n return isNaN(pid) ? undefined : pid;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Remove the PID file\n *\n * @param workingDirectory - Project root directory\n */\nexport function removePid(workingDirectory: string): void {\n const pidFile = getPidFile(workingDirectory);\n\n if (existsSync(pidFile)) {\n try {\n unlinkSync(pidFile);\n } catch {\n // Ignore errors during cleanup\n }\n }\n}\n\n/**\n * Check if a process with the given PID is running\n *\n * Uses process.kill(pid, 0) which doesn't actually send a signal\n * but throws if the process doesn't exist.\n *\n * @param pid - Process ID to check\n * @returns true if process is running\n */\nexport function isProcessRunning(pid: number): boolean {\n try {\n // Signal 0 doesn't kill the process, just checks if it exists\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if the watcher daemon is currently running\n *\n * Reads the PID file and verifies the process is still alive.\n * Cleans up stale PID file if process is not running.\n *\n * @param workingDirectory - Project root directory\n * @returns true if watcher is running\n */\nexport function isWatcherRunning(workingDirectory: string): boolean {\n const pid = readPid(workingDirectory);\n\n if (pid === undefined) {\n return false;\n }\n\n if (isProcessRunning(pid)) {\n return true;\n }\n\n // Stale PID file - process is not running\n // Clean up the file\n removePid(workingDirectory);\n return false;\n}\n\n// ============================================================================\n// Status Management\n// ============================================================================\n\n/**\n * Write watcher status to the status file\n *\n * @param workingDirectory - Project root directory\n * @param status - Status object to persist\n */\nexport function writeStatus(workingDirectory: string, status: WatcherStatus): void {\n const statusFile = getStatusFile(workingDirectory);\n writeFileSync(statusFile, JSON.stringify(status, null, 2), \"utf-8\");\n}\n\n/**\n * Read watcher status from the status file\n *\n * @param workingDirectory - Project root directory\n * @returns Status object if file exists and is valid, undefined otherwise\n */\nexport function readStatus(workingDirectory: string): WatcherStatus | undefined {\n const statusFile = getStatusFile(workingDirectory);\n\n if (!existsSync(statusFile)) {\n return undefined;\n }\n\n try {\n const content = readFileSync(statusFile, \"utf-8\");\n return JSON.parse(content) as WatcherStatus;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Update specific fields in the status file\n *\n * Reads current status, merges updates, and writes back.\n * Creates new status if none exists.\n *\n * @param workingDirectory - Project root directory\n * @param updates - Partial status updates to apply\n */\nexport function updateStatus(\n workingDirectory: string,\n updates: Partial<WatcherStatus>\n): void {\n const current = readStatus(workingDirectory);\n\n if (current) {\n writeStatus(workingDirectory, { ...current, ...updates });\n } else if (updates.state && updates.projectSlug && updates.config) {\n // Create new status with required fields\n writeStatus(workingDirectory, {\n state: updates.state,\n projectSlug: updates.projectSlug,\n ticketsProcessed: updates.ticketsProcessed ?? 0,\n currentlyExecuting: updates.currentlyExecuting ?? [],\n config: updates.config,\n ...updates,\n });\n }\n}\n\n/**\n * Remove the status file\n *\n * @param workingDirectory - Project root directory\n */\nexport function removeStatus(workingDirectory: string): void {\n const statusFile = getStatusFile(workingDirectory);\n\n if (existsSync(statusFile)) {\n try {\n unlinkSync(statusFile);\n } catch {\n // Ignore errors during cleanup\n }\n }\n}\n\n// ============================================================================\n// Cleanup\n// ============================================================================\n\n/**\n * Clean up all watcher state files\n *\n * Used when stopping the watcher or cleaning up after errors.\n *\n * @param workingDirectory - Project root directory\n */\nexport function cleanupWatcherState(workingDirectory: string): void {\n removePid(workingDirectory);\n // Note: We keep status.json for debugging - it shows last known state\n // The status file's state field is set to 'stopped' instead\n}\n"],"mappings":";;;AAYA,SAAS,YAAY,WAAW,cAAc,eAAe,kBAAkB;AAC/E,SAAS,YAAY;AAcd,SAAS,cAAc,kBAAkC;AAC9D,QAAM,MAAM,KAAK,kBAAkB,QAAQ,MAAM;AAGjD,MAAI,CAAC,WAAW,GAAG,GAAG;AACpB,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACpC;AAEA,SAAO;AACT;AAKO,SAAS,WAAW,kBAAkC;AAC3D,SAAO,KAAK,cAAc,gBAAgB,GAAG,aAAa;AAC5D;AAKO,SAAS,cAAc,kBAAkC;AAC9D,SAAO,KAAK,cAAc,gBAAgB,GAAG,aAAa;AAC5D;AAmBO,SAAS,SAAS,kBAA0B,KAAmB;AACpE,QAAM,UAAU,WAAW,gBAAgB;AAC3C,gBAAc,SAAS,IAAI,SAAS,GAAG,OAAO;AAChD;AAQO,SAAS,QAAQ,kBAA8C;AACpE,QAAM,UAAU,WAAW,gBAAgB;AAE3C,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,aAAa,SAAS,OAAO,EAAE,KAAK;AACpD,UAAM,MAAM,SAAS,SAAS,EAAE;AAChC,WAAO,MAAM,GAAG,IAAI,SAAY;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,UAAU,kBAAgC;AACxD,QAAM,UAAU,WAAW,gBAAgB;AAE3C,MAAI,WAAW,OAAO,GAAG;AACvB,QAAI;AACF,iBAAW,OAAO;AAAA,IACpB,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAWO,SAAS,iBAAiB,KAAsB;AACrD,MAAI;AAEF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWO,SAAS,iBAAiB,kBAAmC;AAClE,QAAM,MAAM,QAAQ,gBAAgB;AAEpC,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,GAAG,GAAG;AACzB,WAAO;AAAA,EACT;AAIA,YAAU,gBAAgB;AAC1B,SAAO;AACT;AAYO,SAAS,YAAY,kBAA0B,QAA6B;AACjF,QAAM,aAAa,cAAc,gBAAgB;AACjD,gBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AACpE;AAQO,SAAS,WAAW,kBAAqD;AAC9E,QAAM,aAAa,cAAc,gBAAgB;AAEjD,MAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,aAAa,YAAY,OAAO;AAChD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWO,SAAS,aACd,kBACA,SACM;AACN,QAAM,UAAU,WAAW,gBAAgB;AAE3C,MAAI,SAAS;AACX,gBAAY,kBAAkB,EAAE,GAAG,SAAS,GAAG,QAAQ,CAAC;AAAA,EAC1D,WAAW,QAAQ,SAAS,QAAQ,eAAe,QAAQ,QAAQ;AAEjE,gBAAY,kBAAkB;AAAA,MAC5B,OAAO,QAAQ;AAAA,MACf,aAAa,QAAQ;AAAA,MACrB,kBAAkB,QAAQ,oBAAoB;AAAA,MAC9C,oBAAoB,QAAQ,sBAAsB,CAAC;AAAA,MACnD,QAAQ,QAAQ;AAAA,MAChB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;","names":[]}