pid1 0.0.0-dev.0 → 0.0.0-dev.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.
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as globalLogger } from "./config-BgRb4pSG.mjs";
3
- import { t as ProcessManager } from "./process-manager-gO56266Q.mjs";
3
+ import { t as ProcessManager } from "./process-manager-Ddk5dALx.mjs";
4
4
  import { createClient } from "./client.mjs";
5
5
  import Table from "cli-table3";
6
6
  import { Command } from "commander";
@@ -51,7 +51,6 @@ async function runInit(argv) {
51
51
  pm.serve();
52
52
  await pm.init();
53
53
  pm.startAll();
54
- await pm.wait();
55
54
  }
56
55
  function createRpcClient(argv) {
57
56
  return createClient({ url: `http://${argv.host ?? envHost ?? "127.0.0.1"}:${argv.port ?? defaultPort}/rpc` });
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport Table from \"cli-table3\";\nimport { Command } from \"commander\";\nimport { ProcessManager } from \"./process-manager.ts\";\nimport { createClient } from \"./api/client.ts\";\nimport { globalLogger } from \"./logger.ts\";\n\nconst logger = globalLogger.child(\"cli\");\nconst defaultPort = Number(process.env.PID1_PORT ?? process.env.PORT ?? 3000);\nconst envHost = process.env.PID1_HOST ?? process.env.HOST;\n\nfunction formatTable(rows: Array<Record<string, unknown>>): void {\n if (rows.length === 0) {\n console.log(\"No processes registered\");\n return;\n }\n\n const table = new Table({\n head: [\"ID\", \"NAME\", \"STATUS\", \"PID\", \"RESTARTS\", \"STARTED\"],\n style: { head: [], border: [] },\n });\n\n for (const row of rows) {\n table.push([\n String(row.id),\n String(row.name),\n String(row.status),\n row.pid ? String(row.pid) : \"-\",\n String(row.restarts),\n row.startedAt ? new Date(row.startedAt as string).toLocaleString() : \"-\",\n ]);\n }\n\n console.log(table.toString());\n}\n\ntype CommonArgs = {\n port?: number;\n host?: string;\n};\ntype InitArgs = CommonArgs & {\n cwd?: string;\n config?: string;\n};\n\nasync function runInit(argv: InitArgs) {\n const host = argv.host ?? envHost ?? \"0.0.0.0\";\n const pm = new ProcessManager({\n cwd: argv.cwd,\n configPath: argv.config,\n server: { port: argv.port ?? defaultPort, host },\n });\n pm.serve();\n await pm.init();\n pm.startAll();\n await pm.wait();\n}\n\nfunction createRpcClient(argv: CommonArgs) {\n const host = argv.host ?? envHost ?? \"127.0.0.1\";\n const port = argv.port ?? defaultPort;\n return createClient({ url: `http://${host}:${port}/rpc` });\n}\n\nasync function main() {\n const program = new Command();\n program\n .name(\"pid1\")\n .description(\"Process manager daemon and controller\")\n .option(\"--port <number>\", \"Port for the HTTP server\", (value) =>\n Number(value),\n )\n .option(\"--host <host>\", \"Host for the HTTP server\");\n\n const commonOptions = (): CommonArgs => {\n const opts = program.opts<CommonArgs>();\n return {\n port: opts.port,\n host: opts.host,\n };\n };\n\n program\n .command(\"init\")\n .description(\"Start the daemon, run tasks, and start all processes\")\n .option(\"--cwd <path>\", \"Working directory for config lookup\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (options: InitArgs) => {\n await runInit({ ...commonOptions(), ...options });\n });\n\n program\n .command(\"start [name]\")\n .description(\"Start all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.start({ name });\n console.log(result.message);\n });\n\n program\n .command(\"stop [name]\")\n .description(\"Stop all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.stop({ name });\n console.log(result.message);\n });\n\n program\n .command(\"restart [name]\")\n .description(\"Restart all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.restart({ name });\n console.log(result.message);\n });\n\n program\n .command(\"delete [name]\")\n .description(\"Delete all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.delete({ name });\n console.log(result.message);\n });\n\n program\n .command(\"list\")\n .description(\"List all managed processes\")\n .action(async () => {\n const client = createRpcClient(commonOptions());\n const processes = await client.process.list({});\n formatTable(processes);\n });\n\n program\n .command(\"get <name>\")\n .description(\"Get a process by name or id\")\n .action(async (name: string) => {\n const client = createRpcClient(commonOptions());\n const process = await client.process.get({ name });\n if (!process) {\n console.log(`Process not found: ${name}`);\n return;\n }\n formatTable([process]);\n });\n\n if (process.argv.length <= 2) {\n program.outputHelp();\n return;\n }\n\n await program.parseAsync(process.argv);\n}\n\nmain().catch((error) => {\n if (error.cause?.code === \"ECONNREFUSED\") {\n console.error(\n \"Error: Could not connect to pid1 daemon. Is it running? Start it with: pid1 init\",\n );\n process.exit(1);\n }\n logger.error(error instanceof Error ? error.stack ?? error.message : String(error));\n process.exit(1);\n});\n"],"mappings":";;;;;;;;AAOA,MAAM,SAAS,aAAa,MAAM,MAAM;AACxC,MAAM,cAAc,OAAO,QAAQ,IAAI,aAAa,QAAQ,IAAI,QAAQ,IAAK;AAC7E,MAAM,UAAU,QAAQ,IAAI,aAAa,QAAQ,IAAI;AAErD,SAAS,YAAY,MAA4C;AAC/D,KAAI,KAAK,WAAW,GAAG;AACrB,UAAQ,IAAI,0BAA0B;AACtC;;CAGF,MAAM,QAAQ,IAAI,MAAM;EACtB,MAAM;GAAC;GAAM;GAAQ;GAAU;GAAO;GAAY;GAAU;EAC5D,OAAO;GAAE,MAAM,EAAE;GAAE,QAAQ,EAAE;GAAE;EAChC,CAAC;AAEF,MAAK,MAAM,OAAO,KAChB,OAAM,KAAK;EACT,OAAO,IAAI,GAAG;EACd,OAAO,IAAI,KAAK;EAChB,OAAO,IAAI,OAAO;EAClB,IAAI,MAAM,OAAO,IAAI,IAAI,GAAG;EAC5B,OAAO,IAAI,SAAS;EACpB,IAAI,YAAY,IAAI,KAAK,IAAI,UAAoB,CAAC,gBAAgB,GAAG;EACtE,CAAC;AAGJ,SAAQ,IAAI,MAAM,UAAU,CAAC;;AAY/B,eAAe,QAAQ,MAAgB;CACrC,MAAM,OAAO,KAAK,QAAQ,WAAW;CACrC,MAAM,KAAK,IAAI,eAAe;EAC5B,KAAK,KAAK;EACV,YAAY,KAAK;EACjB,QAAQ;GAAE,MAAM,KAAK,QAAQ;GAAa;GAAM;EACjD,CAAC;AACF,IAAG,OAAO;AACV,OAAM,GAAG,MAAM;AACf,IAAG,UAAU;AACb,OAAM,GAAG,MAAM;;AAGjB,SAAS,gBAAgB,MAAkB;AAGzC,QAAO,aAAa,EAAE,KAAK,UAFd,KAAK,QAAQ,WAAW,YAEK,GAD7B,KAAK,QAAQ,YACwB,OAAO,CAAC;;AAG5D,eAAe,OAAO;CACpB,MAAM,UAAU,IAAI,SAAS;AAC7B,SACG,KAAK,OAAO,CACZ,YAAY,wCAAwC,CACpD,OAAO,mBAAmB,6BAA6B,UACtD,OAAO,MAAM,CACd,CACA,OAAO,iBAAiB,2BAA2B;CAEtD,MAAM,sBAAkC;EACtC,MAAM,OAAO,QAAQ,MAAkB;AACvC,SAAO;GACL,MAAM,KAAK;GACX,MAAM,KAAK;GACZ;;AAGH,SACG,QAAQ,OAAO,CACf,YAAY,uDAAuD,CACnE,OAAO,gBAAgB,sCAAsC,CAC7D,OAAO,mBAAmB,sBAAsB,CAChD,OAAO,OAAO,YAAsB;AACnC,QAAM,QAAQ;GAAE,GAAG,eAAe;GAAE,GAAG;GAAS,CAAC;GACjD;AAEJ,SACG,QAAQ,eAAe,CACvB,YAAY,2DAA2D,CACvE,OAAO,OAAO,SAAkB;EAE/B,MAAM,SAAS,MADA,gBAAgB,eAAe,CAAC,CACnB,QAAQ,MAAM,EAAE,MAAM,CAAC;AACnD,UAAQ,IAAI,OAAO,QAAQ;GAC3B;AAEJ,SACG,QAAQ,cAAc,CACtB,YAAY,0DAA0D,CACtE,OAAO,OAAO,SAAkB;EAE/B,MAAM,SAAS,MADA,gBAAgB,eAAe,CAAC,CACnB,QAAQ,KAAK,EAAE,MAAM,CAAC;AAClD,UAAQ,IAAI,OAAO,QAAQ;GAC3B;AAEJ,SACG,QAAQ,iBAAiB,CACzB,YAAY,6DAA6D,CACzE,OAAO,OAAO,SAAkB;EAE/B,MAAM,SAAS,MADA,gBAAgB,eAAe,CAAC,CACnB,QAAQ,QAAQ,EAAE,MAAM,CAAC;AACrD,UAAQ,IAAI,OAAO,QAAQ;GAC3B;AAEJ,SACG,QAAQ,gBAAgB,CACxB,YAAY,4DAA4D,CACxE,OAAO,OAAO,SAAkB;EAE/B,MAAM,SAAS,MADA,gBAAgB,eAAe,CAAC,CACnB,QAAQ,OAAO,EAAE,MAAM,CAAC;AACpD,UAAQ,IAAI,OAAO,QAAQ;GAC3B;AAEJ,SACG,QAAQ,OAAO,CACf,YAAY,6BAA6B,CACzC,OAAO,YAAY;AAGlB,cADkB,MADH,gBAAgB,eAAe,CAAC,CAChB,QAAQ,KAAK,EAAE,CAAC,CACzB;GACtB;AAEJ,SACG,QAAQ,aAAa,CACrB,YAAY,8BAA8B,CAC1C,OAAO,OAAO,SAAiB;EAE9B,MAAM,UAAU,MADD,gBAAgB,eAAe,CAAC,CAClB,QAAQ,IAAI,EAAE,MAAM,CAAC;AAClD,MAAI,CAAC,SAAS;AACZ,WAAQ,IAAI,sBAAsB,OAAO;AACzC;;AAEF,cAAY,CAAC,QAAQ,CAAC;GACtB;AAEJ,KAAI,QAAQ,KAAK,UAAU,GAAG;AAC5B,UAAQ,YAAY;AACpB;;AAGF,OAAM,QAAQ,WAAW,QAAQ,KAAK;;AAGxC,MAAM,CAAC,OAAO,UAAU;AACtB,KAAI,MAAM,OAAO,SAAS,gBAAgB;AACxC,UAAQ,MACN,mFACD;AACD,UAAQ,KAAK,EAAE;;AAEjB,QAAO,MAAM,iBAAiB,QAAQ,MAAM,SAAS,MAAM,UAAU,OAAO,MAAM,CAAC;AACnF,SAAQ,KAAK,EAAE;EACf"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport Table from \"cli-table3\";\nimport { Command } from \"commander\";\nimport { ProcessManager } from \"./process-manager.ts\";\nimport { createClient } from \"./api/client.ts\";\nimport { globalLogger } from \"./logger.ts\";\n\nconst logger = globalLogger.child(\"cli\");\nconst defaultPort = Number(process.env.PID1_PORT ?? process.env.PORT ?? 3000);\nconst envHost = process.env.PID1_HOST ?? process.env.HOST;\n\nfunction formatTable(rows: Array<Record<string, unknown>>): void {\n if (rows.length === 0) {\n console.log(\"No processes registered\");\n return;\n }\n\n const table = new Table({\n head: [\"ID\", \"NAME\", \"STATUS\", \"PID\", \"RESTARTS\", \"STARTED\"],\n style: { head: [], border: [] },\n });\n\n for (const row of rows) {\n table.push([\n String(row.id),\n String(row.name),\n String(row.status),\n row.pid ? String(row.pid) : \"-\",\n String(row.restarts),\n row.startedAt ? new Date(row.startedAt as string).toLocaleString() : \"-\",\n ]);\n }\n\n console.log(table.toString());\n}\n\ntype CommonArgs = {\n port?: number;\n host?: string;\n};\ntype InitArgs = CommonArgs & {\n cwd?: string;\n config?: string;\n};\n\nasync function runInit(argv: InitArgs) {\n const host = argv.host ?? envHost ?? \"0.0.0.0\";\n const pm = new ProcessManager({\n cwd: argv.cwd,\n configPath: argv.config,\n server: { port: argv.port ?? defaultPort, host },\n });\n pm.serve();\n await pm.init();\n pm.startAll();\n}\n\nfunction createRpcClient(argv: CommonArgs) {\n const host = argv.host ?? envHost ?? \"127.0.0.1\";\n const port = argv.port ?? defaultPort;\n return createClient({ url: `http://${host}:${port}/rpc` });\n}\n\nasync function main() {\n const program = new Command();\n program\n .name(\"pid1\")\n .description(\"Process manager daemon and controller\")\n .option(\"--port <number>\", \"Port for the HTTP server\", (value) => Number(value))\n .option(\"--host <host>\", \"Host for the HTTP server\");\n\n const commonOptions = (): CommonArgs => {\n const opts = program.opts<CommonArgs>();\n return {\n port: opts.port,\n host: opts.host,\n };\n };\n\n program\n .command(\"init\")\n .description(\"Start the daemon, run tasks, and start all processes\")\n .option(\"--cwd <path>\", \"Working directory for config lookup\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (options: InitArgs) => {\n await runInit({ ...commonOptions(), ...options });\n });\n\n program\n .command(\"start [name]\")\n .description(\"Start all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.start({ name });\n console.log(result.message);\n });\n\n program\n .command(\"stop [name]\")\n .description(\"Stop all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.stop({ name });\n console.log(result.message);\n });\n\n program\n .command(\"restart [name]\")\n .description(\"Restart all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.restart({ name });\n console.log(result.message);\n });\n\n program\n .command(\"delete [name]\")\n .description(\"Delete all processes, or a specific process by name or id\")\n .action(async (name?: string) => {\n const client = createRpcClient(commonOptions());\n const result = await client.process.delete({ name });\n console.log(result.message);\n });\n\n program\n .command(\"list\")\n .description(\"List all managed processes\")\n .action(async () => {\n const client = createRpcClient(commonOptions());\n const processes = await client.process.list({});\n formatTable(processes);\n });\n\n program\n .command(\"get <name>\")\n .description(\"Get a process by name or id\")\n .action(async (name: string) => {\n const client = createRpcClient(commonOptions());\n const process = await client.process.get({ name });\n if (!process) {\n console.log(`Process not found: ${name}`);\n return;\n }\n formatTable([process]);\n });\n\n if (process.argv.length <= 2) {\n program.outputHelp();\n return;\n }\n\n await program.parseAsync(process.argv);\n}\n\nmain().catch((error) => {\n if (error.cause?.code === \"ECONNREFUSED\") {\n console.error(\n \"Error: Could not connect to pid1 daemon. Is it running? Start it with: pid1 init\",\n );\n process.exit(1);\n }\n logger.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n process.exit(1);\n});\n"],"mappings":"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"}
@@ -130,7 +130,6 @@ declare class ProcessManager {
130
130
  delete(name: string): Promise<void>;
131
131
  deleteAll(): Promise<void>;
132
132
  get(name: string): ProcessInfo | undefined;
133
- wait(): Promise<void>;
134
133
  shutdown(): Promise<void>;
135
134
  private spawnProcess;
136
135
  private runTasks;
@@ -214,4 +213,4 @@ declare function createClient(options?: ClientOptions): RouterClient<Router>;
214
213
  type Client = RouterClient<Router>;
215
214
  //#endregion
216
215
  export { router as a, ProcessInfo as c, ProcessStatus as d, ServerOptions as f, spawnWithLogging as h, Router as i, ProcessManager as l, SpawnedProcess as m, ClientOptions as n, ManagedProcess as o, createServer as p, createClient as r, ProcessConfig as s, Client as t, ProcessManagerOptions as u };
217
- //# sourceMappingURL=client-Bdt88RU-.d.mts.map
216
+ //# sourceMappingURL=client-B02fC2Sv.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-Bdt88RU-.d.mts","names":[],"sources":["../src/exec.ts","../src/api/server.ts","../src/process-manager.ts","../src/api/router.ts","../src/api/client.ts"],"mappings":"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"}
1
+ {"version":3,"file":"client-B02fC2Sv.d.mts","names":[],"sources":["../src/exec.ts","../src/api/server.ts","../src/process-manager.ts","../src/api/router.ts","../src/api/client.ts"],"mappings":"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"}
package/dist/client.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as ClientOptions, r as createClient, t as Client } from "./client-Bdt88RU-.mjs";
1
+ import { n as ClientOptions, r as createClient, t as Client } from "./client-B02fC2Sv.mjs";
2
2
  export { Client, ClientOptions, createClient };
