crnd 0.0.1 → 0.0.3

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.
Files changed (122) hide show
  1. package/bin/crnd +88 -0
  2. package/package.json +19 -43
  3. package/drizzle/0000_init.sql +0 -35
  4. package/drizzle/0001_add_runs.sql +0 -13
  5. package/drizzle/meta/_journal.json +0 -20
  6. package/src/cli/commands/createDeleteCommand.ts +0 -93
  7. package/src/cli/commands/createDoctorCommand.ts +0 -93
  8. package/src/cli/commands/createExportCommand.ts +0 -75
  9. package/src/cli/commands/createImportCommand.ts +0 -80
  10. package/src/cli/commands/createKillCommand.ts +0 -89
  11. package/src/cli/commands/createListCommand.ts +0 -67
  12. package/src/cli/commands/createLogsCommand.ts +0 -125
  13. package/src/cli/commands/createPauseCommand.ts +0 -78
  14. package/src/cli/commands/createResetCommand.ts +0 -78
  15. package/src/cli/commands/createResumeCommand.ts +0 -78
  16. package/src/cli/commands/createRootCommand.ts +0 -50
  17. package/src/cli/commands/createRunOnceCommand.ts +0 -77
  18. package/src/cli/commands/createRunsCommand.ts +0 -106
  19. package/src/cli/commands/createScheduleCommand.ts +0 -184
  20. package/src/cli/commands/createShowCommand.ts +0 -92
  21. package/src/cli/commands/createStatusCommand.ts +0 -145
  22. package/src/cli/commands/createStopCommand.ts +0 -89
  23. package/src/cli/commands/createUpdateCommand.ts +0 -13
  24. package/src/cli/commands/daemon/createDaemonCommand.ts +0 -24
  25. package/src/cli/commands/daemon/createDaemonInstallCommand.ts +0 -144
  26. package/src/cli/commands/daemon/createDaemonServeCommand.ts +0 -14
  27. package/src/cli/commands/daemon/createDaemonStartCommand.ts +0 -73
  28. package/src/cli/commands/daemon/createDaemonStatusCommand.ts +0 -5
  29. package/src/cli/commands/daemon/createDaemonStopCommand.ts +0 -59
  30. package/src/cli/commands/daemon/createDaemonUninstallCommand.ts +0 -99
  31. package/src/cli/commands/daemon/createLaunchdPlist.ts +0 -34
  32. package/src/cli/commands/daemon/createSystemdService.ts +0 -24
  33. package/src/cli/commands/daemon/escapeXml.ts +0 -8
  34. package/src/cli/commands/daemon/getDaemonServiceArgs.ts +0 -10
  35. package/src/cli/commands/daemon/quoteWindowsArg.ts +0 -4
  36. package/src/cli/commands/getCommandArgs.ts +0 -8
  37. package/src/cli/commands/parseEnvArgs.ts +0 -28
  38. package/src/cli/getDaemonSpawnArgs.ts +0 -9
  39. package/src/cli/main.ts +0 -8
  40. package/src/daemon/autostart/ensureAutostart.ts +0 -30
  41. package/src/daemon/autostart/getAutostartPath.ts +0 -29
  42. package/src/daemon/autostart/getDaemonInstallArgs.ts +0 -10
  43. package/src/daemon/createLogger.ts +0 -13
  44. package/src/daemon/createShutdownHandler.ts +0 -29
  45. package/src/daemon/jobs/createJobsFileSync.ts +0 -113
  46. package/src/daemon/jobs/deleteJobByName.ts +0 -18
  47. package/src/daemon/jobs/upsertJob.ts +0 -85
  48. package/src/daemon/main.ts +0 -64
  49. package/src/daemon/runner/createRunOutputFds.ts +0 -18
  50. package/src/daemon/runner/getRunStatus.ts +0 -14
  51. package/src/daemon/runner/recordSkippedRun.ts +0 -27
  52. package/src/daemon/runner/recoverRunningRuns.ts +0 -36
  53. package/src/daemon/runner/runJob.ts +0 -94
  54. package/src/daemon/scheduler/createScheduler.ts +0 -45
  55. package/src/daemon/scheduler/createSchedulerState.ts +0 -8
  56. package/src/daemon/scheduler/loadJobs.ts +0 -10
  57. package/src/daemon/scheduler/runJobWithTracking.ts +0 -48
  58. package/src/daemon/scheduler/scheduleJob.ts +0 -32
  59. package/src/daemon/scheduler/unscheduleJob.ts +0 -11
  60. package/src/daemon/scheduler/updateNextRunAt.ts +0 -14
  61. package/src/daemon/server/createApp.ts +0 -76
  62. package/src/daemon/server/createAuthMiddleware.ts +0 -16
  63. package/src/daemon/server/routes/registerExportRoute.ts +0 -21
  64. package/src/daemon/server/routes/registerHealthRoute.ts +0 -16
  65. package/src/daemon/server/routes/registerImportRoute.ts +0 -22
  66. package/src/daemon/server/routes/registerJobRunsRoute.ts +0 -46
  67. package/src/daemon/server/routes/registerJobsDeleteRoute.ts +0 -37
  68. package/src/daemon/server/routes/registerJobsGetRoute.ts +0 -29
  69. package/src/daemon/server/routes/registerJobsKillRoute.ts +0 -45
  70. package/src/daemon/server/routes/registerJobsListRoute.ts +0 -13
  71. package/src/daemon/server/routes/registerJobsPauseRoute.ts +0 -53
  72. package/src/daemon/server/routes/registerJobsResetRoute.ts +0 -54
  73. package/src/daemon/server/routes/registerJobsResumeRoute.ts +0 -53
  74. package/src/daemon/server/routes/registerJobsRunRoute.ts +0 -37
  75. package/src/daemon/server/routes/registerJobsStopRoute.ts +0 -45
  76. package/src/daemon/server/routes/registerJobsUpsertRoute.ts +0 -30
  77. package/src/daemon/server/routes/registerRunGetRoute.ts +0 -25
  78. package/src/daemon/server/routes/registerRunLogsRoute.ts +0 -32
  79. package/src/daemon/server/routes/registerShutdownRoute.ts +0 -9
  80. package/src/daemon/server/startServer.ts +0 -23
  81. package/src/db/getMigrationsDir.ts +0 -5
  82. package/src/db/migrateDatabase.ts +0 -21
  83. package/src/db/openDatabase.ts +0 -12
  84. package/src/db/schema/jobs.ts +0 -26
  85. package/src/db/schema/jobsSchemas.ts +0 -10
  86. package/src/db/schema/runs.ts +0 -23
  87. package/src/db/schema/runsSchemas.ts +0 -10
  88. package/src/db/schema.ts +0 -5
  89. package/src/shared/auth/createToken.ts +0 -5
  90. package/src/shared/events/appendEvent.ts +0 -16
  91. package/src/shared/jobs/createCommandSchema.ts +0 -5
  92. package/src/shared/jobs/createEnvSchema.ts +0 -5
  93. package/src/shared/jobs/createJobInputSchema.ts +0 -31
  94. package/src/shared/jobs/createTomlJobSchema.ts +0 -31
  95. package/src/shared/jobs/formatJobRow.ts +0 -14
  96. package/src/shared/jobs/isOverlapPolicy.ts +0 -5
  97. package/src/shared/jobs/parseCommand.ts +0 -6
  98. package/src/shared/jobs/parseEnv.ts +0 -10
  99. package/src/shared/jobs/parseJobsToml.ts +0 -36
  100. package/src/shared/jobs/readJobsToml.ts +0 -17
  101. package/src/shared/jobs/serializeCommand.ts +0 -6
  102. package/src/shared/jobs/serializeEnv.ts +0 -6
  103. package/src/shared/jobs/serializeJobsToml.ts +0 -45
  104. package/src/shared/jobs/writeJobsToml.ts +0 -12
  105. package/src/shared/paths/ensureDir.ts +0 -6
  106. package/src/shared/paths/getConfigDir.ts +0 -6
  107. package/src/shared/paths/getEventsPath.ts +0 -6
  108. package/src/shared/paths/getJobRunsDir.ts +0 -7
  109. package/src/shared/paths/getJobsTomlPath.ts +0 -6
  110. package/src/shared/paths/getPaths.ts +0 -16
  111. package/src/shared/paths/getRunOutputPaths.ts +0 -10
  112. package/src/shared/paths/getRunsDir.ts +0 -7
  113. package/src/shared/paths/getStateDir.ts +0 -8
  114. package/src/shared/rpc/createRpcClient.ts +0 -20
  115. package/src/shared/runs/formatRunRow.ts +0 -6
  116. package/src/shared/state/daemonStateSchema.ts +0 -13
  117. package/src/shared/state/getDaemonStatePath.ts +0 -6
  118. package/src/shared/state/readDaemonState.ts +0 -14
  119. package/src/shared/state/removeDaemonState.ts +0 -9
  120. package/src/shared/state/writeDaemonState.ts +0 -8
  121. package/src/shared/utils/isRecord.ts +0 -5
  122. package/src/shared/version.ts +0 -5
