pidnap 0.0.0-dev.5 → 0.0.0-dev.7

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,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { _ as ProcessDefinition, a as TaskStateSchema, c as CronProcessState, h as RestartingProcessState, i as TaskList, m as RestartingProcessOptions, n as EnvManager, o as CronProcess, p as RestartingProcess, s as CronProcessOptions, t as logger } from "./logger-BU2RmetS.mjs";
2
+ import { _ as ProcessDefinition, a as TaskStateSchema, c as CronProcessState, h as RestartingProcessState, i as TaskList, m as RestartingProcessOptions, n as logger, o as CronProcess, p as RestartingProcess, s as CronProcessOptions, t as EnvManager } from "./env-manager-FKhvfwIR.mjs";
3
3
  import { createClient } from "./client.mjs";
4
- import { Command } from "commander";
5
4
  import { createServer } from "node:http";
6
5
  import { pathToFileURL } from "node:url";
7
6
  import { join, resolve } from "node:path";
8
7
  import { RPCHandler } from "@orpc/server/node";
9
- import { implement, onError } from "@orpc/server";
8
+ import { implement, onError, os } from "@orpc/server";
10
9
  import * as v from "valibot";
11
10
  import { oc } from "@orpc/contract";
12
11
  import { cwd } from "node:process";
13
12
  import { mkdirSync } from "node:fs";
13
+ import { format } from "node:util";
14
14
  import Table from "cli-table3";
15
+ import { createCli } from "trpc-cli";
15
16
 
16
17
  //#region src/api/contract.ts
17
18
  const oc$1 = oc.$input(v.void());