@@ -1 +1 @@
1
- {"version":3,"file":"client.mjs","names":[],"sources":["../src/api/client.ts"],"sourcesContent":["import type { RouterClient } from \"@orpc/server\";\nimport { createORPCClient } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport type { Router } from \"./router.ts\";\n\nexport type ClientOptions = {\n url?: string;\n};\n\nexport function createClient(\n options: ClientOptions = {},\n): RouterClient<Router> {\n const { url = \"http://127.0.0.1:3000/rpc\" } = options;\n\n const link = new RPCLink({ url });\n\n return createORPCClient(link);\n}\n\nexport type Client = RouterClient<Router>;\n"],"mappings":";;;;AASA,SAAgB,aACd,UAAyB,EAAE,EACL;CACtB,MAAM,EAAE,MAAM,gCAAgC;AAI9C,QAAO,iBAFM,IAAI,QAAQ,EAAE,KAAK,CAAC,CAEJ"}
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../src/api/client.ts"],"sourcesContent":["import type { RouterClient } from \"@orpc/server\";\nimport { createORPCClient } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport type { Router } from \"./router.ts\";\n\nexport type ClientOptions = {\n url?: string;\n};\n\nexport function createClient(options: ClientOptions = {}): RouterClient<Router> {\n const { url = \"http://127.0.0.1:3000/rpc\" } = options;\n\n const link = new RPCLink({ url });\n\n return createORPCClient(link);\n}\n\nexport type Client = RouterClient<Router>;\n"],"mappings":";;;;AASA,SAAgB,aAAa,UAAyB,EAAE,EAAwB;CAC9E,MAAM,EAAE,MAAM,gCAAgC;AAI9C,QAAO,iBAFM,IAAI,QAAQ,EAAE,KAAK,CAAC,CAEJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-BgRb4pSG.mjs","names":[],"sources":["../src/logger.ts","../src/config.ts"],"sourcesContent":["import { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nconst ANSI_COLORS = {\n GREEN: \"\\x1b[32m\",\n CYAN: \"\\x1b[36m\",\n YELLOW: \"\\x1b[33m\",\n RED: \"\\x1b[31m\",\n RESET: \"\\x1b[0m\",\n BOLD: \"\\x1b[1m\",\n GRAY: \"\\x1b[90m\",\n};\n\nconst COLORS = {\n debug: (text: string) => `${ANSI_COLORS.GREEN}${text}${ANSI_COLORS.RESET}`,\n info: (text: string) => `${ANSI_COLORS.CYAN}${text}${ANSI_COLORS.RESET}`,\n warn: (text: string) => `${ANSI_COLORS.YELLOW}${text}${ANSI_COLORS.RESET}`,\n error: (text: string) => `${ANSI_COLORS.RED}${text}${ANSI_COLORS.RESET}`,\n gray: (text: string) => `${ANSI_COLORS.GRAY}${text}${ANSI_COLORS.RESET}`,\n bold: (text: string) => `${ANSI_COLORS.BOLD}${text}${ANSI_COLORS.RESET}`,\n};\n\nconst LOG_LEVELS = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n} as const;\n\ntype LogLevel = keyof typeof LOG_LEVELS;\n\nfunction formatTime() {\n return Intl.DateTimeFormat(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n timeZone: \"UTC\",\n hourCycle: \"h23\",\n }).format(new Date());\n}\n\nfunction formatLevel(level: LogLevel, color: boolean): string {\n const upper = level.toUpperCase().padStart(5);\n return color ? `${COLORS[level](upper)}` : upper;\n}\n\nexport type LoggerOptions = {\n name: string;\n level?: LogLevel;\n prettyLogFile?: string | null;\n jsonLogFile?: string | null;\n stdout?: boolean;\n};\n\nexport class Logger {\n private name: string;\n private level: number;\n private prettyLogFile?: string | null;\n private jsonLogFile?: string | null;\n private stdout: boolean;\n\n constructor(options: LoggerOptions) {\n this.name = options.name;\n this.level = LOG_LEVELS[options.level ?? \"info\"];\n this.prettyLogFile = options.prettyLogFile;\n this.jsonLogFile = options.jsonLogFile;\n this.stdout = options.stdout ?? true;\n\n if (this.prettyLogFile) {\n mkdirSync(dirname(this.prettyLogFile), { recursive: true });\n }\n if (this.jsonLogFile) {\n mkdirSync(dirname(this.jsonLogFile), { recursive: true });\n }\n }\n\n private log(level: LogLevel, message: string): void {\n if (LOG_LEVELS[level] < this.level) return;\n\n const time = formatTime();\n\n if (this.stdout) {\n const colorLevel = formatLevel(level, true);\n console.log(\n `${COLORS.gray(`[${time}]`)} ${colorLevel} ${COLORS.bold(`(${this.name})`)} ${message}`,\n );\n }\n\n if (this.prettyLogFile) {\n const plainLevel = formatLevel(level, false);\n const line = `[${time}] ${plainLevel} (${this.name}) ${message}\\n`;\n appendFileSync(this.prettyLogFile, line);\n }\n\n if (this.jsonLogFile) {\n const logObj = {\n time: new Date().toISOString(),\n level,\n name: this.name,\n msg: message,\n };\n appendFileSync(this.jsonLogFile, JSON.stringify(logObj) + \"\\n\");\n }\n }\n\n debug(message: string): void {\n this.log(\"debug\", message);\n }\n\n info(message: string): void {\n this.log(\"info\", message);\n }\n\n warn(message: string): void {\n this.log(\"warn\", message);\n }\n\n error(message: string): void {\n this.log(\"error\", message);\n }\n\n child(name: string, options: Partial<LoggerOptions> = {}): Logger {\n const hasPrettyLogFile = \"prettyLogFile\" in options;\n const hasJsonLogFile = \"jsonLogFile\" in options;\n const hasStdout = \"stdout\" in options;\n\n return new Logger({\n name: `${this.name}:${name}`,\n level: options.level ?? (Object.keys(LOG_LEVELS)[this.level] as LogLevel),\n prettyLogFile: hasPrettyLogFile ? options.prettyLogFile : this.prettyLogFile,\n jsonLogFile: hasJsonLogFile ? options.jsonLogFile : this.jsonLogFile,\n stdout: hasStdout ? options.stdout : this.stdout,\n });\n }\n}\n\nmkdirSync(\"logs\", { recursive: true });\nexport const globalLogger = new Logger({\n name: \"pid1\",\n level: \"debug\",\n jsonLogFile: \"logs/pid1.log\",\n});\n\ntype ProcessLoggerParams = {\n name: string;\n logFile: string;\n};\n\nexport function processLogger({ name, logFile }: ProcessLoggerParams): Logger {\n mkdirSync(dirname(logFile), { recursive: true });\n return globalLogger.child(name, {\n prettyLogFile: logFile,\n jsonLogFile: null,\n });\n}\n","import { globSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tsImport } from \"tsx/esm/api\";\nimport * as v from \"valibot\";\nimport { globalLogger } from \"./logger\";\n\nconst logger = globalLogger.child(\"config\");\nconst EnvFileOption = v.optional(v.union([v.string(), v.literal(false)]));\nconst RestartPolicySchema = v.picklist([\"never\", \"always\", \"on-failure\"]);\n\nconst ProcessConfigSchema = v.object({\n name: v.string(),\n command: v.string(),\n args: v.optional(v.array(v.string()), []),\n env: v.optional(v.record(v.string(), v.string()), {}),\n cwd: v.optional(v.string()),\n envFile: EnvFileOption,\n restartOnEnvChange: v.optional(v.boolean(), true),\n restartPolicy: v.optional(RestartPolicySchema, \"on-failure\"),\n maxRestarts: v.optional(v.number(), 10),\n restartMinDelayMs: v.optional(v.number(), 5000),\n restartMaxDelayMs: v.optional(v.number(), 60000),\n restartResetSeconds: v.optional(v.number(), 300),\n});\n\nconst Config = v.object({\n envFile: EnvFileOption,\n restartOnEnvChange: v.optional(v.boolean(), true),\n restartMinDelayMs: v.optional(v.number(), 5000),\n restartMaxDelayMs: v.optional(v.number(), 60000),\n tasks: v.optional(v.array(ProcessConfigSchema), []),\n processes: v.optional(v.array(ProcessConfigSchema), []),\n});\n\ntype ConfigInput = v.InferInput<typeof Config>;\n\nexport type LoadedConfig = v.InferOutput<typeof Config> & {\n configPath: string;\n};\n\nexport async function loadConfigFile(\n path?: string,\n cwd?: string,\n): Promise<LoadedConfig> {\n const configFile = path ?? findConfigFile(cwd ?? process.cwd());\n if (!configFile) {\n logger.error(\n `Failed to find a config file in ${cwd ?? process.cwd()} or any of its parent directories`,\n );\n logger.error(\"Exiting...\");\n process.exit(1);\n }\n\n logger.info(`Trying to load config from ${configFile}`);\n const config = await tsImport(configFile, {\n parentURL: import.meta.url,\n })\n .then((m) =>\n \"default\" in m.default ? m.default.default : m.default,\n )\n .catch((error) => {\n logger.error(`Failed to load config from ${configFile}`);\n logger.error(error instanceof Error ? error.stack ?? error.message : String(error));\n logger.error(\"Exiting...\");\n process.exit(1);\n });\n\n const res = await v.safeParseAsync(Config, config);\n if (!res.success) {\n logger.error(`Config validation failed`);\n logger.error(v.summarize(res.issues));\n logger.error(\"Exiting...\");\n process.exit(1);\n }\n\n return { ...res.output, configPath: configFile };\n}\n\nexport function findConfigFile(cwd: string) {\n const files = globSync(\"pid1.config.{ts,js,mts,mjs}\", { cwd });\n if (files.length === 0 && join(cwd) !== \"/\") {\n return findConfigFile(join(cwd, \"..\"));\n }\n return files[0] ? join(cwd, files[0]) : null;\n}\n\nexport function defineConfig(config: ConfigInput) {\n return config;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-BgRb4pSG.mjs","names":[],"sources":["../src/logger.ts","../src/config.ts"],"sourcesContent":["import { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nconst ANSI_COLORS = {\n GREEN: \"\\x1b[32m\",\n CYAN: \"\\x1b[36m\",\n YELLOW: \"\\x1b[33m\",\n RED: \"\\x1b[31m\",\n RESET: \"\\x1b[0m\",\n BOLD: \"\\x1b[1m\",\n GRAY: \"\\x1b[90m\",\n};\n\nconst COLORS = {\n debug: (text: string) => `${ANSI_COLORS.GREEN}${text}${ANSI_COLORS.RESET}`,\n info: (text: string) => `${ANSI_COLORS.CYAN}${text}${ANSI_COLORS.RESET}`,\n warn: (text: string) => `${ANSI_COLORS.YELLOW}${text}${ANSI_COLORS.RESET}`,\n error: (text: string) => `${ANSI_COLORS.RED}${text}${ANSI_COLORS.RESET}`,\n gray: (text: string) => `${ANSI_COLORS.GRAY}${text}${ANSI_COLORS.RESET}`,\n bold: (text: string) => `${ANSI_COLORS.BOLD}${text}${ANSI_COLORS.RESET}`,\n};\n\nconst LOG_LEVELS = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n} as const;\n\ntype LogLevel = keyof typeof LOG_LEVELS;\n\nfunction formatTime() {\n return Intl.DateTimeFormat(\"en-US\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n timeZone: \"UTC\",\n hourCycle: \"h23\",\n }).format(new Date());\n}\n\nfunction formatLevel(level: LogLevel, color: boolean): string {\n const upper = level.toUpperCase().padStart(5);\n return color ? `${COLORS[level](upper)}` : upper;\n}\n\nexport type LoggerOptions = {\n name: string;\n level?: LogLevel;\n prettyLogFile?: string | null;\n jsonLogFile?: string | null;\n stdout?: boolean;\n};\n\nexport class Logger {\n private name: string;\n private level: number;\n private prettyLogFile?: string | null;\n private jsonLogFile?: string | null;\n private stdout: boolean;\n\n constructor(options: LoggerOptions) {\n this.name = options.name;\n this.level = LOG_LEVELS[options.level ?? \"info\"];\n this.prettyLogFile = options.prettyLogFile;\n this.jsonLogFile = options.jsonLogFile;\n this.stdout = options.stdout ?? true;\n\n if (this.prettyLogFile) {\n mkdirSync(dirname(this.prettyLogFile), { recursive: true });\n }\n if (this.jsonLogFile) {\n mkdirSync(dirname(this.jsonLogFile), { recursive: true });\n }\n }\n\n private log(level: LogLevel, message: string): void {\n if (LOG_LEVELS[level] < this.level) return;\n\n const time = formatTime();\n\n if (this.stdout) {\n const colorLevel = formatLevel(level, true);\n console.log(\n `${COLORS.gray(`[${time}]`)} ${colorLevel} ${COLORS.bold(`(${this.name})`)} ${message}`,\n );\n }\n\n if (this.prettyLogFile) {\n const plainLevel = formatLevel(level, false);\n const line = `[${time}] ${plainLevel} (${this.name}) ${message}\\n`;\n appendFileSync(this.prettyLogFile, line);\n }\n\n if (this.jsonLogFile) {\n const logObj = {\n time: new Date().toISOString(),\n level,\n name: this.name,\n msg: message,\n };\n appendFileSync(this.jsonLogFile, JSON.stringify(logObj) + \"\\n\");\n }\n }\n\n debug(message: string): void {\n this.log(\"debug\", message);\n }\n\n info(message: string): void {\n this.log(\"info\", message);\n }\n\n warn(message: string): void {\n this.log(\"warn\", message);\n }\n\n error(message: string): void {\n this.log(\"error\", message);\n }\n\n child(name: string, options: Partial<LoggerOptions> = {}): Logger {\n const hasPrettyLogFile = \"prettyLogFile\" in options;\n const hasJsonLogFile = \"jsonLogFile\" in options;\n const hasStdout = \"stdout\" in options;\n\n return new Logger({\n name: `${this.name}:${name}`,\n level: options.level ?? (Object.keys(LOG_LEVELS)[this.level] as LogLevel),\n prettyLogFile: hasPrettyLogFile ? options.prettyLogFile : this.prettyLogFile,\n jsonLogFile: hasJsonLogFile ? options.jsonLogFile : this.jsonLogFile,\n stdout: hasStdout ? options.stdout : this.stdout,\n });\n }\n}\n\nmkdirSync(\"logs\", { recursive: true });\nexport const globalLogger = new Logger({\n name: \"pid1\",\n level: \"debug\",\n jsonLogFile: \"logs/pid1.log\",\n});\n\ntype ProcessLoggerParams = {\n name: string;\n logFile: string;\n};\n\nexport function processLogger({ name, logFile }: ProcessLoggerParams): Logger {\n mkdirSync(dirname(logFile), { recursive: true });\n return globalLogger.child(name, {\n prettyLogFile: logFile,\n jsonLogFile: null,\n });\n}\n","import { globSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tsImport } from \"tsx/esm/api\";\nimport * as v from \"valibot\";\nimport { globalLogger } from \"./logger\";\n\nconst logger = globalLogger.child(\"config\");\nconst EnvFileOption = v.optional(v.union([v.string(), v.literal(false)]));\nconst RestartPolicySchema = v.picklist([\"never\", \"always\", \"on-failure\"]);\n\nconst ProcessConfigSchema = v.object({\n name: v.string(),\n command: v.string(),\n args: v.optional(v.array(v.string()), []),\n env: v.optional(v.record(v.string(), v.string()), {}),\n cwd: v.optional(v.string()),\n envFile: EnvFileOption,\n restartOnEnvChange: v.optional(v.boolean(), true),\n restartPolicy: v.optional(RestartPolicySchema, \"on-failure\"),\n maxRestarts: v.optional(v.number(), 10),\n restartMinDelayMs: v.optional(v.number(), 5000),\n restartMaxDelayMs: v.optional(v.number(), 60000),\n restartResetSeconds: v.optional(v.number(), 300),\n});\n\nconst Config = v.object({\n envFile: EnvFileOption,\n restartOnEnvChange: v.optional(v.boolean(), true),\n restartMinDelayMs: v.optional(v.number(), 5000),\n restartMaxDelayMs: v.optional(v.number(), 60000),\n tasks: v.optional(v.array(ProcessConfigSchema), []),\n processes: v.optional(v.array(ProcessConfigSchema), []),\n});\n\ntype ConfigInput = v.InferInput<typeof Config>;\n\nexport type LoadedConfig = v.InferOutput<typeof Config> & {\n configPath: string;\n};\n\nexport async function loadConfigFile(path?: string, cwd?: string): Promise<LoadedConfig> {\n const configFile = path ?? findConfigFile(cwd ?? process.cwd());\n if (!configFile) {\n logger.error(\n `Failed to find a config file in ${cwd ?? process.cwd()} or any of its parent directories`,\n );\n logger.error(\"Exiting...\");\n process.exit(1);\n }\n\n logger.info(`Trying to load config from ${configFile}`);\n const config = await tsImport(configFile, {\n parentURL: import.meta.url,\n })\n .then((m) => (\"default\" in m.default ? m.default.default : m.default))\n .catch((error) => {\n logger.error(`Failed to load config from ${configFile}`);\n logger.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n logger.error(\"Exiting...\");\n process.exit(1);\n });\n\n const res = await v.safeParseAsync(Config, config);\n if (!res.success) {\n logger.error(`Config validation failed`);\n logger.error(v.summarize(res.issues));\n logger.error(\"Exiting...\");\n process.exit(1);\n }\n\n return { ...res.output, configPath: configFile };\n}\n\nexport function findConfigFile(cwd: string) {\n const files = globSync(\"pid1.config.{ts,js,mts,mjs}\", { cwd });\n if (files.length === 0 && join(cwd) !== \"/\") {\n return findConfigFile(join(cwd, \"..\"));\n }\n return files[0] ? join(cwd, files[0]) : null;\n}\n\nexport function defineConfig(config: ConfigInput) {\n return config;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;cAyBM,MAAA,EAAM,CAAA,CAAA,YAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KASP,WAAA,GAAc,CAAA,CAAE,UAAA,QAAkB,MAAA;AAAA,KAE3B,YAAA,GAAe,CAAA,CAAE,WAAA,QAAmB,MAAA;EAC9C,UAAA;AAAA;AAAA,iBAGoB,cAAA,CACpB,IAAA,WACA,GAAA,YACC,OAAA,CAAQ,YAAA;AAAA,iBAmCK,cAAA,CAAe,GAAA;AAAA,iBAQf,YAAA,CAAa,MAAA,EAAQ,WAAA"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;cAyBM,MAAA,EAAM,CAAA,CAAA,YAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KASP,WAAA,GAAc,CAAA,CAAE,UAAA,QAAkB,MAAA;AAAA,KAE3B,YAAA,GAAe,CAAA,CAAE,WAAA,QAAmB,MAAA;EAC9C,UAAA;AAAA;AAAA,iBAGoB,cAAA,CAAe,IAAA,WAAe,GAAA,YAAe,OAAA,CAAQ,YAAA;AAAA,iBAiC3D,cAAA,CAAe,GAAA;AAAA,iBAQf,YAAA,CAAa,MAAA,EAAQ,WAAA"}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as router, c as ProcessInfo, d as ProcessStatus, f as ServerOptions, h as spawnWithLogging, i as Router, l as ProcessManager, m as SpawnedProcess, n as ClientOptions, o as ManagedProcess, p as createServer, r as createClient, s as ProcessConfig, t as Client, u as ProcessManagerOptions } from "./client-Bdt88RU-.mjs";
1
+ import { a as router, c as ProcessInfo, d as ProcessStatus, f as ServerOptions, h as spawnWithLogging, i as Router, l as ProcessManager, m as SpawnedProcess, n as ClientOptions, o as ManagedProcess, p as createServer, r as createClient, s as ProcessConfig, t as Client, u as ProcessManagerOptions } from "./client-B02fC2Sv.mjs";
2
2
  import { defineConfig, loadConfigFile } from "./config.mjs";
3
3
 
4
4
  //#region src/logger.d.ts
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { i as globalLogger, r as loadConfigFile, t as defineConfig } from "./config-BgRb4pSG.mjs";
2
- import { i as spawnWithLogging, n as createServer, r as router, t as ProcessManager } from "./process-manager-gO56266Q.mjs";
2
+ import { i as spawnWithLogging, n as createServer, r as router, t as ProcessManager } from "./process-manager-Ddk5dALx.mjs";
3
3
  import { createClient } from "./client.mjs";
4
4
 
5
5
  export { ProcessManager, createClient, createServer, defineConfig, globalLogger, loadConfigFile, router, spawnWithLogging };
@@ -236,7 +236,6 @@ function createServer(pm, options = {}) {
236
236
  hostname: host
237
237
  });
238
238
  logger$2.info(`HTTP server listening on http://${host}:${port}`);
239
- logger$2.info(`RPC endpoint: http://${host}:${port}/rpc`);
240
239
  return server;
241
240
  }