@@ -1,184 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import isOverlapPolicy from "../../shared/jobs/isOverlapPolicy";
3
- import createRpcClient from "../../shared/rpc/createRpcClient";
4
- import getCommandArgs from "./getCommandArgs";
5
- import parseEnvArgs from "./parseEnvArgs";
6
-
7
- export default function createScheduleCommand() {
8
- return defineCommand({
9
- meta: {
10
- name: "schedule",
11
- description: "Create or update a job",
12
- },
13
- args: {
14
- name: {
15
- type: "string",
16
- alias: "n",
17
- required: true,
18
- },
19
- description: {
20
- type: "string",
21
- alias: "d",
22
- },
23
- schedule: {
24
- type: "string",
25
- alias: "s",
26
- },
27
- at: {
28
- type: "string",
29
- alias: "a",
30
- },
31
- timezone: {
32
- type: "string",
33
- alias: "z",
34
- },
35
- timeout: {
36
- type: "string",
37
- alias: "t",
38
- },
39
- paused: {
40
- type: "boolean",
41
- alias: "p",
42
- },
43
- overlap: {
44
- type: "string",
45
- alias: "o",
46
- },
47
- cwd: {
48
- type: "string",
49
- alias: "c",
50
- },
51
- env: {
52
- type: "string",
53
- alias: "e",
54
- },
55
- json: {
56
- type: "boolean",
57
- alias: "j",
58
- },
59
- },
60
- async run({ args }) {
61
- const command = getCommandArgs(process.argv);
62
- if (command.length === 0) {
63
- const payload = { status: "missing_command" };
64
- if (!process.stdout.isTTY || args.json) {
65
- console.log(JSON.stringify(payload));
66
- } else {
67
- console.log("schedule: missing command after --");
68
- }
69
- process.exitCode = 2;
70
- return;
71
- }
72
-
73
- const client = createRpcClient();
74
- if (!client) {
75
- const payload = { status: "unreachable" };
76
- if (!process.stdout.isTTY || args.json) {
77
- console.log(JSON.stringify(payload));
78
- } else {
79
- console.log("daemon: unreachable");
80
- }
81
- process.exitCode = 3;
82
- return;
83
- }
84
-
85
- let env: Record<string, string> | undefined;
86
- try {
87
- env = parseEnvArgs(args.env);
88
- } catch {
89
- const payload = { status: "invalid_env" };
90
- if (!process.stdout.isTTY || args.json) {
91
- console.log(JSON.stringify(payload));
92
- } else {
93
- console.log("schedule: invalid env");
94
- }
95
- process.exitCode = 2;
96
- return;
97
- }
98
- const timeoutMs = args.timeout ? Number(args.timeout) : undefined;
99
- if (args.timeout && Number.isNaN(timeoutMs)) {
100
- const payload = { status: "invalid_timeout" };
101
- if (!process.stdout.isTTY || args.json) {
102
- console.log(JSON.stringify(payload));
103
- } else {
104
- console.log("schedule: invalid timeout");
105
- }
106
- process.exitCode = 2;
107
- return;
108
- }
109
-
110
- const hasSchedule = Boolean(args.schedule);
111
- const hasRunAt = Boolean(args.at);
112
- if (hasSchedule === hasRunAt) {
113
- const payload = { status: "invalid_schedule" };
114
- if (!process.stdout.isTTY || args.json) {
115
- console.log(JSON.stringify(payload));
116
- } else {
117
- console.log("schedule: provide schedule or at");
118
- }
119
- process.exitCode = 2;
120
- return;
121
- }
122
-
123
- if (args.overlap && !isOverlapPolicy(args.overlap)) {
124
- const payload = { status: "invalid_overlap" };
125
- if (!process.stdout.isTTY || args.json) {
126
- console.log(JSON.stringify(payload));
127
- } else {
128
- console.log("schedule: invalid overlap policy");
129
- }
130
- process.exitCode = 2;
131
- return;
132
- }
133
-
134
- const overlapPolicy =
135
- args.overlap && isOverlapPolicy(args.overlap)
136
- ? args.overlap
137
- : undefined;
138
-
139
- const payload = {
140
- name: args.name,
141
- description: args.description,
142
- command,
143
- schedule: args.schedule,
144
- runAt: args.at,
145
- timezone: args.timezone,
146
- timeoutMs,
147
- paused: args.paused,
148
- overlapPolicy,
149
- cwd: args.cwd,
150
- env,
151
- };
152
-
153
- try {
154
- const res = await client.jobs.$post({ json: payload });
155
- if (!res.ok) {
156
- const errorPayload = { status: "error", code: res.status };
157
- if (!process.stdout.isTTY || args.json) {
158
- console.log(JSON.stringify(errorPayload));
159
- } else {
160
- console.log(`schedule: error (${res.status})`);
161
- }
162
- process.exitCode = 1;
163
- return;
164
- }
165
-
166
- const data = await res.json();
167
- if (!process.stdout.isTTY || args.json) {
168
- console.log(JSON.stringify(data));
169
- return;
170
- }
171
-
172
- console.log(`job: ${data.name} (${data.id})`);
173
- } catch {
174
- const payload = { status: "unreachable" };
175
- if (!process.stdout.isTTY || args.json) {
176
- console.log(JSON.stringify(payload));
177
- } else {
178
- console.log("daemon: unreachable");
179
- }
180
- process.exitCode = 3;
181
- }
182
- },
183
- });
184
- }
@@ -1,92 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import createRpcClient from "../../shared/rpc/createRpcClient";
3
-
4
- export default function createShowCommand() {
5
- return defineCommand({
6
- meta: {
7
- name: "show",
8
- description: "Show a job",
9
- },
10
- args: {
11
- name: {
12
- type: "string",
13
- alias: "n",
14
- required: true,
15
- },
16
- json: {
17
- type: "boolean",
18
- alias: "j",
19
- },
20
- },
21
- async run({ args }) {
22
- const client = createRpcClient();
23
- if (!client) {
24
- const payload = { status: "unreachable" };
25
- if (!process.stdout.isTTY || args.json) {
26
- console.log(JSON.stringify(payload));
27
- } else {
28
- console.log("daemon: unreachable");
29
- }
30
- process.exitCode = 3;
31
- return;
32
- }
33
-
34
- try {
35
- const res = await client.jobs[":name"].$get({
36
- param: { name: args.name },
37
- });
38
- if (res.status === 404) {
39
- const payload = { status: "not_found" };
40
- if (!process.stdout.isTTY || args.json) {
41
- console.log(JSON.stringify(payload));
42
- } else {
43
- console.log("show: job not found");
44
- }
45
- process.exitCode = 1;
46
- return;
47
- }
48
-
49
- if (!res.ok) {
50
- const payload = { status: "error", code: res.status };
51
- if (!process.stdout.isTTY || args.json) {
52
- console.log(JSON.stringify(payload));
53
- } else {
54
- console.log(`show: error (${res.status})`);
55
- }
56
- process.exitCode = 1;
57
- return;
58
- }
59
-
60
- const data = await res.json();
61
- if (!process.stdout.isTTY || args.json) {
62
- console.log(JSON.stringify(data));
63
- return;
64
- }
65
-
66
- console.log(`name: ${data.name}`);
67
- console.log(`id: ${data.id}`);
68
- if (data.description) {
69
- console.log(`description: ${data.description}`);
70
- }
71
- console.log(`command: ${data.command.join(" ")}`);
72
- if (data.scheduleType === "cron") {
73
- console.log(`schedule: ${data.cron ?? ""}`);
74
- } else {
75
- console.log(`runAt: ${data.runAt ?? ""}`);
76
- }
77
- if (data.timezone) {
78
- console.log(`timezone: ${data.timezone}`);
79
- }
80
- console.log(`paused: ${data.paused}`);
81
- } catch {
82
- const payload = { status: "unreachable" };
83
- if (!process.stdout.isTTY || args.json) {
84
- console.log(JSON.stringify(payload));
85
- } else {
86
- console.log("daemon: unreachable");
87
- }
88
- process.exitCode = 3;
89
- }
90
- },
91
- });
92
- }
@@ -1,145 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import createRpcClient from "../../shared/rpc/createRpcClient";
3
-
4
- export default function createStatusCommand() {
5
- return defineCommand({
6
- meta: {
7
- name: "status",
8
- description: "Show daemon status",
9
- },
10
- args: {
11
- name: {
12
- type: "string",
13
- alias: "n",
14
- },
15
- json: {
16
- type: "boolean",
17
- alias: "j",
18
- },
19
- },
20
- async run({ args }) {
21
- if (args.name) {
22
- const client = createRpcClient();
23
- if (!client) {
24
- const payload = { status: "unreachable" };
25
- if (!process.stdout.isTTY || args.json) {
26
- console.log(JSON.stringify(payload));
27
- } else {
28
- console.log("daemon: unreachable");
29
- }
30
- process.exitCode = 3;
31
- return;
32
- }
33
-
34
- try {
35
- const jobRes = await client.jobs[":name"].$get({
36
- param: { name: args.name },
37
- });
38
- if (jobRes.status === 404) {
39
- const payload = { status: "not_found" };
40
- if (!process.stdout.isTTY || args.json) {
41
- console.log(JSON.stringify(payload));
42
- } else {
43
- console.log("status: job not found");
44
- }
45
- process.exitCode = 1;
46
- return;
47
- }
48
-
49
- if (!jobRes.ok) {
50
- const payload = { status: "error", code: jobRes.status };
51
- if (!process.stdout.isTTY || args.json) {
52
- console.log(JSON.stringify(payload));
53
- } else {
54
- console.log(`status: error (${jobRes.status})`);
55
- }
56
- process.exitCode = 1;
57
- return;
58
- }
59
-
60
- const job = await jobRes.json();
61
- const runsRes = await client.jobs[":name"].runs.$get({
62
- param: { name: args.name },
63
- query: { limit: "1" },
64
- });
65
-
66
- const latestRun = runsRes.ok ? (await runsRes.json())[0] : null;
67
- const payload = {
68
- job,
69
- latestRun,
70
- };
71
-
72
- if (!process.stdout.isTTY || args.json) {
73
- console.log(JSON.stringify(payload));
74
- return;
75
- }
76
-
77
- console.log(`job: ${job.name} (${job.id})`);
78
- console.log(`paused: ${job.paused}`);
79
- if (job.nextRunAt) {
80
- console.log(`nextRunAt: ${job.nextRunAt}`);
81
- }
82
- if (latestRun) {
83
- console.log(
84
- `lastRun: ${latestRun.status} ${latestRun.startedAt ?? ""}`.trim(),
85
- );
86
- }
87
- return;
88
- } catch {
89
- const payload = { status: "unreachable" };
90
- if (!process.stdout.isTTY || args.json) {
91
- console.log(JSON.stringify(payload));
92
- } else {
93
- console.log("daemon: unreachable");
94
- }
95
- process.exitCode = 3;
96
- return;
97
- }
98
- }
99
-
100
- const client = createRpcClient();
101
- if (!client) {
102
- const payload = { status: "stopped" };
103
- if (!process.stdout.isTTY || args.json) {
104
- console.log(JSON.stringify(payload));
105
- } else {
106
- console.log("daemon: stopped");
107
- }
108
- process.exitCode = 3;
109
- return;
110
- }
111
-
112
- try {
113
- const res = await client.health.$get();
114
- if (!res.ok) {
115
- const payload = { status: "unreachable", code: res.status };
116
- if (!process.stdout.isTTY || args.json) {
117
- console.log(JSON.stringify(payload));
118
- } else {
119
- console.log(`daemon: unreachable (${res.status})`);
120
- }
121
- process.exitCode = 3;
122
- return;
123
- }
124
-
125
- const data = await res.json();
126
- if (!process.stdout.isTTY || args.json) {
127
- console.log(JSON.stringify(data));
128
- return;
129
- }
130
-
131
- console.log(`daemon: running (pid ${data.pid})`);
132
- console.log(`started: ${data.startedAt}`);
133
- console.log(`version: ${data.version}`);
134
- } catch {
135
- const payload = { status: "unreachable" };
136
- if (!process.stdout.isTTY || args.json) {
137
- console.log(JSON.stringify(payload));
138
- } else {
139
- console.log("daemon: unreachable");
140
- }
141
- process.exitCode = 3;
142
- }
143
- },
144
- });
145
- }
@@ -1,89 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import createRpcClient from "../../shared/rpc/createRpcClient";
3
-
4
- export default function createStopCommand() {
5
- return defineCommand({
6
- meta: {
7
- name: "stop",
8
- description: "Stop a running job",
9
- },
10
- args: {
11
- name: {
12
- type: "string",
13
- alias: "n",
14
- required: true,
15
- },
16
- json: {
17
- type: "boolean",
18
- alias: "j",
19
- },
20
- },
21
- async run({ args }) {
22
- const client = createRpcClient();
23
- if (!client) {
24
- const payload = { status: "unreachable" };
25
- if (!process.stdout.isTTY || args.json) {
26
- console.log(JSON.stringify(payload));
27
- } else {
28
- console.log("daemon: unreachable");
29
- }
30
- process.exitCode = 3;
31
- return;
32
- }
33
-
34
- try {
35
- const res = await client.jobs[":name"].stop.$post({
36
- param: { name: args.name },
37
- });
38
- if (res.status === 404) {
39
- const payload = { status: "not_found" };
40
- if (!process.stdout.isTTY || args.json) {
41
- console.log(JSON.stringify(payload));
42
- } else {
43
- console.log("stop: job not found");
44
- }
45
- process.exitCode = 1;
46
- return;
47
- }
48
-
49
- if (res.status === 409) {
50
- const payload = { status: "not_running" };
51
- if (!process.stdout.isTTY || args.json) {
52
- console.log(JSON.stringify(payload));
53
- } else {
54
- console.log("stop: no running job");
55
- }
56
- process.exitCode = 1;
57
- return;
58
- }
59
-
60
- if (!res.ok) {
61
- const payload = { status: "error", code: res.status };
62
- if (!process.stdout.isTTY || args.json) {
63
- console.log(JSON.stringify(payload));
64
- } else {
65
- console.log(`stop: error (${res.status})`);
66
- }
67
- process.exitCode = 1;
68
- return;
69
- }
70
-
71
- const data = await res.json();
72
- if (!process.stdout.isTTY || args.json) {
73
- console.log(JSON.stringify(data));
74
- return;
75
- }
76
-
77
- console.log(`stop: requested (${data.runId})`);
78
- } catch {
79
- const payload = { status: "unreachable" };
80
- if (!process.stdout.isTTY || args.json) {
81
- console.log(JSON.stringify(payload));
82
- } else {
83
- console.log("daemon: unreachable");
84
- }
85
- process.exitCode = 3;
86
- }
87
- },
88
- });
89
- }
@@ -1,13 +0,0 @@
1
- import createScheduleCommand from "./createScheduleCommand";
2
-
3
- export default function createUpdateCommand() {
4
- const base = createScheduleCommand();
5
- return {
6
- ...base,
7
- meta: {
8
- ...base.meta,
9
- name: "update",
10
- description: "Update a job",
11
- },
12
- };
13
- }
@@ -1,24 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import createDaemonInstallCommand from "./createDaemonInstallCommand";
3
- import createDaemonServeCommand from "./createDaemonServeCommand";
4
- import createDaemonStartCommand from "./createDaemonStartCommand";
5
- import createDaemonStatusCommand from "./createDaemonStatusCommand";
6
- import createDaemonStopCommand from "./createDaemonStopCommand";
7
- import createDaemonUninstallCommand from "./createDaemonUninstallCommand";
8
-
9
- export default function createDaemonCommand() {
10
- return defineCommand({
11
- meta: {
12
- name: "daemon",
13
- description: "Manage the crnd daemon",
14
- },
15
- subCommands: {
16
- start: createDaemonStartCommand(),
17
- stop: createDaemonStopCommand(),
18
- status: createDaemonStatusCommand(),
19
- serve: createDaemonServeCommand(),
20
- install: createDaemonInstallCommand(),
21
- uninstall: createDaemonUninstallCommand(),
22
- },
23
- });
24
- }
@@ -1,144 +0,0 @@
1
- import { mkdirSync, writeFileSync } from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { defineCommand } from "citty";
5
- import getStateDir from "../../../shared/paths/getStateDir";
6
- import createLaunchdPlist from "./createLaunchdPlist";
7
- import createSystemdService from "./createSystemdService";
8
- import getDaemonServiceArgs from "./getDaemonServiceArgs";
9
- import quoteWindowsArg from "./quoteWindowsArg";
10
-
11
- export default function createDaemonInstallCommand() {
12
- return defineCommand({
13
- meta: {
14
- name: "install",
15
- description: "Install auto-start service",
16
- },
17
- args: {
18
- json: {
19
- type: "boolean",
20
- alias: "j",
21
- },
22
- },
23
- run({ args }) {
24
- if (process.env.CRND_AUTOSTART_DRY_RUN === "1") {
25
- const payload = { ok: true, dryRun: true };
26
- if (!process.stdout.isTTY || args.json) {
27
- console.log(JSON.stringify(payload));
28
- } else {
29
- console.log("daemon: install dry run");
30
- }
31
- return;
32
- }
33
-
34
- const stdoutPath = path.join(getStateDir(), "daemon.out");
35
- const stderrPath = path.join(getStateDir(), "daemon.err");
36
- const daemonArgs = getDaemonServiceArgs();
37
- const platform = process.platform;
38
-
39
- if (platform === "darwin") {
40
- const plistPath = path.join(
41
- os.homedir(),
42
- "Library",
43
- "LaunchAgents",
44
- "com.crnd.daemon.plist",
45
- );
46
- mkdirSync(path.dirname(plistPath), { recursive: true });
47
- writeFileSync(
48
- plistPath,
49
- createLaunchdPlist(daemonArgs, stdoutPath, stderrPath),
50
- "utf-8",
51
- );
52
- Bun.spawnSync(["launchctl", "unload", plistPath]);
53
- const result = Bun.spawnSync(["launchctl", "load", plistPath]);
54
-
55
- const ok = result.success;
56
- if (!process.stdout.isTTY || args.json) {
57
- console.log(JSON.stringify({ ok, path: plistPath }));
58
- } else {
59
- console.log(
60
- ok ? `daemon: installed (${plistPath})` : "daemon: install failed",
61
- );
62
- }
63
- if (!ok) {
64
- process.exitCode = 1;
65
- }
66
- return;
67
- }
68
-
69
- if (platform === "linux") {
70
- const servicePath = path.join(
71
- os.homedir(),
72
- ".config",
73
- "systemd",
74
- "user",
75
- "crnd.service",
76
- );
77
- mkdirSync(path.dirname(servicePath), { recursive: true });
78
- writeFileSync(
79
- servicePath,
80
- createSystemdService(daemonArgs, stdoutPath, stderrPath),
81
- "utf-8",
82
- );
83
- Bun.spawnSync(["systemctl", "--user", "daemon-reload"]);
84
- const result = Bun.spawnSync([
85
- "systemctl",
86
- "--user",
87
- "enable",
88
- "--now",
89
- "crnd.service",
90
- ]);
91
- const ok = result.success;
92
- if (!process.stdout.isTTY || args.json) {
93
- console.log(JSON.stringify({ ok, path: servicePath }));
94
- } else {
95
- console.log(
96
- ok
97
- ? `daemon: installed (${servicePath})`
98
- : "daemon: install failed",
99
- );
100
- }
101
- if (!ok) {
102
- process.exitCode = 1;
103
- }
104
- return;
105
- }
106
-
107
- if (platform === "win32") {
108
- const taskName = "crnd";
109
- const taskCommand = daemonArgs.map(quoteWindowsArg).join(" ");
110
- const result = Bun.spawnSync([
111
- "schtasks",
112
- "/Create",
113
- "/F",
114
- "/SC",
115
- "ONLOGON",
116
- "/TN",
117
- taskName,
118
- "/TR",
119
- taskCommand,
120
- ]);
121
- const ok = result.success;
122
- if (!process.stdout.isTTY || args.json) {
123
- console.log(JSON.stringify({ ok, task: taskName }));
124
- } else {
125
- console.log(
126
- ok ? `daemon: installed (${taskName})` : "daemon: install failed",
127
- );
128
- }
129
- if (!ok) {
130
- process.exitCode = 1;
131
- }
132
- return;
133
- }
134
-
135
- const payload = { ok: false, error: "unsupported_platform" };
136
- if (!process.stdout.isTTY || args.json) {
137
- console.log(JSON.stringify(payload));
138
- } else {
139
- console.log("daemon: unsupported platform");
140
- }
141
- process.exitCode = 1;
142
- },
143
- });
144
- }
@@ -1,14 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import startDaemon from "../../../daemon/main";
3
-
4
- export default function createDaemonServeCommand() {
5
- return defineCommand({
6
- meta: {
7
- name: "serve",
8
- description: "Run the daemon in the foreground",
9
- },
10
- run() {
11
- startDaemon();
12
- },
13
- });
14
- }