18
- const ResourceTarget = v.union([v.string(), v.number()]);
19
+ const ResourceTarget$1 = v.union([v.string(), v.number()]);
19
20
  const ManagerStateSchema = v.picklist([
20
21
  "idle",
21
22
  "initializing",
@@ -48,51 +49,51 @@ const TaskEntryInfoSchema = v.object({
48
49
  });
49
50
  const manager = { status: oc$1.output(ManagerStatusSchema) };
50
51
  const processes = {
51
- get: oc$1.input(v.object({ target: ResourceTarget })).output(RestartingProcessInfoSchema),
52
+ get: oc$1.input(v.object({ target: ResourceTarget$1 })).output(RestartingProcessInfoSchema),
52
53
  list: oc$1.output(v.array(RestartingProcessInfoSchema)),
53
54
  add: oc$1.input(v.object({
54
55
  name: v.string(),
55
56
  definition: ProcessDefinition
56
57
  })).output(RestartingProcessInfoSchema),
57
- start: oc$1.input(v.object({ target: ResourceTarget })).output(RestartingProcessInfoSchema),
58
- stop: oc$1.input(v.object({ target: ResourceTarget })).output(RestartingProcessInfoSchema),
58
+ start: oc$1.input(v.object({ target: ResourceTarget$1 })).output(RestartingProcessInfoSchema),
59
+ stop: oc$1.input(v.object({ target: ResourceTarget$1 })).output(RestartingProcessInfoSchema),
59
60
  restart: oc$1.input(v.object({
60
- target: ResourceTarget,
61
+ target: ResourceTarget$1,
61
62
  force: v.optional(v.boolean())
62
63
  })).output(RestartingProcessInfoSchema),
63
64
  reload: oc$1.input(v.object({
64
- target: ResourceTarget,
65
+ target: ResourceTarget$1,
65
66
  definition: ProcessDefinition,
66
67
  restartImmediately: v.optional(v.boolean())
67
68
  })).output(RestartingProcessInfoSchema),
68
- remove: oc$1.input(v.object({ target: ResourceTarget })).output(v.object({ success: v.boolean() }))
69
+ remove: oc$1.input(v.object({ target: ResourceTarget$1 })).output(v.object({ success: v.boolean() }))
69
70
  };
70
- const tasks$1 = {
71
- get: oc$1.input(v.object({ target: ResourceTarget })).output(TaskEntryInfoSchema),
71
+ const tasks = {
72
+ get: oc$1.input(v.object({ target: ResourceTarget$1 })).output(TaskEntryInfoSchema),
72
73
  list: oc$1.output(v.array(TaskEntryInfoSchema)),
73
74
  add: oc$1.input(v.object({
74
75
  name: v.string(),
75
76
  definition: ProcessDefinition
76
77
  })).output(TaskEntryInfoSchema),
77
- remove: oc$1.input(v.object({ target: ResourceTarget })).output(TaskEntryInfoSchema)
78
+ remove: oc$1.input(v.object({ target: ResourceTarget$1 })).output(TaskEntryInfoSchema)
78
79
  };
79
- const crons$1 = {
80
- get: oc$1.input(v.object({ target: ResourceTarget })).output(CronProcessInfoSchema),
80
+ const crons = {
81
+ get: oc$1.input(v.object({ target: ResourceTarget$1 })).output(CronProcessInfoSchema),
81
82
  list: oc$1.output(v.array(CronProcessInfoSchema)),
82
- trigger: oc$1.input(v.object({ target: ResourceTarget })).output(CronProcessInfoSchema),
83
- start: oc$1.input(v.object({ target: ResourceTarget })).output(CronProcessInfoSchema),
84
- stop: oc$1.input(v.object({ target: ResourceTarget })).output(CronProcessInfoSchema)
83
+ trigger: oc$1.input(v.object({ target: ResourceTarget$1 })).output(CronProcessInfoSchema),
84
+ start: oc$1.input(v.object({ target: ResourceTarget$1 })).output(CronProcessInfoSchema),
85
+ stop: oc$1.input(v.object({ target: ResourceTarget$1 })).output(CronProcessInfoSchema)
85
86
  };
86
87
  const api = {
87
88
  manager,
88
89
  processes,
89
- tasks: tasks$1,
90
- crons: crons$1
90
+ tasks,
91
+ crons
91
92
  };
92
93
 
93
94
  //#endregion
94
95
  //#region src/api/server.ts
95
- const os = implement(api).$context();
96
+ const os$2 = implement(api).$context();
96
97
  function serializeProcess(proc) {
97
98
  return {
98
99
  name: proc.name,
@@ -109,7 +110,7 @@ function serializeCron(cron) {
109
110
  nextRun: cron.nextRun?.toISOString() ?? null
110
111
  };
111
112
  }
112
- const managerStatus = os.manager.status.handler(async ({ context }) => {
113
+ const managerStatus = os$2.manager.status.handler(async ({ context }) => {
113
114
  const manager = context.manager;
114
115
  const taskList = manager.getTaskList();
115
116
  return {
@@ -119,56 +120,56 @@ const managerStatus = os.manager.status.handler(async ({ context }) => {
119
120
  taskCount: taskList?.tasks.length ?? 0
120
121
  };
121
122
  });
122
- const getProcess = os.processes.get.handler(async ({ input, context }) => {
123
+ const getProcess = os$2.processes.get.handler(async ({ input, context }) => {
123
124
  const proc = context.manager.getProcessByTarget(input.target);
124
125
  if (!proc) throw new Error(`Process not found: ${input.target}`);
125
126
  return serializeProcess(proc);
126
127
  });
127
- const listProcesses = os.processes.list.handler(async ({ context }) => {
128
+ const listProcesses = os$2.processes.list.handler(async ({ context }) => {
128
129
  return Array.from(context.manager.getRestartingProcesses().values()).map(serializeProcess);
129
130
  });
130
- const addProcess = os.processes.add.handler(async ({ input, context }) => {
131
+ const addProcess = os$2.processes.add.handler(async ({ input, context }) => {
131
132
  return serializeProcess(await context.manager.addProcess(input.name, input.definition));
132
133
  });
133
- const startProcess = os.processes.start.handler(async ({ input, context }) => {
134
+ const startProcess = os$2.processes.start.handler(async ({ input, context }) => {
134
135
  return serializeProcess(await context.manager.startProcessByTarget(input.target));
135
136
  });
136
- const stopProcess = os.processes.stop.handler(async ({ input, context }) => {
137
+ const stopProcess = os$2.processes.stop.handler(async ({ input, context }) => {
137
138
  return serializeProcess(await context.manager.stopProcessByTarget(input.target));
138
139
  });
139
- const restartProcess = os.processes.restart.handler(async ({ input, context }) => {
140
+ const restartProcess = os$2.processes.restart.handler(async ({ input, context }) => {
140
141
  return serializeProcess(await context.manager.restartProcessByTarget(input.target, input.force));
141
142
  });
142
- const reloadProcess = os.processes.reload.handler(async ({ input, context }) => {
143
+ const reloadProcess = os$2.processes.reload.handler(async ({ input, context }) => {
143
144
  return serializeProcess(await context.manager.reloadProcessByTarget(input.target, input.definition, { restartImmediately: input.restartImmediately }));
144
145
  });
145
- const removeProcess = os.processes.remove.handler(async ({ input, context }) => {
146
+ const removeProcess = os$2.processes.remove.handler(async ({ input, context }) => {
146
147
  await context.manager.removeProcessByTarget(input.target);
147
148
  return { success: true };
148
149
  });
149
- const getCron = os.crons.get.handler(async ({ input, context }) => {
150
+ const getCron = os$2.crons.get.handler(async ({ input, context }) => {
150
151
  const cron = context.manager.getCronByTarget(input.target);
151
152
  if (!cron) throw new Error(`Cron not found: ${input.target}`);
152
153
  return serializeCron(cron);
153
154
  });
154
- const listCrons = os.crons.list.handler(async ({ context }) => {
155
+ const listCrons = os$2.crons.list.handler(async ({ context }) => {
155
156
  return Array.from(context.manager.getCronProcesses().values()).map(serializeCron);
156
157
  });
157
- const triggerCron = os.crons.trigger.handler(async ({ input, context }) => {
158
+ const triggerCron = os$2.crons.trigger.handler(async ({ input, context }) => {
158
159
  return serializeCron(await context.manager.triggerCronByTarget(input.target));
159
160
  });
160
- const startCron = os.crons.start.handler(async ({ input, context }) => {
161
+ const startCron = os$2.crons.start.handler(async ({ input, context }) => {
161
162
  return serializeCron(context.manager.startCronByTarget(input.target));
162
163
  });
163
- const stopCron = os.crons.stop.handler(async ({ input, context }) => {
164
+ const stopCron = os$2.crons.stop.handler(async ({ input, context }) => {
164
165
  return serializeCron(await context.manager.stopCronByTarget(input.target));
165
166
  });
166
- const getTask = os.tasks.get.handler(async ({ input, context }) => {
167
+ const getTask = os$2.tasks.get.handler(async ({ input, context }) => {
167
168
  const task = context.manager.getTaskByTarget(input.target);
168
169
  if (!task) throw new Error(`Task not found: ${input.target}`);
169
170
  return task;
170
171
  });
171
- const listTasks = os.tasks.list.handler(async ({ context }) => {
172
+ const listTasks = os$2.tasks.list.handler(async ({ context }) => {
172
173
  const taskList = context.manager.getTaskList();
173
174
  if (!taskList) return [];
174
175
  return taskList.tasks.map((t) => ({
@@ -177,13 +178,13 @@ const listTasks = os.tasks.list.handler(async ({ context }) => {
177
178
  processNames: t.processes.map((p) => p.name)
178
179
  }));
179
180
  });
180
- const addTask = os.tasks.add.handler(async ({ input, context }) => {
181
+ const addTask = os$2.tasks.add.handler(async ({ input, context }) => {
181
182
  return context.manager.addTask(input.name, input.definition);
182
183
  });
183
- const removeTask = os.tasks.remove.handler(async ({ input, context }) => {
184
+ const removeTask = os$2.tasks.remove.handler(async ({ input, context }) => {
184
185
  return context.manager.removeTaskByTarget(input.target);
185
186
  });
186
- const router = os.router({
187
+ const router = os$2.router({
187
188
  manager: { status: managerStatus },
188
189
  processes: {
189
190
  add: addProcess,
@@ -282,7 +283,7 @@ var Manager = class {
282
283
  cwd: cwd$1,
283
284
  globalEnvFile: config.envFile,
284
285
  customEnvFiles
285
- });
286
+ }, this.logger.child("env-manager"));
286
287
  this.envChangeUnsubscribe = this.envManager.onChange((event) => this.handleEnvChange(event));
287
288
  for (const signal of ["SIGINT", "SIGTERM"]) {
288
289
  const handler = () => this.handleSignal(signal);
@@ -682,6 +683,8 @@ var Manager = class {
682
683
  this.envChangeUnsubscribe = null;
683
684
  }
684
685
  this.envManager.close();
686
+ for (const [signal, handler] of this.signalHandlers) process.off(signal, handler);
687
+ this.signalHandlers.clear();
685
688
  if (this.taskList) await this.taskList.stop(timeout);
686
689
  const cronStopPromises = Array.from(this.cronProcesses.values()).map((p) => p.stop(timeout));
687
690
  const restartingStopPromises = Array.from(this.restartingProcesses.values()).map((p) => p.stop(timeout));
@@ -769,66 +772,116 @@ async function tImport(path) {
769
772
  }
770
773
  }
771
774
 
775
+ //#endregion
776
+ //#region package.json
777
+ var version = "0.0.0-dev.7";
778
+
772
779
  //#endregion
773
780
  //#region src/cli.ts
774
- const program = new Command();
775
- program.name("pidnap").description("Process manager with init system capabilities").version("0.0.0-dev.5");
776
- program.command("init").description("Initialize and run the process manager with config file").option("-c, --config [path]", "Path to config file", "pidnap.config.ts").action(async (options) => {
777
- process.title = "pidnap";
778
- const initLogger = logger({ name: "pidnap" });
779
- try {
780
- const configUrl = pathToFileURL(resolve(process.cwd(), options.config)).href;
781
- const configModule = await tImport(configUrl);
782
- const rawConfig = configModule.default.default || configModule.default || configModule.config || {};
783
- const config = v.parse(ManagerConfig, rawConfig);
784
- const host = config.http?.host ?? "127.0.0.1";
785
- const port = config.http?.port ?? 9876;
786
- const authToken = config.http?.authToken;
787
- const managerLogger = logger({
788
- name: "pidnap",
789
- logFile: resolve(config.logDir ?? resolve(process.cwd(), "logs"), "pidnap.log")
790
- });
791
- const manager = new Manager(config, managerLogger);
792
- const handler = new RPCHandler(router, { interceptors: [onError((error) => {
793
- managerLogger.error(error);
794
- })] });
795
- const server = createServer(async (req, res) => {
796
- if (authToken) {
797
- if (req.headers["authorization"]?.replace("Bearer ", "") !== authToken) {
798
- res.statusCode = 401;
799
- res.end("Unauthorized");
800
- return;
781
+ const os$1 = os.$context().$meta({});
782
+ const ResourceTarget = v.union([v.string(), v.number()]);
783
+ function printProcessTable(proc) {
784
+ const table = new Table({ head: [
785
+ "Name",
786
+ "State",
787
+ "Restarts"
788
+ ] });
789
+ table.push([
790
+ proc.name,
791
+ proc.state,
792
+ proc.restarts
793
+ ]);
794
+ console.log(table.toString());
795
+ }
796
+ function printTaskTable(task) {
797
+ const table = new Table({ head: [
798
+ "Id",
799
+ "State",
800
+ "Processes"
801
+ ] });
802
+ table.push([
803
+ task.id,
804
+ task.state,
805
+ task.processNames.join(", ")
806
+ ]);
807
+ console.log(table.toString());
808
+ }
809
+ function printCronTable(cron) {
810
+ const table = new Table({ head: [
811
+ "Name",
812
+ "State",
813
+ "Runs",
814
+ "Fails",
815
+ "Next Run"
816
+ ] });
817
+ table.push([
818
+ cron.name,
819
+ cron.state,
820
+ cron.runCount,
821
+ cron.failCount,
822
+ cron.nextRun ?? "-"
823
+ ]);
824
+ console.log(table.toString());
825
+ }
826
+ const cliRouter = os$1.router({
827
+ init: os.meta({
828
+ description: "Initialize and run the process manager with config file",
829
+ aliases: { options: { config: "c" } }
830
+ }).input(v.object({ config: v.optional(v.pipe(v.string(), v.description("Path to config file")), "pidnap.config.ts") })).handler(async ({ input }) => {
831
+ process.title = "pidnap";
832
+ const initLogger = logger({ name: "pidnap" });
833
+ try {
834
+ const configUrl = pathToFileURL(resolve(process.cwd(), input.config)).href;
835
+ const configModule = await tImport(configUrl);
836
+ const rawConfig = configModule.default.default || configModule.default || configModule.config || {};
837
+ const config = v.parse(ManagerConfig, rawConfig);
838
+ const host = config.http?.host ?? "127.0.0.1";
839
+ const port = config.http?.port ?? 9876;
840
+ const authToken = config.http?.authToken;
841
+ const managerLogger = logger({
842
+ name: "pidnap",
843
+ logFile: resolve(config.logDir ?? resolve(process.cwd(), "logs"), "pidnap.log")
844
+ });
845
+ const manager = new Manager(config, managerLogger);
846
+ const handler = new RPCHandler(router, { interceptors: [onError((error) => {
847
+ managerLogger.error(error);
848
+ })] });
849
+ const server = createServer(async (req, res) => {
850
+ if (authToken) {
851
+ if (req.headers["authorization"]?.replace("Bearer ", "") !== authToken) {
852
+ res.statusCode = 401;
853
+ res.end("Unauthorized");
854
+ return;
855
+ }
801
856
  }
802
- }
803
- const { matched } = await handler.handle(req, res, {
804
- prefix: "/rpc",
805
- context: { manager }
857
+ const { matched } = await handler.handle(req, res, {
858
+ prefix: "/rpc",
859
+ context: { manager }
860
+ });
861
+ if (matched) return;
862
+ res.statusCode = 404;
863
+ res.end("Not found\n");
806
864
  });
807
- if (matched) return;
808
- res.statusCode = 404;
809
- res.end("Not found\n");
810
- });
811
- server.listen(port, host, async () => {
812
- managerLogger.info(`pidnap RPC server running on http://${host}:${port}`);
813
- if (authToken) managerLogger.info("Auth token required for API access");
814
- try {
815
- await manager.start();
816
- } catch (err) {
817
- managerLogger.error("Failed to start manager:", err);
818
- server.close();
819
- process.exit(1);
820
- }
821
- });
822
- await manager.waitForShutdown();
823
- server.close();
824
- } catch (error) {
825
- initLogger.error("Failed to start pidnap:", error);
826
- process.exit(1);
827
- }
828
- });
829
- program.command("status").description("Show manager status").option("-u, --url <url>", "RPC server URL").action(async (options) => {
830
- try {
831
- const status = await createClient(options.url).manager.status();
865
+ server.listen(port, host, async () => {
866
+ managerLogger.info(`pidnap RPC server running on http://${host}:${port}`);
867
+ if (authToken) managerLogger.info("Auth token required for API access");
868
+ try {
869
+ await manager.start();
870
+ } catch (err) {
871
+ managerLogger.error("Failed to start manager:", err);
872
+ server.close();
873
+ process.exit(1);
874
+ }
875
+ });
876
+ await manager.waitForShutdown();
877
+ server.close();
878
+ } catch (error) {
879
+ initLogger.error("Failed to start pidnap:", error);
880
+ process.exit(1);
881
+ }
882
+ }),
883
+ status: os$1.meta({ description: "Show manager status" }).handler(async ({ context: { client } }) => {
884
+ const status = await client.manager.status();
832
885
  const table = new Table({ head: [
833
886
  "State",
834
887
  "Processes",
@@ -842,356 +895,194 @@ program.command("status").description("Show manager status").option("-u, --url <
842
895
  status.taskCount
843
896
  ]);
844
897
  console.log(table.toString());
845
- } catch (error) {
846
- console.error("Failed to fetch status:", error);
847
- process.exit(1);
848
- }
849
- });
850
- const processGroup = program.command("process").description("Manage restarting processes");
851
- processGroup.command("list").description("List restarting processes").option("-u, --url <url>", "RPC server URL").action(async (options) => {
852
- try {
853
- const processes = await createClient(options.url).processes.list();
854
- const table = new Table({ head: [
855
- "Name",
856
- "State",
857
- "Restarts"
858
- ] });
859
- for (const proc of processes) table.push([
860
- proc.name,
861
- proc.state,
862
- proc.restarts
863
- ]);
864
- console.log(table.toString());
865
- } catch (error) {
866
- console.error("Failed to list processes:", error);
867
- process.exit(1);
868
- }
869
- });
870
- processGroup.command("get").description("Get a restarting process by name or index").argument("<target>", "Process name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
871
- try {
872
- const proc = await createClient(options.url).processes.get({ target: parseTarget(target) });
873
- const table = new Table({ head: [
874
- "Name",
875
- "State",
876
- "Restarts"
877
- ] });
878
- table.push([
879
- proc.name,
880
- proc.state,
881
- proc.restarts
882
- ]);
883
- console.log(table.toString());
884
- } catch (error) {
885
- console.error("Failed to get process:", error);
886
- process.exit(1);
887
- }
888
- });
889
- processGroup.command("add").description("Add a restarting process").requiredOption("-n, --name <name>", "Process name").requiredOption("-d, --definition <json>", "Process definition JSON").option("-u, --url <url>", "RPC server URL").action(async (options) => {
890
- try {
891
- const client = createClient(options.url);
892
- const definition = parseDefinition(options.definition);
893
- const proc = await client.processes.add({
894
- name: options.name,
895
- definition
896
- });
897
- const table = new Table({ head: [
898
- "Name",
899
- "State",
900
- "Restarts"
901
- ] });
902
- table.push([
903
- proc.name,
904
- proc.state,
905
- proc.restarts
906
- ]);
907
- console.log(table.toString());
908
- } catch (error) {
909
- console.error("Failed to add process:", error);
910
- process.exit(1);
911
- }
912
- });
913
- processGroup.command("start").description("Start a restarting process").argument("<target>", "Process name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
914
- try {
915
- const proc = await createClient(options.url).processes.start({ target: parseTarget(target) });
916
- const table = new Table({ head: [
917
- "Name",
918
- "State",
919
- "Restarts"
920
- ] });
921
- table.push([
922
- proc.name,
923
- proc.state,
924
- proc.restarts
925
- ]);
926
- console.log(table.toString());
927
- } catch (error) {
928
- console.error("Failed to start process:", error);
929
- process.exit(1);
930
- }
931
- });
932
- processGroup.command("stop").description("Stop a restarting process").argument("<target>", "Process name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
933
- try {
934
- const proc = await createClient(options.url).processes.stop({ target: parseTarget(target) });
935
- const table = new Table({ head: [
936
- "Name",
937
- "State",
938
- "Restarts"
939
- ] });
940
- table.push([
941
- proc.name,
942
- proc.state,
943
- proc.restarts
944
- ]);
945
- console.log(table.toString());
946
- } catch (error) {
947
- console.error("Failed to stop process:", error);
948
- process.exit(1);
949
- }
950
- });
951
- processGroup.command("restart").description("Restart a restarting process").argument("<target>", "Process name or index").option("-f, --force", "Force restart").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
952
- try {
953
- const proc = await createClient(options.url).processes.restart({
954
- target: parseTarget(target),
955
- force: options.force
956
- });
957
- const table = new Table({ head: [
958
- "Name",
959
- "State",
960
- "Restarts"
961
- ] });
962
- table.push([
963
- proc.name,
964
- proc.state,
965
- proc.restarts
966
- ]);
967
- console.log(table.toString());
968
- } catch (error) {
969
- console.error("Failed to restart process:", error);
970
- process.exit(1);
971
- }
972
- });
973
- processGroup.command("remove").description("Remove a restarting process").argument("<target>", "Process name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
974
- try {
975
- await createClient(options.url).processes.remove({ target: parseTarget(target) });
976
- console.log("Process removed");
977
- } catch (error) {
978
- console.error("Failed to remove process:", error);
979
- process.exit(1);
980
- }
981
- });
982
- const crons = program.command("crons").description("Manage cron processes");
983
- crons.command("list").description("List cron processes").option("-u, --url <url>", "RPC server URL").action(async (options) => {
984
- try {
985
- const crons = await createClient(options.url).crons.list();
986
- const table = new Table({ head: [
987
- "Name",
988
- "State",
989
- "Runs",
990
- "Fails",
991
- "Next Run"
992
- ] });
993
- for (const cron of crons) table.push([
994
- cron.name,
995
- cron.state,
996
- cron.runCount,
997
- cron.failCount,
998
- cron.nextRun ?? "-"
999
- ]);
1000
- console.log(table.toString());
1001
- } catch (error) {
1002
- console.error("Failed to list crons:", error);
1003
- process.exit(1);
1004
- }
1005
- });
1006
- crons.command("get").description("Get a cron process by name or index").argument("<target>", "Cron name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
1007
- try {
1008
- const cron = await createClient(options.url).crons.get({ target: parseTarget(target) });
1009
- const table = new Table({ head: [
1010
- "Name",
1011
- "State",
1012
- "Runs",
1013
- "Fails",
1014
- "Next Run"
1015
- ] });
1016
- table.push([
1017
- cron.name,
1018
- cron.state,
1019
- cron.runCount,
1020
- cron.failCount,
1021
- cron.nextRun ?? "-"
1022
- ]);
1023
- console.log(table.toString());
1024
- } catch (error) {
1025
- console.error("Failed to get cron:", error);
1026
- process.exit(1);
1027
- }
1028
- });
1029
- crons.command("trigger").description("Trigger a cron process").argument("<target>", "Cron name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
1030
- try {
1031
- const cron = await createClient(options.url).crons.trigger({ target: parseTarget(target) });
1032
- const table = new Table({ head: [
1033
- "Name",
1034
- "State",
1035
- "Runs",
1036
- "Fails",
1037
- "Next Run"
1038
- ] });
1039
- table.push([
1040
- cron.name,
1041
- cron.state,
1042
- cron.runCount,
1043
- cron.failCount,
1044
- cron.nextRun ?? "-"
1045
- ]);
1046
- console.log(table.toString());
1047
- } catch (error) {
1048
- console.error("Failed to trigger cron:", error);
1049
- process.exit(1);
1050
- }
898
+ }),
899
+ process: os$1.router({
900
+ list: os$1.meta({ description: "List restarting processes" }).handler(async ({ context: { client } }) => {
901
+ const processes = await client.processes.list();
902
+ const table = new Table({ head: [
903
+ "Name",
904
+ "State",
905
+ "Restarts"
906
+ ] });
907
+ for (const proc of processes) table.push([
908
+ proc.name,
909
+ proc.state,
910
+ proc.restarts
911
+ ]);
912
+ console.log(table.toString());
913
+ }),
914
+ get: os$1.meta({
915
+ description: "Get a restarting process by name or index",
916
+ aliases: { options: { target: "t" } }
917
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Process name or index")) })).handler(async ({ input, context: { client } }) => {
918
+ printProcessTable(await client.processes.get({ target: input.target }));
919
+ }),
920
+ add: os$1.meta({
921
+ description: "Add a restarting process",
922
+ aliases: { options: {
923
+ name: "n",
924
+ definition: "d"
925
+ } }
926
+ }).input(v.object({
927
+ name: v.pipe(v.string(), v.description("Process name")),
928
+ definition: v.pipe(ProcessDefinition, v.description("Process definition JSON"))
929
+ })).handler(async ({ input, context: { client } }) => {
930
+ printProcessTable(await client.processes.add({
931
+ name: input.name,
932
+ definition: input.definition
933
+ }));
934
+ }),
935
+ start: os$1.meta({
936
+ description: "Start a restarting process",
937
+ aliases: { options: { target: "t" } }
938
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Process name or index")) })).handler(async ({ input, context: { client } }) => {
939
+ printProcessTable(await client.processes.start({ target: input.target }));
940
+ }),
941
+ stop: os$1.meta({
942
+ description: "Stop a restarting process",
943
+ aliases: { options: { target: "t" } }
944
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Process name or index")) })).handler(async ({ input, context: { client } }) => {
945
+ printProcessTable(await client.processes.stop({ target: input.target }));
946
+ }),
947
+ restart: os$1.meta({
948
+ description: "Restart a restarting process",
949
+ aliases: { options: {
950
+ target: "t",
951
+ force: "f"
952
+ } }
953
+ }).input(v.object({
954
+ target: v.pipe(ResourceTarget, v.description("Process name or index")),
955
+ force: v.optional(v.pipe(v.boolean(), v.description("Force restart")))
956
+ })).handler(async ({ input, context: { client } }) => {
957
+ printProcessTable(await client.processes.restart({
958
+ target: input.target,
959
+ force: input.force
960
+ }));
961
+ }),
962
+ reload: os$1.meta({
963
+ description: "Reload a restarting process definition",
964
+ aliases: { options: {
965
+ target: "t",
966
+ definition: "d",
967
+ restartImmediately: "r"
968
+ } }
969
+ }).input(v.object({
970
+ target: v.pipe(ResourceTarget, v.description("Process name or index")),
971
+ definition: v.pipe(ProcessDefinition, v.description("Process definition JSON")),
972
+ restartImmediately: v.optional(v.pipe(v.boolean(), v.description("Restart immediately after reload")))
973
+ })).handler(async ({ input, context: { client } }) => {
974
+ printProcessTable(await client.processes.reload({
975
+ target: input.target,
976
+ definition: input.definition,
977
+ restartImmediately: input.restartImmediately
978
+ }));
979
+ }),
980
+ remove: os$1.meta({
981
+ description: "Remove a restarting process",
982
+ aliases: { options: { target: "t" } }
983
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Process name or index")) })).handler(async ({ input, context: { client } }) => {
984
+ await client.processes.remove({ target: input.target });
985
+ console.log("Process removed");
986
+ })
987
+ }),
988
+ tasks: os$1.router({
989
+ list: os$1.meta({ description: "List tasks" }).handler(async ({ context: { client } }) => {
990
+ const tasks = await client.tasks.list();
991
+ const table = new Table({ head: [
992
+ "Id",
993
+ "State",
994
+ "Processes"
995
+ ] });
996
+ for (const task of tasks) table.push([
997
+ task.id,
998
+ task.state,
999
+ task.processNames.join(", ")
1000
+ ]);
1001
+ console.log(table.toString());
1002
+ }),
1003
+ get: os$1.meta({
1004
+ description: "Get a task by id or index",
1005
+ aliases: { options: { target: "t" } }
1006
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Task id or index")) })).handler(async ({ input, context: { client } }) => {
1007
+ printTaskTable(await client.tasks.get({ target: input.target }));
1008
+ }),
1009
+ add: os$1.meta({
1010
+ description: "Add a task",
1011
+ aliases: { options: {
1012
+ name: "n",
1013
+ definition: "d"
1014
+ } }
1015
+ }).input(v.object({
1016
+ name: v.pipe(v.string(), v.description("Task name")),
1017
+ definition: v.pipe(ProcessDefinition, v.description("Process definition JSON"))
1018
+ })).handler(async ({ input, context: { client } }) => {
1019
+ printTaskTable(await client.tasks.add({
1020
+ name: input.name,
1021
+ definition: input.definition
1022
+ }));
1023
+ }),
1024
+ remove: os$1.meta({
1025
+ description: "Remove a task by id or index",
1026
+ aliases: { options: { target: "t" } }
1027
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Task id or index")) })).handler(async ({ input, context: { client } }) => {
1028
+ printTaskTable(await client.tasks.remove({ target: input.target }));
1029
+ })
1030
+ }),
1031
+ crons: os$1.router({
1032
+ list: os$1.meta({ description: "List cron processes" }).handler(async ({ context: { client } }) => {
1033
+ const crons = await client.crons.list();
1034
+ const table = new Table({ head: [
1035
+ "Name",
1036
+ "State",
1037
+ "Runs",
1038
+ "Fails",
1039
+ "Next Run"
1040
+ ] });
1041
+ for (const cron of crons) table.push([
1042
+ cron.name,
1043
+ cron.state,
1044
+ cron.runCount,
1045
+ cron.failCount,
1046
+ cron.nextRun ?? "-"
1047
+ ]);
1048
+ console.log(table.toString());
1049
+ }),
1050
+ get: os$1.meta({
1051
+ description: "Get a cron process by name or index",
1052
+ aliases: { options: { target: "t" } }
1053
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Cron name or index")) })).handler(async ({ input, context: { client } }) => {
1054
+ printCronTable(await client.crons.get({ target: input.target }));
1055
+ }),
1056
+ trigger: os$1.meta({
1057
+ description: "Trigger a cron process",
1058
+ aliases: { options: { target: "t" } }
1059
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Cron name or index")) })).handler(async ({ input, context: { client } }) => {
1060
+ printCronTable(await client.crons.trigger({ target: input.target }));
1061
+ }),
1062
+ start: os$1.meta({
1063
+ description: "Start a cron process",
1064
+ aliases: { options: { target: "t" } }
1065
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Cron name or index")) })).handler(async ({ input, context: { client } }) => {
1066
+ printCronTable(await client.crons.start({ target: input.target }));
1067
+ }),
1068
+ stop: os$1.meta({
1069
+ description: "Stop a cron process",
1070
+ aliases: { options: { target: "t" } }
1071
+ }).input(v.object({ target: v.pipe(ResourceTarget, v.description("Cron name or index")) })).handler(async ({ input, context: { client } }) => {
1072
+ printCronTable(await client.crons.stop({ target: input.target }));
1073
+ })
1074
+ })
1051
1075
  });
1052
- crons.command("start").description("Start a cron process").argument("<target>", "Cron name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
1053
- try {
1054
- const cron = await createClient(options.url).crons.start({ target: parseTarget(target) });
1055
- const table = new Table({ head: [
1056
- "Name",
1057
- "State",
1058
- "Runs",
1059
- "Fails",
1060
- "Next Run"
1061
- ] });
1062
- table.push([
1063
- cron.name,
1064
- cron.state,
1065
- cron.runCount,
1066
- cron.failCount,
1067
- cron.nextRun ?? "-"
1068
- ]);
1069
- console.log(table.toString());
1070
- } catch (error) {
1071
- console.error("Failed to start cron:", error);
1072
- process.exit(1);
1073
- }
1074
- });
1075
- crons.command("stop").description("Stop a cron process").argument("<target>", "Cron name or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
1076
- try {
1077
- const cron = await createClient(options.url).crons.stop({ target: parseTarget(target) });
1078
- const table = new Table({ head: [
1079
- "Name",
1080
- "State",
1081
- "Runs",
1082
- "Fails",
1083
- "Next Run"
1084
- ] });
1085
- table.push([
1086
- cron.name,
1087
- cron.state,
1088
- cron.runCount,
1089
- cron.failCount,
1090
- cron.nextRun ?? "-"
1091
- ]);
1092
- console.log(table.toString());
1093
- } catch (error) {
1094
- console.error("Failed to stop cron:", error);
1095
- process.exit(1);
1096
- }
1097
- });
1098
- const tasks = program.command("tasks").description("Manage tasks");
1099
- tasks.command("list").description("List tasks").option("-u, --url <url>", "RPC server URL").action(async (options) => {
1100
- try {
1101
- const tasks = await createClient(options.url).tasks.list();
1102
- const table = new Table({ head: [
1103
- "Id",
1104
- "State",
1105
- "Processes"
1106
- ] });
1107
- for (const task of tasks) table.push([
1108
- task.id,
1109
- task.state,
1110
- task.processNames.join(", ")
1111
- ]);
1112
- console.log(table.toString());
1113
- } catch (error) {
1114
- console.error("Failed to list tasks:", error);
1115
- process.exit(1);
1116
- }
1117
- });
1118
- tasks.command("get").description("Get a task by id or index").argument("<target>", "Task id or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
1119
- try {
1120
- const task = await createClient(options.url).tasks.get({ target: parseTarget(target) });
1121
- const table = new Table({ head: [
1122
- "Id",
1123
- "State",
1124
- "Processes"
1125
- ] });
1126
- table.push([
1127
- task.id,
1128
- task.state,
1129
- task.processNames.join(", ")
1130
- ]);
1131
- console.log(table.toString());
1132
- } catch (error) {
1133
- console.error("Failed to get task:", error);
1134
- process.exit(1);
1135
- }
1136
- });
1137
- tasks.command("add").description("Add a task").requiredOption("-n, --name <name>", "Task name").requiredOption("-d, --definition <json>", "Process definition JSON").option("-u, --url <url>", "RPC server URL").action(async (options) => {
1138
- try {
1139
- const client = createClient(options.url);
1140
- const definition = parseDefinition(options.definition);
1141
- const task = await client.tasks.add({
1142
- name: options.name,
1143
- definition
1144
- });
1145
- const table = new Table({ head: [
1146
- "Id",
1147
- "State",
1148
- "Processes"
1149
- ] });
1150
- table.push([
1151
- task.id,
1152
- task.state,
1153
- task.processNames.join(", ")
1154
- ]);
1155
- console.log(table.toString());
1156
- } catch (error) {
1157
- console.error("Failed to add task:", error);
1158
- process.exit(1);
1159
- }
1160
- });
1161
- tasks.command("remove").description("Remove a task by id or index").argument("<target>", "Task id or index").option("-u, --url <url>", "RPC server URL").action(async (target, options) => {
1162
- try {
1163
- const task = await createClient(options.url).tasks.remove({ target: parseTarget(target) });
1164
- const table = new Table({ head: [
1165
- "Id",
1166
- "State",
1167
- "Processes"
1168
- ] });
1169
- table.push([
1170
- task.id,
1171
- task.state,
1172
- task.processNames.join(", ")
1173
- ]);
1174
- console.log(table.toString());
1175
- } catch (error) {
1176
- console.error("Failed to remove task:", error);
1177
- process.exit(1);
1178
- }
1179
- });
1180
- const TargetSchema = v.union([v.string(), v.number()]);
1181
- function parseTarget(value) {
1182
- const asNumber = Number(value);
1183
- return v.parse(TargetSchema, Number.isNaN(asNumber) ? value : asNumber);
1184
- }
1185
- function parseDefinition(raw) {
1186
- try {
1187
- const parsed = JSON.parse(raw);
1188
- return v.parse(ProcessDefinition, parsed);
1189
- } catch (error) {
1190
- console.error("Invalid --definition JSON. Expected a ProcessDefinition.");
1191
- throw error;
1192
- }
1193
- }
1194
- program.parse();
1076
+ const client = createClient();
1077
+ createCli({
1078
+ name: "pidnap",
1079
+ version,
1080
+ router: cliRouter,
1081
+ context: { client }
1082
+ }).run({ formatError(error) {
1083
+ if (error?.cause?.code === "ECONNREFUSED") return `Failed to connect to RPC server, are you sure the server is running? If the Server is running of different url, use PIDNAP_RPC_URL environment variable to set it.\n` + format(error);
1084
+ return format(error);
1085
+ } });
1195
1086
 
1196
1087
  //#endregion
1197
1088
  export { };