242
241
  };
@@ -413,11 +412,6 @@ var ProcessManager = class {
413
412
  args: resolved.managed.config.args
414
413
  };
415
414
  }
416
- async wait() {
417
- const donePromises = [...this.processes.values()].filter((m) => m.spawned).map((m) => m.spawned.done);
418
- await Promise.allSettled(donePromises);
419
- this.logger.info("All processes exited");
420
- }
421
415
  async shutdown() {
422
416
  await this.stopActiveTask();
423
417
  await this.stopAll();
@@ -640,4 +634,4 @@ var ProcessManager = class {
640
634
 
641
635
  //#endregion
642
636
  export { spawnWithLogging as i, createServer as n, router as r, ProcessManager as t };
643
- //# sourceMappingURL=process-manager-gO56266Q.mjs.map
637
+ //# sourceMappingURL=process-manager-Ddk5dALx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-manager-Ddk5dALx.mjs","names":["logger","logger","honoLogger"],"sources":["../src/env.ts","../src/exec.ts","../src/api/router.ts","../src/api/server.ts","../src/process-manager.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { parse } from \"dotenv\";\nimport { globalLogger } from \"./logger\";\n\nexport type EnvFileConfig = {\n envFile?: string | false;\n};\n\nconst logger = globalLogger.child(\"env\");\n\nfunction loadEnvFile(path: string): Record<string, string> {\n if (!existsSync(path)) {\n return {};\n }\n\n try {\n const content = readFileSync(path, \"utf-8\");\n const parsed = parse(content);\n logger.debug(`Loaded env file: ${path}`);\n return parsed;\n } catch (error) {\n logger.warn(`Failed to parse env file ${path}: ${error}`);\n return {};\n }\n}\n\nexport type LoadEnvOptions = {\n configDir: string;\n processName: string;\n globalEnvFile?: string | false;\n processEnvFile?: string | false;\n configEnv?: Record<string, string>;\n};\n\nexport function loadEnvForProcess(options: LoadEnvOptions): Record<string, string> {\n const { configDir, processName, globalEnvFile, processEnvFile, configEnv = {} } = options;\n\n const baseEnv = Object.fromEntries(\n Object.entries(process.env).filter(([, value]) => value !== undefined),\n ) as Record<string, string>;\n\n let globalEnv: Record<string, string> = {};\n if (globalEnvFile !== false) {\n const globalPath = globalEnvFile ?? join(configDir, \".env\");\n globalEnv = loadEnvFile(globalPath);\n }\n\n let processEnv: Record<string, string> = {};\n if (processEnvFile !== false) {\n const processPath = processEnvFile ?? join(configDir, `.env.${processName}`);\n processEnv = loadEnvFile(processPath);\n }\n\n return {\n ...baseEnv,\n ...globalEnv,\n ...configEnv,\n ...processEnv,\n };\n}\n\nexport function getConfigDir(configPath: string): string {\n return dirname(configPath);\n}\n","import { processLogger } from \"./logger\";\nimport { x } from \"tinyexec\";\n\ntype ExecType = \"task\" | \"process\";\n\ntype ExecWithLoggingParams = {\n name: string;\n command: string;\n args: string[];\n env: Record<string, string>;\n cwd: string;\n logFile: string;\n abortSignal?: AbortSignal;\n type: ExecType;\n};\n\ntype TinyExecProcess = ReturnType<typeof x>;\n\nexport type SpawnedProcess = {\n proc: TinyExecProcess;\n done: Promise<number | null>;\n kill: (signal?: NodeJS.Signals) => boolean;\n};\n\nexport function spawnWithLogging({\n name,\n command,\n args,\n env,\n cwd,\n logFile,\n abortSignal,\n type,\n}: ExecWithLoggingParams): SpawnedProcess {\n const proc = x(command, args, {\n nodeOptions: { cwd, env },\n signal: abortSignal,\n throwOnError: true,\n });\n\n const kill = (signal: NodeJS.Signals = \"SIGTERM\"): boolean => {\n if (proc.pid) {\n try {\n process.kill(proc.pid, signal);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n };\n\n const done = (async () => {\n const logger = processLogger({ name: `${type}:${name}`, logFile });\n\n logger.info(`Starting: command=${command}, args=[${args.join(\", \")}], cwd=${cwd}`);\n\n for await (const line of proc) {\n logger.info(line);\n }\n\n await proc;\n\n const exitCode = proc.exitCode;\n\n if (proc.aborted || proc.killed || exitCode === null || exitCode === undefined) {\n logger.info(`${name} was terminated`);\n } else if (exitCode === 0) {\n logger.info(`${name} completed successfully`);\n } else {\n logger.info(`${name} exited with code ${exitCode}`);\n }\n\n return proc.exitCode ?? null;\n })();\n\n return { proc, done, kill };\n}\n","import { os, ORPCError } from \"@orpc/server\";\nimport * as v from \"valibot\";\nimport type { ProcessManager, ProcessInfo } from \"../process-manager.ts\";\n\nconst ProcessInfoSchema = v.object({\n id: v.number(),\n name: v.string(),\n status: v.picklist([\"stopped\", \"running\", \"errored\"]),\n pid: v.optional(v.number()),\n exitCode: v.nullable(v.number()),\n restarts: v.number(),\n startedAt: v.nullable(v.date()),\n command: v.string(),\n args: v.array(v.string()),\n});\n\nconst ProcessNameSchema = v.object({\n name: v.string(),\n});\n\ntype RouterContext = {\n pm: ProcessManager;\n};\n\nconst base = os.$context<RouterContext>();\n\nexport const list = base.output(v.array(ProcessInfoSchema)).handler(async ({ context }) => {\n return context.pm.list();\n});\n\nexport const get = base\n .input(ProcessNameSchema)\n .output(v.nullable(ProcessInfoSchema))\n .handler(async ({ input, context }) => {\n return context.pm.get(input.name) ?? null;\n });\n\nexport const start = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n context.pm.start(input.name);\n return { success: true, message: `Started process: ${input.name}` };\n } else {\n context.pm.startAll();\n return { success: true, message: \"Started all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to start\",\n });\n }\n });\n\nexport const stop = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n await context.pm.stop(input.name);\n return { success: true, message: `Stopped process: ${input.name}` };\n } else {\n await context.pm.stopAll();\n return { success: true, message: \"Stopped all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to stop\",\n });\n }\n });\n\nexport const restart = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n await context.pm.restart(input.name);\n return { success: true, message: `Restarted process: ${input.name}` };\n } else {\n await context.pm.restartAll();\n return { success: true, message: \"Restarted all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to restart\",\n });\n }\n });\n\nexport const deleteProcess = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n await context.pm.delete(input.name);\n return { success: true, message: `Deleted process: ${input.name}` };\n } else {\n await context.pm.deleteAll();\n return { success: true, message: \"Deleted all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to delete\",\n });\n }\n });\n\nexport const health = os.output(v.object({ status: v.literal(\"ok\") })).handler(async () => {\n return { status: \"ok\" as const };\n});\n\nexport const router = {\n health,\n process: {\n list,\n get,\n start,\n stop,\n restart,\n delete: deleteProcess,\n },\n};\n\nexport type Router = typeof router;\n","import { Hono } from \"hono\";\nimport { serve } from \"@hono/node-server\";\nimport { RPCHandler } from \"@orpc/server/fetch\";\nimport { onError } from \"@orpc/server\";\nimport { router } from \"./router.ts\";\nimport type { ProcessManager } from \"../process-manager.ts\";\nimport { globalLogger } from \"../logger.ts\";\nimport { logger as honoLogger } from \"hono/logger\";\n\nexport type ServerOptions = {\n port?: number;\n host?: string;\n};\n\nexport function createServer(pm: ProcessManager, options: ServerOptions = {}) {\n const { port = 3000, host = \"127.0.0.1\" } = options;\n const logger = globalLogger.child(\"server\");\n\n const app = new Hono();\n\n const handler = new RPCHandler(router, {\n interceptors: [\n onError((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`RPC Error: ${message}`);\n }),\n ],\n });\n\n app.use(honoLogger((msg, ...args) => logger.debug(`${msg} ${args.join(\" \")}`)));\n\n app.get(\"/health\", (c) => c.json({ status: \"ok\" }));\n\n app.use(\"/rpc/*\", async (c, next) => {\n const { matched, response } = await handler.handle(c.req.raw, {\n prefix: \"/rpc\",\n context: { pm },\n });\n\n if (matched) {\n return c.newResponse(response.body, response);\n }\n\n await next();\n });\n\n app.notFound((c) => c.json({ error: \"Not found\" }, 404));\n\n return {\n app,\n start: () => {\n const server = serve({\n fetch: app.fetch,\n port,\n hostname: host,\n });\n\n logger.info(`HTTP server listening on http://${host}:${port}`);\n return server;\n },\n };\n}\n\nexport type { Router } from \"./router.ts\";\n","import { dirname, join } from \"node:path\";\nimport { watch, type FSWatcher } from \"node:fs\";\nimport { loadConfigFile } from \"./config.ts\";\nimport { loadEnvForProcess } from \"./env.ts\";\nimport { spawnWithLogging, type SpawnedProcess } from \"./exec.ts\";\nimport { globalLogger } from \"./logger.ts\";\nimport { createServer, type ServerOptions } from \"./api/server.ts\";\n\nexport type ProcessManagerOptions = {\n cwd?: string;\n configPath?: string;\n server?: ServerOptions & { enabled?: boolean };\n};\n\nexport type ProcessStatus = \"stopped\" | \"running\" | \"errored\";\nexport type RestartPolicy = \"never\" | \"always\" | \"on-failure\";\n\nexport type ProcessConfig = {\n name: string;\n command: string;\n args: string[];\n env: Record<string, string>;\n cwd?: string;\n envFile?: string | false;\n restartOnEnvChange?: boolean;\n restartPolicy?: RestartPolicy;\n maxRestarts?: number;\n restartMinDelayMs?: number;\n restartMaxDelayMs?: number;\n restartResetSeconds?: number;\n};\n\nexport type ManagedProcess = {\n id: number;\n config: ProcessConfig;\n status: ProcessStatus;\n spawned: SpawnedProcess | null;\n exitCode: number | null;\n restarts: number;\n restartAttempts: number;\n restartTimer: NodeJS.Timeout | null;\n stopRequested: boolean;\n startedAt: Date | null;\n};\n\nconst DEFAULT_STOP_TIMEOUT_MS = 10000;\nconst DEFAULT_RESTART_RESET_SECONDS = 300;\nconst DEFAULT_RESTART_MAX = 10;\nconst DEFAULT_RESTART_MIN_DELAY_MS = 5000;\nconst DEFAULT_RESTART_MAX_DELAY_MS = 60000;\n\nexport type ProcessInfo = {\n id: number;\n name: string;\n status: ProcessStatus;\n pid: number | undefined;\n exitCode: number | null;\n restarts: number;\n startedAt: Date | null;\n command: string;\n args: string[];\n};\n\nexport class ProcessManager {\n private logger = globalLogger.child(\"pm\");\n private cwd: string;\n private configPath?: string;\n private configDir?: string;\n private globalEnvFile?: string | false;\n private processes: Map<string, ManagedProcess>;\n private processIds: Map<number, string>;\n private nextProcessId = 0;\n private signalHandlersSetup = false;\n private serverOptions?: ServerOptions & { enabled?: boolean };\n private httpServer?: ReturnType<ReturnType<typeof createServer>[\"start\"]>;\n private envWatcher: FSWatcher | null = null;\n private envChangeTimers = new Map<string, NodeJS.Timeout>();\n private envRestartTimers = new Map<string, NodeJS.Timeout>();\n private restartOnEnvChangeGlobal = true;\n private restartMinDelayMsGlobal = DEFAULT_RESTART_MIN_DELAY_MS;\n private restartMaxDelayMsGlobal = DEFAULT_RESTART_MAX_DELAY_MS;\n private currentTask: SpawnedProcess | null = null;\n private currentTaskName: string | null = null;\n private taskAbortController: AbortController | null = null;\n\n constructor(options: ProcessManagerOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n this.configPath = options.configPath;\n this.processes = new Map();\n this.processIds = new Map();\n this.serverOptions = options.server;\n }\n\n async init(): Promise<void> {\n const config = await loadConfigFile(this.configPath, this.cwd);\n\n this.configDir = dirname(config.configPath);\n this.globalEnvFile = config.envFile;\n this.restartOnEnvChangeGlobal = config.restartOnEnvChange ?? true;\n this.restartMinDelayMsGlobal = config.restartMinDelayMs ?? DEFAULT_RESTART_MIN_DELAY_MS;\n this.restartMaxDelayMsGlobal = config.restartMaxDelayMs ?? DEFAULT_RESTART_MAX_DELAY_MS;\n\n this.logger.info(\n `Executing ${config.tasks.length} tasks and registering ${config.processes.length} processes`,\n );\n\n this.setupSignalHandlers();\n this.setupEnvWatchers();\n await this.runTasks(config.tasks);\n\n for (const p of config.processes) {\n this.register(p);\n }\n }\n\n register(config: ProcessConfig): void {\n if (this.processes.has(config.name)) {\n throw new Error(`Process ${config.name} already registered`);\n }\n\n const id = this.nextProcessId++;\n const managed: ManagedProcess = {\n id,\n config,\n status: \"stopped\",\n spawned: null,\n exitCode: null,\n restarts: 0,\n restartAttempts: 0,\n restartTimer: null,\n stopRequested: false,\n startedAt: null,\n };\n\n this.processes.set(config.name, managed);\n this.processIds.set(id, config.name);\n this.logger.info(`Registered process: ${config.name} (id: ${id})`);\n }\n\n list(): ProcessInfo[] {\n return [...this.processes.values()].map((m) => ({\n id: m.id,\n name: m.config.name,\n status: m.status,\n pid: m.spawned?.proc.pid,\n exitCode: m.exitCode,\n restarts: m.restarts,\n startedAt: m.startedAt,\n command: m.config.command,\n args: m.config.args,\n }));\n }\n\n start(name: string): void {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n if (managed.status === \"running\") {\n this.logger.warn(`Process ${resolvedName} is already running`);\n return;\n }\n\n this.spawnProcess(managed);\n }\n\n startAll(): void {\n this.setupSignalHandlers();\n\n for (const [_, managed] of this.processes) {\n if (managed.status !== \"running\") {\n this.spawnProcess(managed);\n }\n }\n }\n\n serve(options?: ServerOptions & { enabled?: boolean }): void {\n const serverOpts = { ...this.serverOptions, ...options };\n if (serverOpts.enabled === false) return;\n const { enabled: _enabled, ...serverOptions } = serverOpts;\n const server = createServer(this, serverOptions);\n this.httpServer = server.start();\n }\n\n async stop(name: string, timeoutMs = DEFAULT_STOP_TIMEOUT_MS): Promise<void> {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n managed.stopRequested = true;\n this.clearRestartTimer(managed);\n\n if (managed.status !== \"running\" || !managed.spawned) {\n this.logger.warn(`Process ${resolvedName} is not running`);\n return;\n }\n\n const { spawned } = managed;\n\n this.logger.info(`Stopping process: ${resolvedName} (SIGTERM)`);\n spawned.kill(\"SIGTERM\");\n\n const exitedGracefully = await Promise.race([\n spawned.done.then(() => true).catch(() => true),\n new Promise<false>((resolve) => setTimeout(() => resolve(false), timeoutMs)),\n ]);\n\n if (!exitedGracefully && managed.status === \"running\") {\n this.logger.warn(`Process ${resolvedName} did not stop gracefully, sending SIGKILL`);\n spawned.kill(\"SIGKILL\");\n await spawned.done.catch(() => {});\n }\n }\n\n async stopAll(): Promise<void> {\n this.logger.info(\"Stopping all processes...\");\n\n for (const managed of this.processes.values()) {\n managed.stopRequested = true;\n this.clearRestartTimer(managed);\n }\n\n const stopPromises = [...this.processes.entries()]\n .filter(([, m]) => m.status === \"running\")\n .map(([name]) => this.stop(name));\n\n await Promise.allSettled(stopPromises);\n }\n\n async restart(name: string): Promise<void> {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n this.logger.info(`Restarting process: ${resolvedName}`);\n\n if (managed.status === \"running\") {\n await this.stop(resolvedName);\n }\n\n managed.restarts++;\n this.spawnProcess(managed);\n }\n\n async restartAll(): Promise<void> {\n this.logger.info(\"Restarting all processes...\");\n\n for (const [name] of this.processes) {\n await this.restart(name);\n }\n }\n\n async delete(name: string): Promise<void> {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n managed.stopRequested = true;\n this.clearRestartTimer(managed);\n\n if (managed.status === \"running\") {\n await this.stop(resolvedName);\n }\n\n this.processes.delete(resolvedName);\n this.processIds.delete(managed.id);\n this.logger.info(`Deleted process: ${resolvedName}`);\n }\n\n async deleteAll(): Promise<void> {\n await this.stopAll();\n this.processes.clear();\n this.logger.info(\"Deleted all processes\");\n }\n\n get(name: string): ProcessInfo | undefined {\n let resolved: { name: string; managed: ManagedProcess };\n try {\n resolved = this.resolveProcessIdentifier(name);\n } catch {\n return undefined;\n }\n\n return {\n id: resolved.managed.id,\n name: resolved.managed.config.name,\n status: resolved.managed.status,\n pid: resolved.managed.spawned?.proc.pid,\n exitCode: resolved.managed.exitCode,\n restarts: resolved.managed.restarts,\n startedAt: resolved.managed.startedAt,\n command: resolved.managed.config.command,\n args: resolved.managed.config.args,\n };\n }\n\n async shutdown(): Promise<void> {\n await this.stopActiveTask();\n await this.stopAll();\n this.closeEnvWatcher();\n if (this.httpServer) {\n this.httpServer.close();\n this.logger.info(\"HTTP server closed\");\n }\n }\n\n private spawnProcess(managed: ManagedProcess): void {\n const { config } = managed;\n\n managed.stopRequested = false;\n this.clearRestartTimer(managed);\n\n const env = loadEnvForProcess({\n configDir: this.configDir ?? this.cwd,\n processName: config.name,\n globalEnvFile: this.globalEnvFile,\n processEnvFile: config.envFile,\n configEnv: config.env,\n });\n\n const spawned = spawnWithLogging({\n cwd: config.cwd ?? this.cwd,\n logFile: join(this.cwd, \"logs\", \"processes\", `${config.name}.log`),\n type: \"process\",\n name: config.name,\n command: config.command,\n args: config.args,\n env,\n });\n\n managed.spawned = spawned;\n managed.status = \"running\";\n managed.startedAt = new Date();\n managed.exitCode = null;\n\n this.logger.info(`Started process: ${config.name} (pid: ${spawned.proc.pid})`);\n\n const handleExit = (exitCode: number | null, error?: unknown) => {\n managed.exitCode = exitCode;\n managed.status =\n exitCode === null || exitCode === undefined || exitCode === 0 ? \"stopped\" : \"errored\";\n const now = Date.now();\n const startedAt = managed.startedAt?.getTime() ?? now;\n const uptimeMs = Math.max(0, now - startedAt);\n const resetMs = (config.restartResetSeconds ?? DEFAULT_RESTART_RESET_SECONDS) * 1000;\n\n if (uptimeMs >= resetMs) {\n managed.restartAttempts = 0;\n }\n\n if (exitCode === null || exitCode === undefined) {\n this.logger.info(`Process ${config.name} stopped`);\n } else if (exitCode !== 0) {\n this.logger.info(`Process ${config.name} exited with code ${exitCode}`);\n } else {\n this.logger.info(`Process ${config.name} exited successfully`);\n }\n\n if (error) {\n this.logger.error(`Process ${config.name} failed with error: ${error}`);\n }\n\n const policy = config.restartPolicy ?? \"on-failure\";\n const isFailure = exitCode === null || exitCode === undefined || exitCode !== 0;\n const shouldRestart =\n !managed.stopRequested && (policy === \"always\" || (policy === \"on-failure\" && isFailure));\n\n if (!shouldRestart) {\n return;\n }\n\n const maxRestarts = config.maxRestarts ?? DEFAULT_RESTART_MAX;\n if (managed.restartAttempts >= maxRestarts) {\n managed.status = \"errored\";\n this.logger.warn(\n `Process ${config.name} reached restart limit (${maxRestarts}), not restarting`,\n );\n return;\n }\n\n managed.restartAttempts += 1;\n managed.restarts += 1;\n const minDelay = config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;\n const maxDelay = config.restartMaxDelayMs ?? this.restartMaxDelayMsGlobal;\n const delay = Math.min(maxDelay, minDelay * Math.pow(2, managed.restartAttempts - 1));\n\n this.logger.warn(\n `Restarting process ${config.name} in ${delay}ms (attempt ${managed.restartAttempts}/${maxRestarts})`,\n );\n\n managed.restartTimer = setTimeout(() => {\n managed.restartTimer = null;\n if (!managed.stopRequested) {\n this.spawnProcess(managed);\n }\n }, delay);\n };\n\n spawned.done\n .then((exitCode) => handleExit(exitCode))\n .catch((error) => {\n const exitCode = spawned.proc.exitCode ?? 1;\n handleExit(exitCode, error);\n });\n }\n\n private async runTasks(tasks: Array<ProcessConfig>): Promise<void> {\n for (const task of tasks) {\n const env = loadEnvForProcess({\n configDir: this.configDir ?? this.cwd,\n processName: task.name,\n globalEnvFile: this.globalEnvFile,\n processEnvFile: task.envFile,\n configEnv: task.env,\n });\n\n const taskAbortController = new AbortController();\n this.taskAbortController = taskAbortController;\n\n const spawned = spawnWithLogging({\n cwd: task.cwd ?? this.cwd,\n logFile: join(this.cwd, \"logs\", \"tasks\", `${task.name}.log`),\n type: \"task\",\n name: task.name,\n command: task.command,\n args: task.args,\n env,\n abortSignal: taskAbortController.signal,\n });\n\n this.currentTask = spawned;\n this.currentTaskName = task.name;\n\n let exitCode: number | null;\n try {\n exitCode = await spawned.done;\n } finally {\n this.currentTask = null;\n this.currentTaskName = null;\n this.taskAbortController = null;\n }\n\n if (exitCode !== 0) {\n this.logger.error(`Task ${task.name} failed with exit code ${exitCode}`);\n throw new Error(`Task ${task.name} failed`);\n }\n }\n\n if (tasks.length > 0) {\n this.logger.info(\"All tasks completed\");\n }\n }\n\n private clearRestartTimer(managed: ManagedProcess): void {\n if (managed.restartTimer) {\n clearTimeout(managed.restartTimer);\n managed.restartTimer = null;\n }\n }\n\n private async stopActiveTask(timeoutMs = DEFAULT_STOP_TIMEOUT_MS): Promise<void> {\n if (!this.currentTask) return;\n\n const taskName = this.currentTaskName ?? \"unknown\";\n this.logger.info(`Stopping task: ${taskName} (SIGTERM)`);\n this.currentTask.kill(\"SIGTERM\");\n\n const exitedGracefully = await Promise.race([\n this.currentTask.done.then(() => true).catch(() => true),\n new Promise<false>((resolve) => setTimeout(() => resolve(false), timeoutMs)),\n ]);\n\n if (!exitedGracefully) {\n this.logger.warn(`Task ${taskName} did not stop gracefully, sending SIGKILL`);\n this.currentTask.kill(\"SIGKILL\");\n await this.currentTask.done.catch(() => {});\n }\n }\n\n private abortActiveTask(signal: NodeJS.Signals): void {\n if (this.taskAbortController && !this.taskAbortController.signal.aborted) {\n this.taskAbortController.abort();\n }\n if (this.currentTask) {\n this.currentTask.kill(signal);\n }\n }\n\n private setupSignalHandlers(): void {\n if (this.signalHandlersSetup) return;\n this.signalHandlersSetup = true;\n\n const signals = [\"SIGINT\", \"SIGTERM\"] as const;\n for (const signal of signals) {\n process.on(signal, () => {\n process.stdout.write(\"\\r\\x1b[K\");\n this.logger.info(`Received ${signal}, shutting down...`);\n this.abortActiveTask(signal);\n this.shutdown().then(() => process.exit(0));\n });\n }\n }\n\n private setupEnvWatchers(): void {\n if (this.envWatcher) return;\n if (!this.restartOnEnvChangeGlobal) return;\n\n const watchDir = this.configDir ?? this.cwd;\n this.envWatcher = watch(watchDir, (event, filename) => {\n if (!filename) return;\n const envFile = filename.toString();\n if (!envFile.startsWith(\".env\")) return;\n if (event !== \"change\" && event !== \"rename\") return;\n\n if (envFile === \".env\") {\n this.scheduleEnvRestart(\"global\", () => {\n this.logger.info(\"Detected .env change, scheduling restarts\");\n for (const managed of this.processes.values()) {\n this.scheduleEnvRestartForProcess(managed);\n }\n });\n return;\n }\n\n if (!envFile.startsWith(\".env.\")) return;\n const processName = envFile.slice(\".env.\".length);\n if (!processName) return;\n\n this.scheduleEnvRestart(processName, () => {\n const managed = this.processes.get(processName);\n if (!managed) return;\n this.logger.info(`Detected ${envFile} change, scheduling restart for ${processName}`);\n this.scheduleEnvRestartForProcess(managed);\n });\n });\n }\n\n private closeEnvWatcher(): void {\n if (this.envWatcher) {\n this.envWatcher.close();\n this.envWatcher = null;\n }\n for (const timer of this.envChangeTimers.values()) {\n clearTimeout(timer);\n }\n this.envChangeTimers.clear();\n for (const timer of this.envRestartTimers.values()) {\n clearTimeout(timer);\n }\n this.envRestartTimers.clear();\n }\n\n private scheduleEnvRestart(key: string, restart: () => void): void {\n const existing = this.envChangeTimers.get(key);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n this.envChangeTimers.delete(key);\n restart();\n }, 250);\n this.envChangeTimers.set(key, timer);\n }\n\n private scheduleEnvRestartForProcess(managed: ManagedProcess): void {\n if (!this.restartOnEnvChangeGlobal) return;\n if (managed.config.restartOnEnvChange === false) return;\n if (managed.status !== \"running\") return;\n const name = managed.config.name;\n const existing = this.envRestartTimers.get(name);\n if (existing) clearTimeout(existing);\n\n const delayMs = managed.config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;\n\n const timer = setTimeout(\n () => {\n this.envRestartTimers.delete(name);\n this.restart(name).catch((error) => {\n this.logger.error(`Failed to restart ${name} after env change: ${error}`);\n });\n },\n Math.max(0, delayMs),\n );\n\n this.envRestartTimers.set(name, timer);\n this.logger.info(`Restarting ${name} after env change in ${Math.max(0, delayMs)}ms`);\n }\n\n private resolveProcessIdentifier(nameOrId: string): {\n name: string;\n managed: ManagedProcess;\n } {\n const byName = this.processes.get(nameOrId);\n if (byName) {\n return { name: nameOrId, managed: byName };\n }\n\n if (/^\\d+$/.test(nameOrId)) {\n const id = Number(nameOrId);\n const name = this.processIds.get(id);\n if (name) {\n const managed = this.processes.get(name);\n if (managed) {\n return { name, managed };\n }\n }\n }\n\n throw new Error(`Process ${nameOrId} not found`);\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "pid1",
3
- "type": "module",
4
- "version": "0.0.0-dev.0",
3
+ "version": "0.0.0-dev.1",
5
4
  "bin": "./dist/cli.mjs",
5
+ "files": [
6
+ "dist",
7
+ "src"
8
+ ],
9
+ "type": "module",
6
10
  "exports": {
7
11
  ".": {
8
12
  "import": "./dist/index.mjs",
@@ -17,10 +21,6 @@
17
21
  "types": "./dist/client.d.mts"
18
22
  }
19
23
  },
20
- "files": [
21
- "src",
22
- "dist"
23
- ],
24
24
  "dependencies": {
25
25
  "@hono/node-server": "^1.19.9",
26
26
  "@orpc/client": "^1.13.4",
@@ -38,15 +38,17 @@
38
38
  "@types/node": "^25.0.10",
39
39
  "oxfmt": "^0.26.0",
40
40
  "tsdown": "^0.20.1",
41
- "vitest": "^3.2.4",
42
- "typescript": "^5.9.3"
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^3.2.4"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "tsdown",
46
46
  "dev": "tsx src/cli.ts init",
47
47
  "dev:docker": "docker build -t pid1 . && docker run --rm pid1",
48
+ "prepublish": "pnpm build",
48
49
  "test": "vitest run",
49
50
  "test:watch": "vitest",
50
- "typecheck": "tsc --noEmit"
51
+ "typecheck": "tsc --noEmit",
52
+ "format": "oxfmt"
51
53
  }
52
54
  }
package/src/api/client.ts CHANGED
@@ -7,9 +7,7 @@ export type ClientOptions = {
7
7
  url?: string;
8
8
  };
9
9
 
10
- export function createClient(
11
- options: ClientOptions = {},
12
- ): RouterClient<Router> {
10
+ export function createClient(options: ClientOptions = {}): RouterClient<Router> {
13
11
  const { url = "http://127.0.0.1:3000/rpc" } = options;
14
12
 
15
13
  const link = new RPCLink({ url });
package/src/api/router.ts CHANGED
@@ -24,11 +24,9 @@ type RouterContext = {
24
24
 
25
25
  const base = os.$context<RouterContext>();
26
26
 
27
- export const list = base
28
- .output(v.array(ProcessInfoSchema))
29
- .handler(async ({ context }) => {
30
- return context.pm.list();
31
- });
27
+ export const list = base.output(v.array(ProcessInfoSchema)).handler(async ({ context }) => {
28
+ return context.pm.list();
29
+ });
32
30
 
33
31
  export const get = base
34
32
  .input(ProcessNameSchema)
@@ -129,11 +127,9 @@ export const deleteProcess = base
129
127
  }
130
128
  });
131
129
 
132
- export const health = os
133
- .output(v.object({ status: v.literal("ok") }))
134
- .handler(async () => {
135
- return { status: "ok" as const };
136
- });
130
+ export const health = os.output(v.object({ status: v.literal("ok") })).handler(async () => {
131
+ return { status: "ok" as const };
132
+ });
137
133
 
138
134
  export const router = {
139
135
  health,
package/src/api/server.ts CHANGED
@@ -27,9 +27,7 @@ export function createServer(pm: ProcessManager, options: ServerOptions = {}) {
27
27
  ],
28
28
  });
29
29
 
30
- app.use(
31
- honoLogger((msg, ...args) => logger.debug(`${msg} ${args.join(" ")}`)),
32
- );
30
+ app.use(honoLogger((msg, ...args) => logger.debug(`${msg} ${args.join(" ")}`)));
33
31
 
34
32
  app.get("/health", (c) => c.json({ status: "ok" }));
35
33
 
package/src/cli.ts CHANGED
@@ -66,9 +66,7 @@ async function main() {
66
66
  program
67
67
  .name("pid1")
68
68
  .description("Process manager daemon and controller")
69
- .option("--port <number>", "Port for the HTTP server", (value) =>
70
- Number(value),
71
- )
69
+ .option("--port <number>", "Port for the HTTP server", (value) => Number(value))
72
70
  .option("--host <host>", "Host for the HTTP server");
73
71
 
74
72
  const commonOptions = (): CommonArgs => {
@@ -161,8 +159,6 @@ main().catch((error) => {
161
159
  );
162
160
  process.exit(1);
163
161
  }
164
- logger.error(
165
- error instanceof Error ? (error.stack ?? error.message) : String(error),
166
- );
162
+ logger.error(error instanceof Error ? (error.stack ?? error.message) : String(error));
167
163
  process.exit(1);
168
164
  });
package/src/config.ts CHANGED
@@ -38,16 +38,13 @@ export type LoadedConfig = v.InferOutput<typeof Config> & {
38
38
  configPath: string;
39
39
  };
40
40
 
41
- export async function loadConfigFile(
42
- path?: string,
43
- cwd?: string,
44
- ): Promise<LoadedConfig> {
41
+ export async function loadConfigFile(path?: string, cwd?: string): Promise<LoadedConfig> {
45
42
  const configFile = path ?? findConfigFile(cwd ?? process.cwd());
46
43
  if (!configFile) {
47
- logger.error(
44
+ logger.error(
48
45
  `Failed to find a config file in ${cwd ?? process.cwd()} or any of its parent directories`,
49
46
  );
50
- logger.error("Exiting...");
47
+ logger.error("Exiting...");
51
48
  process.exit(1);
52
49
  }
53
50
 
@@ -55,12 +52,10 @@ export async function loadConfigFile(
55
52
  const config = await tsImport(configFile, {
56
53
  parentURL: import.meta.url,
57
54
  })
58
- .then((m) =>
59
- "default" in m.default ? m.default.default : m.default,
60
- )
55
+ .then((m) => ("default" in m.default ? m.default.default : m.default))
61
56
  .catch((error) => {
62
57
  logger.error(`Failed to load config from ${configFile}`);
63
- logger.error(error instanceof Error ? error.stack ?? error.message : String(error));
58
+ logger.error(error instanceof Error ? (error.stack ?? error.message) : String(error));
64
59
  logger.error("Exiting...");
65
60
  process.exit(1);
66
61
  });
package/src/env.ts CHANGED
@@ -33,16 +33,8 @@ export type LoadEnvOptions = {
33
33
  configEnv?: Record<string, string>;
34
34
  };
35
35
 
36
- export function loadEnvForProcess(
37
- options: LoadEnvOptions,
38
- ): Record<string, string> {
39
- const {
40
- configDir,
41
- processName,
42
- globalEnvFile,
43
- processEnvFile,
44
- configEnv = {},
45
- } = options;
36
+ export function loadEnvForProcess(options: LoadEnvOptions): Record<string, string> {
37
+ const { configDir, processName, globalEnvFile, processEnvFile, configEnv = {} } = options;
46
38
 
47
39
  const baseEnv = Object.fromEntries(
48
40
  Object.entries(process.env).filter(([, value]) => value !== undefined),
@@ -56,8 +48,7 @@ export function loadEnvForProcess(
56
48
 
57
49
  let processEnv: Record<string, string> = {};
58
50
  if (processEnvFile !== false) {
59
- const processPath =
60
- processEnvFile ?? join(configDir, `.env.${processName}`);
51
+ const processPath = processEnvFile ?? join(configDir, `.env.${processName}`);
61
52
  processEnv = loadEnvFile(processPath);
62
53
  }
63
54
 
package/src/exec.ts CHANGED
@@ -53,9 +53,7 @@ export function spawnWithLogging({
53
53
  const done = (async () => {
54
54
  const logger = processLogger({ name: `${type}:${name}`, logFile });
55
55
 
56
- logger.info(
57
- `Starting: command=${command}, args=[${args.join(", ")}], cwd=${cwd}`,
58
- );
56
+ logger.info(`Starting: command=${command}, args=[${args.join(", ")}], cwd=${cwd}`);
59
57
 
60
58
  for await (const line of proc) {
61
59
  logger.info(line);
@@ -65,12 +63,7 @@ export function spawnWithLogging({
65
63
 
66
64
  const exitCode = proc.exitCode;
67
65
 
68
- if (
69
- proc.aborted ||
70
- proc.killed ||
71
- exitCode === null ||
72
- exitCode === undefined
73
- ) {
66
+ if (proc.aborted || proc.killed || exitCode === null || exitCode === undefined) {
74
67
  logger.info(`${name} was terminated`);
75
68
  } else if (exitCode === 0) {
76
69
  logger.info(`${name} completed successfully`);
@@ -97,10 +97,8 @@ export class ProcessManager {
97
97
  this.configDir = dirname(config.configPath);
98
98
  this.globalEnvFile = config.envFile;
99
99
  this.restartOnEnvChangeGlobal = config.restartOnEnvChange ?? true;
100
- this.restartMinDelayMsGlobal =
101
- config.restartMinDelayMs ?? DEFAULT_RESTART_MIN_DELAY_MS;
102
- this.restartMaxDelayMsGlobal =
103
- config.restartMaxDelayMs ?? DEFAULT_RESTART_MAX_DELAY_MS;
100
+ this.restartMinDelayMsGlobal = config.restartMinDelayMs ?? DEFAULT_RESTART_MIN_DELAY_MS;
101
+ this.restartMaxDelayMsGlobal = config.restartMaxDelayMs ?? DEFAULT_RESTART_MAX_DELAY_MS;
104
102
 
105
103
  this.logger.info(
106
104
  `Executing ${config.tasks.length} tasks and registering ${config.processes.length} processes`,
@@ -200,15 +198,11 @@ export class ProcessManager {
200
198
 
201
199
  const exitedGracefully = await Promise.race([
202
200
  spawned.done.then(() => true).catch(() => true),
203
- new Promise<false>((resolve) =>
204
- setTimeout(() => resolve(false), timeoutMs),
205
- ),
201
+ new Promise<false>((resolve) => setTimeout(() => resolve(false), timeoutMs)),
206
202
  ]);
207
203
 
208
204
  if (!exitedGracefully && managed.status === "running") {
209
- this.logger.warn(
210
- `Process ${resolvedName} did not stop gracefully, sending SIGKILL`,
211
- );
205
+ this.logger.warn(`Process ${resolvedName} did not stop gracefully, sending SIGKILL`);
212
206
  spawned.kill("SIGKILL");
213
207
  await spawned.done.catch(() => {});
214
208
  }
@@ -331,21 +325,16 @@ export class ProcessManager {
331
325
  managed.startedAt = new Date();
332
326
  managed.exitCode = null;
333
327
 
334
- this.logger.info(
335
- `Started process: ${config.name} (pid: ${spawned.proc.pid})`,
336
- );
328
+ this.logger.info(`Started process: ${config.name} (pid: ${spawned.proc.pid})`);
337
329
 
338
330
  const handleExit = (exitCode: number | null, error?: unknown) => {
339
331
  managed.exitCode = exitCode;
340
332
  managed.status =
341
- exitCode === null || exitCode === undefined || exitCode === 0
342
- ? "stopped"
343
- : "errored";
333
+ exitCode === null || exitCode === undefined || exitCode === 0 ? "stopped" : "errored";
344
334
  const now = Date.now();
345
335
  const startedAt = managed.startedAt?.getTime() ?? now;
346
336
  const uptimeMs = Math.max(0, now - startedAt);
347
- const resetMs =
348
- (config.restartResetSeconds ?? DEFAULT_RESTART_RESET_SECONDS) * 1000;
337
+ const resetMs = (config.restartResetSeconds ?? DEFAULT_RESTART_RESET_SECONDS) * 1000;
349
338
 
350
339
  if (uptimeMs >= resetMs) {
351
340
  managed.restartAttempts = 0;
@@ -364,11 +353,9 @@ export class ProcessManager {
364
353
  }
365
354
 
366
355
  const policy = config.restartPolicy ?? "on-failure";
367
- const isFailure =
368
- exitCode === null || exitCode === undefined || exitCode !== 0;
356
+ const isFailure = exitCode === null || exitCode === undefined || exitCode !== 0;
369
357
  const shouldRestart =
370
- !managed.stopRequested &&
371
- (policy === "always" || (policy === "on-failure" && isFailure));
358
+ !managed.stopRequested && (policy === "always" || (policy === "on-failure" && isFailure));
372
359
 
373
360
  if (!shouldRestart) {
374
361
  return;
@@ -387,10 +374,7 @@ export class ProcessManager {
387
374
  managed.restarts += 1;
388
375
  const minDelay = config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;
389
376
  const maxDelay = config.restartMaxDelayMs ?? this.restartMaxDelayMsGlobal;
390
- const delay = Math.min(
391
- maxDelay,
392
- minDelay * Math.pow(2, managed.restartAttempts - 1),
393
- );
377
+ const delay = Math.min(maxDelay, minDelay * Math.pow(2, managed.restartAttempts - 1));
394
378
 
395
379
  this.logger.warn(
396
380
  `Restarting process ${config.name} in ${delay}ms (attempt ${managed.restartAttempts}/${maxRestarts})`,
@@ -449,9 +433,7 @@ export class ProcessManager {
449
433
  }
450
434
 
451
435
  if (exitCode !== 0) {
452
- this.logger.error(
453
- `Task ${task.name} failed with exit code ${exitCode}`,
454
- );
436
+ this.logger.error(`Task ${task.name} failed with exit code ${exitCode}`);
455
437
  throw new Error(`Task ${task.name} failed`);
456
438
  }
457
439
  }
@@ -468,9 +450,7 @@ export class ProcessManager {
468
450
  }
469
451
  }
470
452
 
471
- private async stopActiveTask(
472
- timeoutMs = DEFAULT_STOP_TIMEOUT_MS,
473
- ): Promise<void> {
453
+ private async stopActiveTask(timeoutMs = DEFAULT_STOP_TIMEOUT_MS): Promise<void> {
474
454
  if (!this.currentTask) return;
475
455
 
476
456
  const taskName = this.currentTaskName ?? "unknown";
@@ -479,15 +459,11 @@ export class ProcessManager {
479
459
 
480
460
  const exitedGracefully = await Promise.race([
481
461
  this.currentTask.done.then(() => true).catch(() => true),
482
- new Promise<false>((resolve) =>
483
- setTimeout(() => resolve(false), timeoutMs),
484
- ),
462
+ new Promise<false>((resolve) => setTimeout(() => resolve(false), timeoutMs)),
485
463
  ]);
486
464
 
487
465
  if (!exitedGracefully) {
488
- this.logger.warn(
489
- `Task ${taskName} did not stop gracefully, sending SIGKILL`,
490
- );
466
+ this.logger.warn(`Task ${taskName} did not stop gracefully, sending SIGKILL`);
491
467
  this.currentTask.kill("SIGKILL");
492
468
  await this.currentTask.done.catch(() => {});
493
469
  }
@@ -545,9 +521,7 @@ export class ProcessManager {
545
521
  this.scheduleEnvRestart(processName, () => {
546
522
  const managed = this.processes.get(processName);
547
523
  if (!managed) return;
548
- this.logger.info(
549
- `Detected ${envFile} change, scheduling restart for ${processName}`,
550
- );
524
+ this.logger.info(`Detected ${envFile} change, scheduling restart for ${processName}`);
551
525
  this.scheduleEnvRestartForProcess(managed);
552
526
  });
553
527
  });
@@ -586,25 +560,20 @@ export class ProcessManager {
586
560
  const existing = this.envRestartTimers.get(name);
587
561
  if (existing) clearTimeout(existing);
588
562
 
589
- const delayMs =
590
- managed.config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;
563
+ const delayMs = managed.config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;
591
564
 
592
565
  const timer = setTimeout(
593
566
  () => {
594
567
  this.envRestartTimers.delete(name);
595
568
  this.restart(name).catch((error) => {
596
- this.logger.error(
597
- `Failed to restart ${name} after env change: ${error}`,
598
- );
569
+ this.logger.error(`Failed to restart ${name} after env change: ${error}`);
599
570
  });
600
571
  },
601
572
  Math.max(0, delayMs),
602
573
  );
603
574
 
604
575
  this.envRestartTimers.set(name, timer);
605
- this.logger.info(
606
- `Restarting ${name} after env change in ${Math.max(0, delayMs)}ms`,
607
- );
576
+ this.logger.info(`Restarting ${name} after env change in ${Math.max(0, delayMs)}ms`);
608
577
  }
609
578
 
610
579
  private resolveProcessIdentifier(nameOrId: string): {
@@ -1 +0,0 @@
1
- {"version":3,"file":"process-manager-gO56266Q.mjs","names":["logger","logger","honoLogger"],"sources":["../src/env.ts","../src/exec.ts","../src/api/router.ts","../src/api/server.ts","../src/process-manager.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { parse } from \"dotenv\";\nimport { globalLogger } from \"./logger\";\n\nexport type EnvFileConfig = {\n envFile?: string | false;\n};\n\nconst logger = globalLogger.child(\"env\");\n\nfunction loadEnvFile(path: string): Record<string, string> {\n if (!existsSync(path)) {\n return {};\n }\n\n try {\n const content = readFileSync(path, \"utf-8\");\n const parsed = parse(content);\n logger.debug(`Loaded env file: ${path}`);\n return parsed;\n } catch (error) {\n logger.warn(`Failed to parse env file ${path}: ${error}`);\n return {};\n }\n}\n\nexport type LoadEnvOptions = {\n configDir: string;\n processName: string;\n globalEnvFile?: string | false;\n processEnvFile?: string | false;\n configEnv?: Record<string, string>;\n};\n\nexport function loadEnvForProcess(\n options: LoadEnvOptions,\n): Record<string, string> {\n const {\n configDir,\n processName,\n globalEnvFile,\n processEnvFile,\n configEnv = {},\n } = options;\n\n const baseEnv = Object.fromEntries(\n Object.entries(process.env).filter(([, value]) => value !== undefined),\n ) as Record<string, string>;\n\n let globalEnv: Record<string, string> = {};\n if (globalEnvFile !== false) {\n const globalPath = globalEnvFile ?? join(configDir, \".env\");\n globalEnv = loadEnvFile(globalPath);\n }\n\n let processEnv: Record<string, string> = {};\n if (processEnvFile !== false) {\n const processPath =\n processEnvFile ?? join(configDir, `.env.${processName}`);\n processEnv = loadEnvFile(processPath);\n }\n\n return {\n ...baseEnv,\n ...globalEnv,\n ...configEnv,\n ...processEnv,\n };\n}\n\nexport function getConfigDir(configPath: string): string {\n return dirname(configPath);\n}\n","import { processLogger } from \"./logger\";\nimport { x } from \"tinyexec\";\n\ntype ExecType = \"task\" | \"process\";\n\ntype ExecWithLoggingParams = {\n name: string;\n command: string;\n args: string[];\n env: Record<string, string>;\n cwd: string;\n logFile: string;\n abortSignal?: AbortSignal;\n type: ExecType;\n};\n\ntype TinyExecProcess = ReturnType<typeof x>;\n\nexport type SpawnedProcess = {\n proc: TinyExecProcess;\n done: Promise<number | null>;\n kill: (signal?: NodeJS.Signals) => boolean;\n};\n\nexport function spawnWithLogging({\n name,\n command,\n args,\n env,\n cwd,\n logFile,\n abortSignal,\n type,\n}: ExecWithLoggingParams): SpawnedProcess {\n const proc = x(command, args, {\n nodeOptions: { cwd, env },\n signal: abortSignal,\n throwOnError: true,\n });\n\n const kill = (signal: NodeJS.Signals = \"SIGTERM\"): boolean => {\n if (proc.pid) {\n try {\n process.kill(proc.pid, signal);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n };\n\n const done = (async () => {\n const logger = processLogger({ name: `${type}:${name}`, logFile });\n\n logger.info(\n `Starting: command=${command}, args=[${args.join(\", \")}], cwd=${cwd}`,\n );\n\n for await (const line of proc) {\n logger.info(line);\n }\n\n await proc;\n\n const exitCode = proc.exitCode;\n\n if (\n proc.aborted ||\n proc.killed ||\n exitCode === null ||\n exitCode === undefined\n ) {\n logger.info(`${name} was terminated`);\n } else if (exitCode === 0) {\n logger.info(`${name} completed successfully`);\n } else {\n logger.info(`${name} exited with code ${exitCode}`);\n }\n\n return proc.exitCode ?? null;\n })();\n\n return { proc, done, kill };\n}\n","import { os, ORPCError } from \"@orpc/server\";\nimport * as v from \"valibot\";\nimport type { ProcessManager, ProcessInfo } from \"../process-manager.ts\";\n\nconst ProcessInfoSchema = v.object({\n id: v.number(),\n name: v.string(),\n status: v.picklist([\"stopped\", \"running\", \"errored\"]),\n pid: v.optional(v.number()),\n exitCode: v.nullable(v.number()),\n restarts: v.number(),\n startedAt: v.nullable(v.date()),\n command: v.string(),\n args: v.array(v.string()),\n});\n\nconst ProcessNameSchema = v.object({\n name: v.string(),\n});\n\ntype RouterContext = {\n pm: ProcessManager;\n};\n\nconst base = os.$context<RouterContext>();\n\nexport const list = base\n .output(v.array(ProcessInfoSchema))\n .handler(async ({ context }) => {\n return context.pm.list();\n });\n\nexport const get = base\n .input(ProcessNameSchema)\n .output(v.nullable(ProcessInfoSchema))\n .handler(async ({ input, context }) => {\n return context.pm.get(input.name) ?? null;\n });\n\nexport const start = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n context.pm.start(input.name);\n return { success: true, message: `Started process: ${input.name}` };\n } else {\n context.pm.startAll();\n return { success: true, message: \"Started all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to start\",\n });\n }\n });\n\nexport const stop = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n await context.pm.stop(input.name);\n return { success: true, message: `Stopped process: ${input.name}` };\n } else {\n await context.pm.stopAll();\n return { success: true, message: \"Stopped all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to stop\",\n });\n }\n });\n\nexport const restart = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n await context.pm.restart(input.name);\n return { success: true, message: `Restarted process: ${input.name}` };\n } else {\n await context.pm.restartAll();\n return { success: true, message: \"Restarted all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to restart\",\n });\n }\n });\n\nexport const deleteProcess = base\n .input(\n v.object({\n name: v.optional(v.string()),\n }),\n )\n .output(v.object({ success: v.boolean(), message: v.string() }))\n .handler(async ({ input, context }) => {\n try {\n if (input.name) {\n await context.pm.delete(input.name);\n return { success: true, message: `Deleted process: ${input.name}` };\n } else {\n await context.pm.deleteAll();\n return { success: true, message: \"Deleted all processes\" };\n }\n } catch (error) {\n throw new ORPCError(\"BAD_REQUEST\", {\n message: error instanceof Error ? error.message : \"Failed to delete\",\n });\n }\n });\n\nexport const health = os\n .output(v.object({ status: v.literal(\"ok\") }))\n .handler(async () => {\n return { status: \"ok\" as const };\n });\n\nexport const router = {\n health,\n process: {\n list,\n get,\n start,\n stop,\n restart,\n delete: deleteProcess,\n },\n};\n\nexport type Router = typeof router;\n","import { Hono } from \"hono\";\nimport { serve } from \"@hono/node-server\";\nimport { RPCHandler } from \"@orpc/server/fetch\";\nimport { onError } from \"@orpc/server\";\nimport { router } from \"./router.ts\";\nimport type { ProcessManager } from \"../process-manager.ts\";\nimport { globalLogger } from \"../logger.ts\";\nimport { logger as honoLogger } from \"hono/logger\";\n\nexport type ServerOptions = {\n port?: number;\n host?: string;\n};\n\nexport function createServer(pm: ProcessManager, options: ServerOptions = {}) {\n const { port = 3000, host = \"127.0.0.1\" } = options;\n const logger = globalLogger.child(\"server\");\n\n const app = new Hono();\n\n const handler = new RPCHandler(router, {\n interceptors: [\n onError((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`RPC Error: ${message}`);\n }),\n ],\n });\n\n app.use(\n honoLogger((msg, ...args) => logger.debug(`${msg} ${args.join(\" \")}`)),\n );\n\n app.get(\"/health\", (c) => c.json({ status: \"ok\" }));\n\n app.use(\"/rpc/*\", async (c, next) => {\n const { matched, response } = await handler.handle(c.req.raw, {\n prefix: \"/rpc\",\n context: { pm },\n });\n\n if (matched) {\n return c.newResponse(response.body, response);\n }\n\n await next();\n });\n\n app.notFound((c) => c.json({ error: \"Not found\" }, 404));\n\n return {\n app,\n start: () => {\n const server = serve({\n fetch: app.fetch,\n port,\n hostname: host,\n });\n\n logger.info(`HTTP server listening on http://${host}:${port}`);\n logger.info(`RPC endpoint: http://${host}:${port}/rpc`);\n\n return server;\n },\n };\n}\n\nexport type { Router } from \"./router.ts\";\n","import { dirname, join } from \"node:path\";\nimport { watch, type FSWatcher } from \"node:fs\";\nimport { loadConfigFile } from \"./config.ts\";\nimport { loadEnvForProcess } from \"./env.ts\";\nimport { spawnWithLogging, type SpawnedProcess } from \"./exec.ts\";\nimport { globalLogger } from \"./logger.ts\";\nimport { createServer, type ServerOptions } from \"./api/server.ts\";\n\nexport type ProcessManagerOptions = {\n cwd?: string;\n configPath?: string;\n server?: ServerOptions & { enabled?: boolean };\n};\n\nexport type ProcessStatus = \"stopped\" | \"running\" | \"errored\";\nexport type RestartPolicy = \"never\" | \"always\" | \"on-failure\";\n\nexport type ProcessConfig = {\n name: string;\n command: string;\n args: string[];\n env: Record<string, string>;\n cwd?: string;\n envFile?: string | false;\n restartOnEnvChange?: boolean;\n restartPolicy?: RestartPolicy;\n maxRestarts?: number;\n restartMinDelayMs?: number;\n restartMaxDelayMs?: number;\n restartResetSeconds?: number;\n};\n\nexport type ManagedProcess = {\n id: number;\n config: ProcessConfig;\n status: ProcessStatus;\n spawned: SpawnedProcess | null;\n exitCode: number | null;\n restarts: number;\n restartAttempts: number;\n restartTimer: NodeJS.Timeout | null;\n stopRequested: boolean;\n startedAt: Date | null;\n};\n\nconst DEFAULT_STOP_TIMEOUT_MS = 10000;\nconst DEFAULT_RESTART_RESET_SECONDS = 300;\nconst DEFAULT_RESTART_MAX = 10;\nconst DEFAULT_RESTART_MIN_DELAY_MS = 5000;\nconst DEFAULT_RESTART_MAX_DELAY_MS = 60000;\n\nexport type ProcessInfo = {\n id: number;\n name: string;\n status: ProcessStatus;\n pid: number | undefined;\n exitCode: number | null;\n restarts: number;\n startedAt: Date | null;\n command: string;\n args: string[];\n};\n\nexport class ProcessManager {\n private logger = globalLogger.child(\"pm\");\n private cwd: string;\n private configPath?: string;\n private configDir?: string;\n private globalEnvFile?: string | false;\n private processes: Map<string, ManagedProcess>;\n private processIds: Map<number, string>;\n private nextProcessId = 0;\n private signalHandlersSetup = false;\n private serverOptions?: ServerOptions & { enabled?: boolean };\n private httpServer?: ReturnType<ReturnType<typeof createServer>[\"start\"]>;\n private envWatcher: FSWatcher | null = null;\n private envChangeTimers = new Map<string, NodeJS.Timeout>();\n private envRestartTimers = new Map<string, NodeJS.Timeout>();\n private restartOnEnvChangeGlobal = true;\n private restartMinDelayMsGlobal = DEFAULT_RESTART_MIN_DELAY_MS;\n private restartMaxDelayMsGlobal = DEFAULT_RESTART_MAX_DELAY_MS;\n private currentTask: SpawnedProcess | null = null;\n private currentTaskName: string | null = null;\n private taskAbortController: AbortController | null = null;\n\n constructor(options: ProcessManagerOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n this.configPath = options.configPath;\n this.processes = new Map();\n this.processIds = new Map();\n this.serverOptions = options.server;\n }\n\n async init(): Promise<void> {\n const config = await loadConfigFile(this.configPath, this.cwd);\n\n this.configDir = dirname(config.configPath);\n this.globalEnvFile = config.envFile;\n this.restartOnEnvChangeGlobal = config.restartOnEnvChange ?? true;\n this.restartMinDelayMsGlobal =\n config.restartMinDelayMs ?? DEFAULT_RESTART_MIN_DELAY_MS;\n this.restartMaxDelayMsGlobal =\n config.restartMaxDelayMs ?? DEFAULT_RESTART_MAX_DELAY_MS;\n\n this.logger.info(\n `Executing ${config.tasks.length} tasks and registering ${config.processes.length} processes`,\n );\n\n this.setupSignalHandlers();\n this.setupEnvWatchers();\n await this.runTasks(config.tasks);\n\n for (const p of config.processes) {\n this.register(p);\n }\n }\n\n register(config: ProcessConfig): void {\n if (this.processes.has(config.name)) {\n throw new Error(`Process ${config.name} already registered`);\n }\n\n const id = this.nextProcessId++;\n const managed: ManagedProcess = {\n id,\n config,\n status: \"stopped\",\n spawned: null,\n exitCode: null,\n restarts: 0,\n restartAttempts: 0,\n restartTimer: null,\n stopRequested: false,\n startedAt: null,\n };\n\n this.processes.set(config.name, managed);\n this.processIds.set(id, config.name);\n this.logger.info(`Registered process: ${config.name} (id: ${id})`);\n }\n\n list(): ProcessInfo[] {\n return [...this.processes.values()].map((m) => ({\n id: m.id,\n name: m.config.name,\n status: m.status,\n pid: m.spawned?.proc.pid,\n exitCode: m.exitCode,\n restarts: m.restarts,\n startedAt: m.startedAt,\n command: m.config.command,\n args: m.config.args,\n }));\n }\n\n start(name: string): void {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n if (managed.status === \"running\") {\n this.logger.warn(`Process ${resolvedName} is already running`);\n return;\n }\n\n this.spawnProcess(managed);\n }\n\n startAll(): void {\n this.setupSignalHandlers();\n\n for (const [_, managed] of this.processes) {\n if (managed.status !== \"running\") {\n this.spawnProcess(managed);\n }\n }\n }\n\n serve(options?: ServerOptions & { enabled?: boolean }): void {\n const serverOpts = { ...this.serverOptions, ...options };\n if (serverOpts.enabled === false) return;\n const { enabled: _enabled, ...serverOptions } = serverOpts;\n const server = createServer(this, serverOptions);\n this.httpServer = server.start();\n }\n\n async stop(name: string, timeoutMs = DEFAULT_STOP_TIMEOUT_MS): Promise<void> {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n managed.stopRequested = true;\n this.clearRestartTimer(managed);\n\n if (managed.status !== \"running\" || !managed.spawned) {\n this.logger.warn(`Process ${resolvedName} is not running`);\n return;\n }\n\n const { spawned } = managed;\n\n this.logger.info(`Stopping process: ${resolvedName} (SIGTERM)`);\n spawned.kill(\"SIGTERM\");\n\n const exitedGracefully = await Promise.race([\n spawned.done.then(() => true).catch(() => true),\n new Promise<false>((resolve) =>\n setTimeout(() => resolve(false), timeoutMs),\n ),\n ]);\n\n if (!exitedGracefully && managed.status === \"running\") {\n this.logger.warn(\n `Process ${resolvedName} did not stop gracefully, sending SIGKILL`,\n );\n spawned.kill(\"SIGKILL\");\n await spawned.done.catch(() => {});\n }\n }\n\n async stopAll(): Promise<void> {\n this.logger.info(\"Stopping all processes...\");\n\n for (const managed of this.processes.values()) {\n managed.stopRequested = true;\n this.clearRestartTimer(managed);\n }\n\n const stopPromises = [...this.processes.entries()]\n .filter(([, m]) => m.status === \"running\")\n .map(([name]) => this.stop(name));\n\n await Promise.allSettled(stopPromises);\n }\n\n async restart(name: string): Promise<void> {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n this.logger.info(`Restarting process: ${resolvedName}`);\n\n if (managed.status === \"running\") {\n await this.stop(resolvedName);\n }\n\n managed.restarts++;\n this.spawnProcess(managed);\n }\n\n async restartAll(): Promise<void> {\n this.logger.info(\"Restarting all processes...\");\n\n for (const [name] of this.processes) {\n await this.restart(name);\n }\n }\n\n async delete(name: string): Promise<void> {\n const { name: resolvedName, managed } = this.resolveProcessIdentifier(name);\n\n managed.stopRequested = true;\n this.clearRestartTimer(managed);\n\n if (managed.status === \"running\") {\n await this.stop(resolvedName);\n }\n\n this.processes.delete(resolvedName);\n this.processIds.delete(managed.id);\n this.logger.info(`Deleted process: ${resolvedName}`);\n }\n\n async deleteAll(): Promise<void> {\n await this.stopAll();\n this.processes.clear();\n this.logger.info(\"Deleted all processes\");\n }\n\n get(name: string): ProcessInfo | undefined {\n let resolved: { name: string; managed: ManagedProcess };\n try {\n resolved = this.resolveProcessIdentifier(name);\n } catch {\n return undefined;\n }\n\n return {\n id: resolved.managed.id,\n name: resolved.managed.config.name,\n status: resolved.managed.status,\n pid: resolved.managed.spawned?.proc.pid,\n exitCode: resolved.managed.exitCode,\n restarts: resolved.managed.restarts,\n startedAt: resolved.managed.startedAt,\n command: resolved.managed.config.command,\n args: resolved.managed.config.args,\n };\n }\n\n async wait(): Promise<void> {\n const donePromises = [...this.processes.values()]\n .filter((m) => m.spawned)\n .map((m) => m.spawned!.done);\n\n await Promise.allSettled(donePromises);\n this.logger.info(\"All processes exited\");\n }\n\n async shutdown(): Promise<void> {\n await this.stopActiveTask();\n await this.stopAll();\n this.closeEnvWatcher();\n if (this.httpServer) {\n this.httpServer.close();\n this.logger.info(\"HTTP server closed\");\n }\n }\n\n private spawnProcess(managed: ManagedProcess): void {\n const { config } = managed;\n\n managed.stopRequested = false;\n this.clearRestartTimer(managed);\n\n const env = loadEnvForProcess({\n configDir: this.configDir ?? this.cwd,\n processName: config.name,\n globalEnvFile: this.globalEnvFile,\n processEnvFile: config.envFile,\n configEnv: config.env,\n });\n\n const spawned = spawnWithLogging({\n cwd: config.cwd ?? this.cwd,\n logFile: join(this.cwd, \"logs\", \"processes\", `${config.name}.log`),\n type: \"process\",\n name: config.name,\n command: config.command,\n args: config.args,\n env,\n });\n\n managed.spawned = spawned;\n managed.status = \"running\";\n managed.startedAt = new Date();\n managed.exitCode = null;\n\n this.logger.info(\n `Started process: ${config.name} (pid: ${spawned.proc.pid})`,\n );\n\n const handleExit = (exitCode: number | null, error?: unknown) => {\n managed.exitCode = exitCode;\n managed.status =\n exitCode === null || exitCode === undefined || exitCode === 0\n ? \"stopped\"\n : \"errored\";\n const now = Date.now();\n const startedAt = managed.startedAt?.getTime() ?? now;\n const uptimeMs = Math.max(0, now - startedAt);\n const resetMs =\n (config.restartResetSeconds ?? DEFAULT_RESTART_RESET_SECONDS) * 1000;\n\n if (uptimeMs >= resetMs) {\n managed.restartAttempts = 0;\n }\n\n if (exitCode === null || exitCode === undefined) {\n this.logger.info(`Process ${config.name} stopped`);\n } else if (exitCode !== 0) {\n this.logger.info(\n `Process ${config.name} exited with code ${exitCode}`,\n );\n } else {\n this.logger.info(`Process ${config.name} exited successfully`);\n }\n\n if (error) {\n this.logger.error(`Process ${config.name} failed with error: ${error}`);\n }\n\n const policy = config.restartPolicy ?? \"on-failure\";\n const isFailure =\n exitCode === null || exitCode === undefined || exitCode !== 0;\n const shouldRestart =\n !managed.stopRequested &&\n (policy === \"always\" || (policy === \"on-failure\" && isFailure));\n\n if (!shouldRestart) {\n return;\n }\n\n const maxRestarts = config.maxRestarts ?? DEFAULT_RESTART_MAX;\n if (managed.restartAttempts >= maxRestarts) {\n managed.status = \"errored\";\n this.logger.warn(\n `Process ${config.name} reached restart limit (${maxRestarts}), not restarting`,\n );\n return;\n }\n\n managed.restartAttempts += 1;\n managed.restarts += 1;\n const minDelay =\n config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;\n const maxDelay =\n config.restartMaxDelayMs ?? this.restartMaxDelayMsGlobal;\n const delay = Math.min(\n maxDelay,\n minDelay * Math.pow(2, managed.restartAttempts - 1),\n );\n\n this.logger.warn(\n `Restarting process ${config.name} in ${delay}ms (attempt ${managed.restartAttempts}/${maxRestarts})`,\n );\n\n managed.restartTimer = setTimeout(() => {\n managed.restartTimer = null;\n if (!managed.stopRequested) {\n this.spawnProcess(managed);\n }\n }, delay);\n };\n\n spawned.done\n .then((exitCode) => handleExit(exitCode))\n .catch((error) => {\n const exitCode = spawned.proc.exitCode ?? 1;\n handleExit(exitCode, error);\n });\n }\n\n private async runTasks(tasks: Array<ProcessConfig>): Promise<void> {\n for (const task of tasks) {\n const env = loadEnvForProcess({\n configDir: this.configDir ?? this.cwd,\n processName: task.name,\n globalEnvFile: this.globalEnvFile,\n processEnvFile: task.envFile,\n configEnv: task.env,\n });\n\n const taskAbortController = new AbortController();\n this.taskAbortController = taskAbortController;\n\n const spawned = spawnWithLogging({\n cwd: task.cwd ?? this.cwd,\n logFile: join(this.cwd, \"logs\", \"tasks\", `${task.name}.log`),\n type: \"task\",\n name: task.name,\n command: task.command,\n args: task.args,\n env,\n abortSignal: taskAbortController.signal,\n });\n\n this.currentTask = spawned;\n this.currentTaskName = task.name;\n\n let exitCode: number | null;\n try {\n exitCode = await spawned.done;\n } finally {\n this.currentTask = null;\n this.currentTaskName = null;\n this.taskAbortController = null;\n }\n\n if (exitCode !== 0) {\n this.logger.error(\n `Task ${task.name} failed with exit code ${exitCode}`,\n );\n throw new Error(`Task ${task.name} failed`);\n }\n }\n\n if (tasks.length > 0) {\n this.logger.info(\"All tasks completed\");\n }\n }\n\n private clearRestartTimer(managed: ManagedProcess): void {\n if (managed.restartTimer) {\n clearTimeout(managed.restartTimer);\n managed.restartTimer = null;\n }\n }\n\n private async stopActiveTask(\n timeoutMs = DEFAULT_STOP_TIMEOUT_MS,\n ): Promise<void> {\n if (!this.currentTask) return;\n\n const taskName = this.currentTaskName ?? \"unknown\";\n this.logger.info(`Stopping task: ${taskName} (SIGTERM)`);\n this.currentTask.kill(\"SIGTERM\");\n\n const exitedGracefully = await Promise.race([\n this.currentTask.done.then(() => true).catch(() => true),\n new Promise<false>((resolve) =>\n setTimeout(() => resolve(false), timeoutMs),\n ),\n ]);\n\n if (!exitedGracefully) {\n this.logger.warn(\n `Task ${taskName} did not stop gracefully, sending SIGKILL`,\n );\n this.currentTask.kill(\"SIGKILL\");\n await this.currentTask.done.catch(() => {});\n }\n }\n\n private abortActiveTask(signal: NodeJS.Signals): void {\n if (this.taskAbortController && !this.taskAbortController.signal.aborted) {\n this.taskAbortController.abort();\n }\n if (this.currentTask) {\n this.currentTask.kill(signal);\n }\n }\n\n private setupSignalHandlers(): void {\n if (this.signalHandlersSetup) return;\n this.signalHandlersSetup = true;\n\n const signals = [\"SIGINT\", \"SIGTERM\"] as const;\n for (const signal of signals) {\n process.on(signal, () => {\n process.stdout.write(\"\\r\\x1b[K\");\n this.logger.info(`Received ${signal}, shutting down...`);\n this.abortActiveTask(signal);\n this.shutdown().then(() => process.exit(0));\n });\n }\n }\n\n private setupEnvWatchers(): void {\n if (this.envWatcher) return;\n if (!this.restartOnEnvChangeGlobal) return;\n\n const watchDir = this.configDir ?? this.cwd;\n this.envWatcher = watch(watchDir, (event, filename) => {\n if (!filename) return;\n const envFile = filename.toString();\n if (!envFile.startsWith(\".env\")) return;\n if (event !== \"change\" && event !== \"rename\") return;\n\n if (envFile === \".env\") {\n this.scheduleEnvRestart(\"global\", () => {\n this.logger.info(\"Detected .env change, scheduling restarts\");\n for (const managed of this.processes.values()) {\n this.scheduleEnvRestartForProcess(managed);\n }\n });\n return;\n }\n\n if (!envFile.startsWith(\".env.\")) return;\n const processName = envFile.slice(\".env.\".length);\n if (!processName) return;\n\n this.scheduleEnvRestart(processName, () => {\n const managed = this.processes.get(processName);\n if (!managed) return;\n this.logger.info(\n `Detected ${envFile} change, scheduling restart for ${processName}`,\n );\n this.scheduleEnvRestartForProcess(managed);\n });\n });\n }\n\n private closeEnvWatcher(): void {\n if (this.envWatcher) {\n this.envWatcher.close();\n this.envWatcher = null;\n }\n for (const timer of this.envChangeTimers.values()) {\n clearTimeout(timer);\n }\n this.envChangeTimers.clear();\n for (const timer of this.envRestartTimers.values()) {\n clearTimeout(timer);\n }\n this.envRestartTimers.clear();\n }\n\n private scheduleEnvRestart(key: string, restart: () => void): void {\n const existing = this.envChangeTimers.get(key);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n this.envChangeTimers.delete(key);\n restart();\n }, 250);\n this.envChangeTimers.set(key, timer);\n }\n\n private scheduleEnvRestartForProcess(managed: ManagedProcess): void {\n if (!this.restartOnEnvChangeGlobal) return;\n if (managed.config.restartOnEnvChange === false) return;\n if (managed.status !== \"running\") return;\n const name = managed.config.name;\n const existing = this.envRestartTimers.get(name);\n if (existing) clearTimeout(existing);\n\n const delayMs =\n managed.config.restartMinDelayMs ?? this.restartMinDelayMsGlobal;\n\n const timer = setTimeout(() => {\n this.envRestartTimers.delete(name);\n this.restart(name).catch((error) => {\n this.logger.error(\n `Failed to restart ${name} after env change: ${error}`,\n );\n });\n }, Math.max(0, delayMs));\n\n this.envRestartTimers.set(name, timer);\n this.logger.info(\n `Restarting ${name} after env change in ${Math.max(0, delayMs)}ms`,\n );\n }\n\n private resolveProcessIdentifier(nameOrId: string): {\n name: string;\n managed: ManagedProcess;\n } {\n const byName = this.processes.get(nameOrId);\n if (byName) {\n return { name: nameOrId, managed: byName };\n }\n\n if (/^\\d+$/.test(nameOrId)) {\n const id = Number(nameOrId);\n const name = this.processIds.get(id);\n if (name) {\n const managed = this.processes.get(name);\n if (managed) {\n return { name, managed };\n }\n }\n }\n\n throw new Error(`Process ${nameOrId} not found`);\n }\n}\n"],"mappings":"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"}