crontick 0.1.0
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/LICENSE +21 -0
- package/README.md +56 -0
- package/dist/chunk-35FFLWP3.js +79 -0
- package/dist/chunk-35FFLWP3.js.map +1 -0
- package/dist/chunk-FMGZ3SSS.js +57 -0
- package/dist/chunk-FMGZ3SSS.js.map +1 -0
- package/dist/chunk-LPAFZNXK.js +214 -0
- package/dist/chunk-LPAFZNXK.js.map +1 -0
- package/dist/chunk-YMAT5MON.js +22 -0
- package/dist/chunk-YMAT5MON.js.map +1 -0
- package/dist/cli/index.cjs +879 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +2 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +554 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/daemon/index.cjs +1655 -0
- package/dist/daemon/index.cjs.map +1 -0
- package/dist/daemon/index.d.cts +2 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +1306 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/dashboard/.gitkeep +0 -0
- package/dist/dashboard/dashboard.css +192 -0
- package/dist/dashboard/dashboard.js +316 -0
- package/dist/dashboard/index.html +108 -0
- package/dist/index.cjs +180 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/job-JQGLDEJV.js +26 -0
- package/dist/job-JQGLDEJV.js.map +1 -0
- package/dist/mcp/index.cjs +1000 -0
- package/dist/mcp/index.cjs.map +1 -0
- package/dist/mcp/index.d.cts +13 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +876 -0
- package/dist/mcp/index.js.map +1 -0
- package/package.json +81 -0
- package/plugin/.gitkeep +0 -0
- package/plugin/README.md +50 -0
- package/plugin/install.mjs +155 -0
- package/plugin/plugin.json +11 -0
- package/plugin/uninstall.mjs +68 -0
- package/src/skill/SKILL.md +227 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 crontick contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# crontick
|
|
2
|
+
|
|
3
|
+
[](https://github.com/tejitpabari99/crontick/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/tejitpabari99/crontick/actions/workflows/release.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/crontick)
|
|
6
|
+
|
|
7
|
+
**crontick** is a standalone cron daemon, CLI, dashboard, and stdio MCP server for running local
|
|
8
|
+
scheduled jobs on Windows, macOS, and Linux.
|
|
9
|
+
|
|
10
|
+
## What ships
|
|
11
|
+
|
|
12
|
+
- `crontick` — CLI for jobs, daemon control, logs, doctor, dashboard, and MCP launch
|
|
13
|
+
- `crontick-daemon` — loopback-only local scheduler + runner + HTTP API
|
|
14
|
+
- `crontick-mcp` — stdio MCP server with job, run, schedule, stats, and doctor tools
|
|
15
|
+
- `plugin/install.mjs` — Copilot plugin installer that installs the package, skill, and optional
|
|
16
|
+
Windows autostart
|
|
17
|
+
|
|
18
|
+
## v1 scope
|
|
19
|
+
|
|
20
|
+
- `action.kind: "script"` and `action.kind: "exec"`
|
|
21
|
+
- cron, interval, and one-shot schedules
|
|
22
|
+
- stdio MCP transport only
|
|
23
|
+
- Windows autostart via `HKCU\Run`; macOS/Linux provide manual guidance for now
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install -g crontick
|
|
29
|
+
crontick daemon start
|
|
30
|
+
crontick new hello --cron "*/5 * * * *" --exec "echo hello"
|
|
31
|
+
crontick list
|
|
32
|
+
crontick mcp --help
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Security model
|
|
36
|
+
|
|
37
|
+
The daemon API binds only to `127.0.0.1`. There are no bearer tokens or remote listeners; the
|
|
38
|
+
trust boundary is the local user session. `exec` actions always use `shell=false`, and run logs are
|
|
39
|
+
redacted for common secret patterns before they are returned by the API or MCP server.
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
- [Getting started](docs/getting-started.md)
|
|
44
|
+
- [CLI reference](docs/cli.md)
|
|
45
|
+
- [MCP usage](docs/mcp.md)
|
|
46
|
+
- [Schedules](docs/schedules.md)
|
|
47
|
+
- [Actions](docs/actions.md)
|
|
48
|
+
- [Security](docs/security.md)
|
|
49
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
50
|
+
- [Architecture](docs/architecture.md)
|
|
51
|
+
- [Contributing](docs/contributing.md)
|
|
52
|
+
- [Releasing](RELEASING.md)
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT © crontick contributors
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/schemas/job.ts
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
var CronScheduleSchema = z.object({
|
|
6
|
+
kind: z.literal("cron"),
|
|
7
|
+
cron: z.string().min(1),
|
|
8
|
+
tz: z.string().optional()
|
|
9
|
+
});
|
|
10
|
+
var IntervalScheduleSchema = z.object({
|
|
11
|
+
kind: z.literal("interval"),
|
|
12
|
+
everySec: z.number().positive(),
|
|
13
|
+
startAt: z.string().optional()
|
|
14
|
+
// ISO-8601
|
|
15
|
+
});
|
|
16
|
+
var OneShotScheduleSchema = z.object({
|
|
17
|
+
kind: z.literal("one-shot"),
|
|
18
|
+
runAt: z.string().min(1)
|
|
19
|
+
// ISO-8601
|
|
20
|
+
});
|
|
21
|
+
var ScheduleSchema = z.discriminatedUnion("kind", [
|
|
22
|
+
CronScheduleSchema,
|
|
23
|
+
IntervalScheduleSchema,
|
|
24
|
+
OneShotScheduleSchema
|
|
25
|
+
]);
|
|
26
|
+
var ScriptActionSchema = z.object({
|
|
27
|
+
kind: z.literal("script"),
|
|
28
|
+
script: z.string().min(1),
|
|
29
|
+
shell: z.enum(["auto", "bash", "pwsh", "cmd"]).default("auto"),
|
|
30
|
+
cwd: z.string().optional(),
|
|
31
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
32
|
+
envFile: z.string().optional(),
|
|
33
|
+
timeoutSec: z.number().positive().optional()
|
|
34
|
+
});
|
|
35
|
+
var ExecActionSchema = z.object({
|
|
36
|
+
kind: z.literal("exec"),
|
|
37
|
+
command: z.string().min(1),
|
|
38
|
+
args: z.array(z.string()).default([]),
|
|
39
|
+
cwd: z.string().optional(),
|
|
40
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
41
|
+
envFile: z.string().optional(),
|
|
42
|
+
timeoutSec: z.number().positive().optional()
|
|
43
|
+
// shell is intentionally absent: exec always uses shell=false to prevent injection
|
|
44
|
+
});
|
|
45
|
+
var ActionSchema = z.discriminatedUnion("kind", [ScriptActionSchema, ExecActionSchema]);
|
|
46
|
+
var RetrySchema = z.object({
|
|
47
|
+
max: z.number().int().min(0).default(0),
|
|
48
|
+
backoffSec: z.number().positive().default(30)
|
|
49
|
+
});
|
|
50
|
+
var BudgetsSchema = z.object({
|
|
51
|
+
maxRunsPerDay: z.number().int().positive().nullable().default(null),
|
|
52
|
+
maxTokensPerRun: z.number().int().positive().nullable().default(null)
|
|
53
|
+
});
|
|
54
|
+
var kebabCase = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
55
|
+
var JobSchema = z.object({
|
|
56
|
+
id: z.string().regex(kebabCase, 'Job ID must be kebab-case (e.g. "my-job")'),
|
|
57
|
+
description: z.string().optional(),
|
|
58
|
+
enabled: z.boolean().default(true),
|
|
59
|
+
schedule: ScheduleSchema,
|
|
60
|
+
action: ActionSchema,
|
|
61
|
+
catchup: z.enum(["run-once", "run-all", "skip"]).default("skip"),
|
|
62
|
+
overlap: z.enum(["skip", "queue", "cancel-previous"]).default("skip"),
|
|
63
|
+
retry: RetrySchema.default({ max: 0, backoffSec: 30 }),
|
|
64
|
+
budgets: BudgetsSchema.default({ maxRunsPerDay: null, maxTokensPerRun: null })
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
CronScheduleSchema,
|
|
69
|
+
IntervalScheduleSchema,
|
|
70
|
+
OneShotScheduleSchema,
|
|
71
|
+
ScheduleSchema,
|
|
72
|
+
ScriptActionSchema,
|
|
73
|
+
ExecActionSchema,
|
|
74
|
+
ActionSchema,
|
|
75
|
+
RetrySchema,
|
|
76
|
+
BudgetsSchema,
|
|
77
|
+
JobSchema
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chunk-35FFLWP3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schemas/job.ts"],"sourcesContent":["import { z } from 'zod';\n\n// ── Schedule ──────────────────────────────────────────────────────────────────\n\nexport const CronScheduleSchema = z.object({\n kind: z.literal('cron'),\n cron: z.string().min(1),\n tz: z.string().optional(),\n});\n\nexport const IntervalScheduleSchema = z.object({\n kind: z.literal('interval'),\n everySec: z.number().positive(),\n startAt: z.string().optional(), // ISO-8601\n});\n\nexport const OneShotScheduleSchema = z.object({\n kind: z.literal('one-shot'),\n runAt: z.string().min(1), // ISO-8601\n});\n\nexport const ScheduleSchema = z.discriminatedUnion('kind', [\n CronScheduleSchema,\n IntervalScheduleSchema,\n OneShotScheduleSchema,\n]);\n\n// ── Action ────────────────────────────────────────────────────────────────────\n\nexport const ScriptActionSchema = z.object({\n kind: z.literal('script'),\n script: z.string().min(1),\n shell: z.enum(['auto', 'bash', 'pwsh', 'cmd']).default('auto'),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n envFile: z.string().optional(),\n timeoutSec: z.number().positive().optional(),\n});\n\nexport const ExecActionSchema = z.object({\n kind: z.literal('exec'),\n command: z.string().min(1),\n args: z.array(z.string()).default([]),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n envFile: z.string().optional(),\n timeoutSec: z.number().positive().optional(),\n // shell is intentionally absent: exec always uses shell=false to prevent injection\n});\n\nexport const ActionSchema = z.discriminatedUnion('kind', [ScriptActionSchema, ExecActionSchema]);\n\n// ── Supporting types ──────────────────────────────────────────────────────────\n\nexport const RetrySchema = z.object({\n max: z.number().int().min(0).default(0),\n backoffSec: z.number().positive().default(30),\n});\n\nexport const BudgetsSchema = z.object({\n maxRunsPerDay: z.number().int().positive().nullable().default(null),\n maxTokensPerRun: z.number().int().positive().nullable().default(null),\n});\n\n// ── Job ───────────────────────────────────────────────────────────────────────\n\nconst kebabCase = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport const JobSchema = z.object({\n id: z.string().regex(kebabCase, 'Job ID must be kebab-case (e.g. \"my-job\")'),\n description: z.string().optional(),\n enabled: z.boolean().default(true),\n schedule: ScheduleSchema,\n action: ActionSchema,\n catchup: z.enum(['run-once', 'run-all', 'skip']).default('skip'),\n overlap: z.enum(['skip', 'queue', 'cancel-previous']).default('skip'),\n retry: RetrySchema.default({ max: 0, backoffSec: 30 }),\n budgets: BudgetsSchema.default({ maxRunsPerDay: null, maxTokensPerRun: null }),\n});\n\nexport type Job = z.infer<typeof JobSchema>;\nexport type JobInput = z.input<typeof JobSchema>;\nexport type Schedule = z.infer<typeof ScheduleSchema>;\nexport type Action = z.infer<typeof ActionSchema>;\n"],"mappings":";;;AAAA,SAAS,SAAS;AAIX,IAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,IAAI,EAAE,OAAO,EAAE,SAAS;AAC1B,CAAC;AAEM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA;AAC/B,CAAC;AAEM,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AACzB,CAAC;AAEM,IAAM,iBAAiB,EAAE,mBAAmB,QAAQ;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAIM,IAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,MAAM,EAAE,QAAQ,QAAQ;AAAA,EACxB,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,OAAO,EAAE,KAAK,CAAC,QAAQ,QAAQ,QAAQ,KAAK,CAAC,EAAE,QAAQ,MAAM;AAAA,EAC7D,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC/C,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC7C,CAAC;AAEM,IAAM,mBAAmB,EAAE,OAAO;AAAA,EACvC,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpC,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC/C,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA;AAE7C,CAAC;AAEM,IAAM,eAAe,EAAE,mBAAmB,QAAQ,CAAC,oBAAoB,gBAAgB,CAAC;AAIxF,IAAM,cAAc,EAAE,OAAO;AAAA,EAClC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACtC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE;AAC9C,CAAC;AAEM,IAAM,gBAAgB,EAAE,OAAO;AAAA,EACpC,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,IAAI;AAAA,EAClE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,IAAI;AACtE,CAAC;AAID,IAAM,YAAY;AAEX,IAAM,YAAY,EAAE,OAAO;AAAA,EAChC,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,2CAA2C;AAAA,EAC3E,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,SAAS,EAAE,KAAK,CAAC,YAAY,WAAW,MAAM,CAAC,EAAE,QAAQ,MAAM;AAAA,EAC/D,SAAS,EAAE,KAAK,CAAC,QAAQ,SAAS,iBAAiB,CAAC,EAAE,QAAQ,MAAM;AAAA,EACpE,OAAO,YAAY,QAAQ,EAAE,KAAK,GAAG,YAAY,GAAG,CAAC;AAAA,EACrD,SAAS,cAAc,QAAQ,EAAE,eAAe,MAAM,iBAAiB,KAAK,CAAC;AAC/E,CAAC;","names":[]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/version.ts
|
|
4
|
+
var VERSION = "0.1.0";
|
|
5
|
+
|
|
6
|
+
// src/paths.ts
|
|
7
|
+
import envPaths from "env-paths";
|
|
8
|
+
import { mkdirSync } from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
function root() {
|
|
11
|
+
const override = process.env["CRONTICK_HOME"];
|
|
12
|
+
if (override) return override;
|
|
13
|
+
return envPaths("crontick", { suffix: "" }).data;
|
|
14
|
+
}
|
|
15
|
+
function dataDir() {
|
|
16
|
+
return root();
|
|
17
|
+
}
|
|
18
|
+
function jobsDir() {
|
|
19
|
+
return join(root(), "jobs");
|
|
20
|
+
}
|
|
21
|
+
function runsDbPath() {
|
|
22
|
+
return join(root(), "runs.db");
|
|
23
|
+
}
|
|
24
|
+
function logsDir() {
|
|
25
|
+
return join(root(), "logs");
|
|
26
|
+
}
|
|
27
|
+
function configPath() {
|
|
28
|
+
return join(root(), "config.json");
|
|
29
|
+
}
|
|
30
|
+
function pidFilePath() {
|
|
31
|
+
return join(root(), "daemon.pid");
|
|
32
|
+
}
|
|
33
|
+
function portFilePath() {
|
|
34
|
+
return join(root(), "daemon.port");
|
|
35
|
+
}
|
|
36
|
+
function autostartDir() {
|
|
37
|
+
return join(root(), "autostart");
|
|
38
|
+
}
|
|
39
|
+
function ensureDirs() {
|
|
40
|
+
for (const dir of [dataDir(), jobsDir(), logsDir()]) {
|
|
41
|
+
mkdirSync(dir, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
VERSION,
|
|
47
|
+
dataDir,
|
|
48
|
+
jobsDir,
|
|
49
|
+
runsDbPath,
|
|
50
|
+
logsDir,
|
|
51
|
+
configPath,
|
|
52
|
+
pidFilePath,
|
|
53
|
+
portFilePath,
|
|
54
|
+
autostartDir,
|
|
55
|
+
ensureDirs
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=chunk-FMGZ3SSS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/paths.ts"],"sourcesContent":["// Version constant injected at build time by tsup/esbuild (define: __CRONTICK_VERSION__)\n// and at test time by vitest (define in vitest.config.ts).\ndeclare const __CRONTICK_VERSION__: string;\nexport const VERSION: string = __CRONTICK_VERSION__;\n","import envPaths from 'env-paths';\nimport { mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nfunction root(): string {\n const override = process.env['CRONTICK_HOME'];\n if (override) return override;\n // env-paths v3: data dir on windows = %LOCALAPPDATA%\\crontick\n return envPaths('crontick', { suffix: '' }).data;\n}\n\nexport function dataDir(): string {\n return root();\n}\n\nexport function jobsDir(): string {\n return join(root(), 'jobs');\n}\n\nexport function runsDbPath(): string {\n return join(root(), 'runs.db');\n}\n\nexport function logsDir(): string {\n return join(root(), 'logs');\n}\n\nexport function configPath(): string {\n return join(root(), 'config.json');\n}\n\nexport function pidFilePath(): string {\n return join(root(), 'daemon.pid');\n}\n\nexport function portFilePath(): string {\n return join(root(), 'daemon.port');\n}\n\nexport function autostartDir(): string {\n return join(root(), 'autostart');\n}\n\nexport function ensureDirs(): void {\n for (const dir of [dataDir(), jobsDir(), logsDir()]) {\n mkdirSync(dir, { recursive: true });\n }\n}\n"],"mappings":";;;AAGO,IAAM,UAAkB;;;ACH/B,OAAO,cAAc;AACrB,SAAS,iBAAiB;AAC1B,SAAS,YAAY;AAErB,SAAS,OAAe;AACtB,QAAM,WAAW,QAAQ,IAAI,eAAe;AAC5C,MAAI,SAAU,QAAO;AAErB,SAAO,SAAS,YAAY,EAAE,QAAQ,GAAG,CAAC,EAAE;AAC9C;AAEO,SAAS,UAAkB;AAChC,SAAO,KAAK;AACd;AAEO,SAAS,UAAkB;AAChC,SAAO,KAAK,KAAK,GAAG,MAAM;AAC5B;AAEO,SAAS,aAAqB;AACnC,SAAO,KAAK,KAAK,GAAG,SAAS;AAC/B;AAEO,SAAS,UAAkB;AAChC,SAAO,KAAK,KAAK,GAAG,MAAM;AAC5B;AAEO,SAAS,aAAqB;AACnC,SAAO,KAAK,KAAK,GAAG,aAAa;AACnC;AAEO,SAAS,cAAsB;AACpC,SAAO,KAAK,KAAK,GAAG,YAAY;AAClC;AAEO,SAAS,eAAuB;AACrC,SAAO,KAAK,KAAK,GAAG,aAAa;AACnC;AAEO,SAAS,eAAuB;AACrC,SAAO,KAAK,KAAK,GAAG,WAAW;AACjC;AAEO,SAAS,aAAmB;AACjC,aAAW,OAAO,CAAC,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG;AACnD,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACpC;AACF;","names":[]}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
autostartDir
|
|
4
|
+
} from "./chunk-FMGZ3SSS.js";
|
|
5
|
+
|
|
6
|
+
// src/autostart/win32.ts
|
|
7
|
+
import { spawnSync } from "child_process";
|
|
8
|
+
import {
|
|
9
|
+
writeFileSync,
|
|
10
|
+
existsSync,
|
|
11
|
+
unlinkSync,
|
|
12
|
+
mkdirSync
|
|
13
|
+
} from "fs";
|
|
14
|
+
import { dirname, join } from "path";
|
|
15
|
+
var RUN_KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
|
16
|
+
function getValueName() {
|
|
17
|
+
return process.env["CRONTICK_AUTOSTART_TEST_VALUE"] ?? "crontick-daemon";
|
|
18
|
+
}
|
|
19
|
+
function getVbsPath() {
|
|
20
|
+
return join(autostartDir(), "crontick-daemon.vbs");
|
|
21
|
+
}
|
|
22
|
+
function findDaemonBinary() {
|
|
23
|
+
const override = process.env["CRONTICK_DAEMON_BINARY"];
|
|
24
|
+
if (override) return override;
|
|
25
|
+
const whereResult = spawnSync("where.exe", ["crontick-daemon"], {
|
|
26
|
+
encoding: "utf-8",
|
|
27
|
+
timeout: 5e3,
|
|
28
|
+
windowsHide: true
|
|
29
|
+
});
|
|
30
|
+
if (whereResult.status === 0 && whereResult.stdout.trim()) {
|
|
31
|
+
const first = whereResult.stdout.trim().split(/[\r\n]+/)[0]?.trim();
|
|
32
|
+
if (first) return first;
|
|
33
|
+
}
|
|
34
|
+
const nodeDir = dirname(process.execPath);
|
|
35
|
+
for (const candidate of ["crontick-daemon.cmd", "crontick-daemon"]) {
|
|
36
|
+
const p = join(nodeDir, candidate);
|
|
37
|
+
if (existsSync(p)) return p;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function buildVbsContent(daemonPath) {
|
|
42
|
+
const safePath = daemonPath.replace(/"/g, "");
|
|
43
|
+
return [
|
|
44
|
+
"' crontick-daemon autostart shim \u2014 generated by crontick autostart install",
|
|
45
|
+
"' Do not edit manually. Run: crontick autostart install to regenerate.",
|
|
46
|
+
'Set WshShell = CreateObject("WScript.Shell")',
|
|
47
|
+
`WshShell.Run "cmd /c ""${safePath}""", 0, False`,
|
|
48
|
+
""
|
|
49
|
+
].join("\r\n");
|
|
50
|
+
}
|
|
51
|
+
function regQuery(valueName) {
|
|
52
|
+
const result = spawnSync(
|
|
53
|
+
"reg",
|
|
54
|
+
["query", RUN_KEY, "/v", valueName],
|
|
55
|
+
{ encoding: "utf-8", timeout: 5e3, windowsHide: true }
|
|
56
|
+
);
|
|
57
|
+
if (result.status !== 0 || !result.stdout) return null;
|
|
58
|
+
const match = result.stdout.match(/REG_SZ\s+(.+)/i);
|
|
59
|
+
return match?.[1]?.trim() ?? null;
|
|
60
|
+
}
|
|
61
|
+
function regWrite(valueName, data) {
|
|
62
|
+
const result = spawnSync(
|
|
63
|
+
"reg",
|
|
64
|
+
["add", RUN_KEY, "/v", valueName, "/t", "REG_SZ", "/d", data, "/f"],
|
|
65
|
+
{ encoding: "utf-8", timeout: 5e3, windowsHide: true }
|
|
66
|
+
);
|
|
67
|
+
if (result.status !== 0) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`reg.exe add failed (exit ${result.status ?? "?"}): ${result.stderr?.trim() ?? "unknown error"}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function regDelete(valueName) {
|
|
74
|
+
spawnSync(
|
|
75
|
+
"reg",
|
|
76
|
+
["delete", RUN_KEY, "/v", valueName, "/f"],
|
|
77
|
+
{ encoding: "utf-8", timeout: 5e3, windowsHide: true }
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
var Win32Autostart = class {
|
|
81
|
+
async install() {
|
|
82
|
+
const daemonPath = findDaemonBinary();
|
|
83
|
+
if (!daemonPath) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"crontick-daemon binary not found. Ensure crontick is installed globally: npm i -g crontick"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const vbsPath = getVbsPath();
|
|
89
|
+
const valueName = getValueName();
|
|
90
|
+
mkdirSync(autostartDir(), { recursive: true });
|
|
91
|
+
writeFileSync(vbsPath, buildVbsContent(daemonPath), "utf-8");
|
|
92
|
+
regDelete(valueName);
|
|
93
|
+
regWrite(valueName, `wscript.exe "${vbsPath}"`);
|
|
94
|
+
return { ok: true };
|
|
95
|
+
}
|
|
96
|
+
async remove() {
|
|
97
|
+
const valueName = getValueName();
|
|
98
|
+
regDelete(valueName);
|
|
99
|
+
const vbsPath = getVbsPath();
|
|
100
|
+
if (existsSync(vbsPath)) {
|
|
101
|
+
try {
|
|
102
|
+
unlinkSync(vbsPath);
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { ok: true };
|
|
107
|
+
}
|
|
108
|
+
async status() {
|
|
109
|
+
const valueName = getValueName();
|
|
110
|
+
const data = regQuery(valueName);
|
|
111
|
+
const installed = data !== null;
|
|
112
|
+
return {
|
|
113
|
+
installed,
|
|
114
|
+
backend: "win32",
|
|
115
|
+
details: installed ? { registryValue: valueName, registryData: data, vbsPath: getVbsPath() } : { registryValue: valueName }
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/autostart/manual.ts
|
|
121
|
+
function instructions() {
|
|
122
|
+
switch (process.platform) {
|
|
123
|
+
case "win32":
|
|
124
|
+
return "Windows: add the following command to your startup folder or HKCU Run key:\n crontick-daemon\nOr run: crontick autostart install (uses HKCU Run + hidden VBS shim)";
|
|
125
|
+
case "darwin":
|
|
126
|
+
return "macOS (post-v1): create a launchd plist at\n ~/Library/LaunchAgents/com.crontick.daemon.plist\nwith ProgramArguments pointing to the crontick-daemon binary.\nThen run: launchctl load ~/Library/LaunchAgents/com.crontick.daemon.plist\n\nFor now, add the following to your shell profile (~/.zprofile or ~/.bash_profile):\n crontick-daemon &";
|
|
127
|
+
case "linux":
|
|
128
|
+
return "Linux (post-v1): create a systemd user unit at\n ~/.config/systemd/user/crontick.service\nThen run: systemctl --user enable --now crontick.service\n\nFor now, add the following to your shell profile (~/.profile or ~/.bashrc):\n crontick-daemon &\nOr add a @reboot crontab entry: crontab -e\n @reboot crontick-daemon";
|
|
129
|
+
default:
|
|
130
|
+
return "Add `crontick-daemon` to your system startup mechanism.\nThe daemon listens on a random localhost port; the port is written to the data directory.";
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
var ManualAutostart = class {
|
|
134
|
+
async install() {
|
|
135
|
+
return { ok: true };
|
|
136
|
+
}
|
|
137
|
+
async remove() {
|
|
138
|
+
return { ok: true };
|
|
139
|
+
}
|
|
140
|
+
async status() {
|
|
141
|
+
return {
|
|
142
|
+
installed: false,
|
|
143
|
+
backend: "manual",
|
|
144
|
+
details: { instructions: instructions() }
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/autostart/darwin.ts
|
|
150
|
+
var DarwinAutostart = class {
|
|
151
|
+
async install() {
|
|
152
|
+
throw new NotImplementedInV1Error(
|
|
153
|
+
"darwin autostart is planned for post-v1; use manual for now. See https://github.com/crontick/crontick for updates."
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
async remove() {
|
|
157
|
+
throw new NotImplementedInV1Error(
|
|
158
|
+
"darwin autostart is planned for post-v1; use manual for now."
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
async status() {
|
|
162
|
+
throw new NotImplementedInV1Error(
|
|
163
|
+
"darwin autostart is planned for post-v1; use manual for now."
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// src/autostart/linux.ts
|
|
169
|
+
var LinuxAutostart = class {
|
|
170
|
+
async install() {
|
|
171
|
+
throw new NotImplementedInV1Error(
|
|
172
|
+
"linux autostart is planned for post-v1; use manual for now. See https://github.com/crontick/crontick for updates."
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
async remove() {
|
|
176
|
+
throw new NotImplementedInV1Error(
|
|
177
|
+
"linux autostart is planned for post-v1; use manual for now."
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
async status() {
|
|
181
|
+
throw new NotImplementedInV1Error(
|
|
182
|
+
"linux autostart is planned for post-v1; use manual for now."
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// src/autostart/index.ts
|
|
188
|
+
var NotImplementedInV1Error = class _NotImplementedInV1Error extends Error {
|
|
189
|
+
constructor(message) {
|
|
190
|
+
super(message);
|
|
191
|
+
this.name = "NotImplementedInV1Error";
|
|
192
|
+
Object.setPrototypeOf(this, _NotImplementedInV1Error.prototype);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
function createAutostart(opts) {
|
|
196
|
+
const backend = opts?.backend ?? (process.platform === "win32" ? "win32" : "manual");
|
|
197
|
+
switch (backend) {
|
|
198
|
+
case "win32":
|
|
199
|
+
return new Win32Autostart();
|
|
200
|
+
case "darwin":
|
|
201
|
+
return new DarwinAutostart();
|
|
202
|
+
case "linux":
|
|
203
|
+
return new LinuxAutostart();
|
|
204
|
+
case "manual":
|
|
205
|
+
default:
|
|
206
|
+
return new ManualAutostart();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export {
|
|
211
|
+
NotImplementedInV1Error,
|
|
212
|
+
createAutostart
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=chunk-LPAFZNXK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/autostart/win32.ts","../src/autostart/manual.ts","../src/autostart/darwin.ts","../src/autostart/linux.ts","../src/autostart/index.ts"],"sourcesContent":["/**\n * Windows autostart backend — HKCU Run key + hidden VBS shim.\n *\n * Registry key: HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\n * Value name: crontick-daemon (or CRONTICK_AUTOSTART_TEST_VALUE for tests)\n * Value data: wscript.exe \"<dataDir>\\autostart\\crontick-daemon.vbs\"\n *\n * The VBS shim launches crontick-daemon via `cmd /c` with window style 0 (hidden).\n */\nimport { spawnSync } from 'node:child_process';\nimport {\n writeFileSync,\n existsSync,\n unlinkSync,\n mkdirSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { autostartDir } from '../paths.js';\nimport type { AutostartStatus } from './index.js';\n\nconst RUN_KEY = 'HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run';\n\nfunction getValueName(): string {\n return process.env['CRONTICK_AUTOSTART_TEST_VALUE'] ?? 'crontick-daemon';\n}\n\nfunction getVbsPath(): string {\n return join(autostartDir(), 'crontick-daemon.vbs');\n}\n\n/**\n * Locate the absolute path to the crontick-daemon binary/cmd wrapper.\n * Prefers `where.exe` detection so PATH changes don't break the shim.\n * CRONTICK_DAEMON_BINARY env var overrides detection (useful in CI/tests).\n */\nfunction findDaemonBinary(): string | null {\n // 0. Test / CI override\n const override = process.env['CRONTICK_DAEMON_BINARY'];\n if (override) return override;\n\n // 1. Try where.exe\n const whereResult = spawnSync('where.exe', ['crontick-daemon'], {\n encoding: 'utf-8',\n timeout: 5_000,\n windowsHide: true,\n });\n if (whereResult.status === 0 && whereResult.stdout.trim()) {\n const first = whereResult.stdout.trim().split(/[\\r\\n]+/)[0]?.trim();\n if (first) return first;\n }\n\n // 2. Fallback: look in the same directory as the Node.js executable\n const nodeDir = dirname(process.execPath);\n for (const candidate of ['crontick-daemon.cmd', 'crontick-daemon']) {\n const p = join(nodeDir, candidate);\n if (existsSync(p)) return p;\n }\n\n return null;\n}\n\nfunction buildVbsContent(daemonPath: string): string {\n // Remove any double-quotes in path (shouldn't exist in valid Win paths)\n const safePath = daemonPath.replace(/\"/g, '');\n return [\n \"' crontick-daemon autostart shim — generated by crontick autostart install\",\n \"' Do not edit manually. Run: crontick autostart install to regenerate.\",\n 'Set WshShell = CreateObject(\"WScript.Shell\")',\n `WshShell.Run \"cmd /c \"\"${safePath}\"\"\", 0, False`,\n '',\n ].join('\\r\\n');\n}\n\nfunction regQuery(valueName: string): string | null {\n const result = spawnSync(\n 'reg',\n ['query', RUN_KEY, '/v', valueName],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n if (result.status !== 0 || !result.stdout) return null;\n // Output format: \" valueName REG_SZ <data>\"\n const match = result.stdout.match(/REG_SZ\\s+(.+)/i);\n return match?.[1]?.trim() ?? null;\n}\n\nfunction regWrite(valueName: string, data: string): void {\n const result = spawnSync(\n 'reg',\n ['add', RUN_KEY, '/v', valueName, '/t', 'REG_SZ', '/d', data, '/f'],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n if (result.status !== 0) {\n throw new Error(\n `reg.exe add failed (exit ${result.status ?? '?'}): ${result.stderr?.trim() ?? 'unknown error'}`,\n );\n }\n}\n\nfunction regDelete(valueName: string): void {\n spawnSync(\n 'reg',\n ['delete', RUN_KEY, '/v', valueName, '/f'],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n // Ignore errors (value may not exist)\n}\n\nexport class Win32Autostart {\n async install(): Promise<{ ok: true }> {\n const daemonPath = findDaemonBinary();\n if (!daemonPath) {\n throw new Error(\n 'crontick-daemon binary not found. Ensure crontick is installed globally: npm i -g crontick',\n );\n }\n\n const vbsPath = getVbsPath();\n const valueName = getValueName();\n\n // Ensure directory and write VBS shim\n mkdirSync(autostartDir(), { recursive: true });\n writeFileSync(vbsPath, buildVbsContent(daemonPath), 'utf-8');\n\n // Idempotent: remove previous value before writing\n regDelete(valueName);\n regWrite(valueName, `wscript.exe \"${vbsPath}\"`);\n\n return { ok: true };\n }\n\n async remove(): Promise<{ ok: true }> {\n const valueName = getValueName();\n regDelete(valueName);\n\n // Remove VBS shim if it exists\n const vbsPath = getVbsPath();\n if (existsSync(vbsPath)) {\n try { unlinkSync(vbsPath); } catch { /* ignore */ }\n }\n\n return { ok: true };\n }\n\n async status(): Promise<AutostartStatus> {\n const valueName = getValueName();\n const data = regQuery(valueName);\n const installed = data !== null;\n return {\n installed,\n backend: 'win32',\n details: installed\n ? { registryValue: valueName, registryData: data, vbsPath: getVbsPath() }\n : { registryValue: valueName },\n };\n }\n}\n","/**\n * Manual autostart backend — prints per-platform instructions.\n * Works on any platform; used as the default on non-Windows in v1.\n */\nimport type { AutostartStatus } from './index.js';\n\nfunction instructions(): string {\n switch (process.platform) {\n case 'win32':\n return (\n 'Windows: add the following command to your startup folder or HKCU Run key:\\n' +\n ' crontick-daemon\\n' +\n 'Or run: crontick autostart install (uses HKCU Run + hidden VBS shim)'\n );\n case 'darwin':\n return (\n 'macOS (post-v1): create a launchd plist at\\n' +\n ' ~/Library/LaunchAgents/com.crontick.daemon.plist\\n' +\n 'with ProgramArguments pointing to the crontick-daemon binary.\\n' +\n 'Then run: launchctl load ~/Library/LaunchAgents/com.crontick.daemon.plist\\n' +\n '\\nFor now, add the following to your shell profile (~/.zprofile or ~/.bash_profile):\\n' +\n ' crontick-daemon &'\n );\n case 'linux':\n return (\n 'Linux (post-v1): create a systemd user unit at\\n' +\n ' ~/.config/systemd/user/crontick.service\\n' +\n 'Then run: systemctl --user enable --now crontick.service\\n' +\n '\\nFor now, add the following to your shell profile (~/.profile or ~/.bashrc):\\n' +\n ' crontick-daemon &\\n' +\n 'Or add a @reboot crontab entry: crontab -e\\n' +\n ' @reboot crontick-daemon'\n );\n default:\n return (\n 'Add `crontick-daemon` to your system startup mechanism.\\n' +\n 'The daemon listens on a random localhost port; the port is written to the data directory.'\n );\n }\n}\n\nexport class ManualAutostart {\n async install(): Promise<{ ok: true }> {\n return { ok: true };\n }\n\n async remove(): Promise<{ ok: true }> {\n return { ok: true };\n }\n\n async status(): Promise<AutostartStatus> {\n return {\n installed: false,\n backend: 'manual',\n details: { instructions: instructions() },\n };\n }\n}\n","/**\n * macOS autostart backend — STUB for post-v1.\n *\n * TODO (darwin implementation, post-v1):\n * - install():\n * 1. Build a launchd plist string for com.crontick.daemon\n * 2. Write to ~/Library/LaunchAgents/com.crontick.daemon.plist\n * 3. Run: launchctl load ~/Library/LaunchAgents/com.crontick.daemon.plist\n * - remove():\n * 1. Run: launchctl unload ~/Library/LaunchAgents/com.crontick.daemon.plist\n * 2. Delete ~/Library/LaunchAgents/com.crontick.daemon.plist\n * - status():\n * Run: launchctl list com.crontick.daemon (exit 0 = loaded)\n *\n * Plist template:\n * <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n * <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" ...>\n * <plist version=\"1.0\"><dict>\n * <key>Label</key><string>com.crontick.daemon</string>\n * <key>ProgramArguments</key>\n * <array><string>/usr/local/bin/crontick-daemon</string></array>\n * <key>RunAtLoad</key><true/>\n * <key>StandardOutPath</key><string>~/.local/state/crontick/logs/daemon.stdout.log</string>\n * <key>StandardErrorPath</key><string>~/.local/state/crontick/logs/daemon.stderr.log</string>\n * </dict></plist>\n */\nimport { NotImplementedInV1Error } from './index.js';\nimport type { AutostartStatus } from './index.js';\n\nexport class DarwinAutostart {\n async install(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'darwin autostart is planned for post-v1; use manual for now. ' +\n 'See https://github.com/crontick/crontick for updates.',\n );\n }\n\n async remove(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'darwin autostart is planned for post-v1; use manual for now.',\n );\n }\n\n async status(): Promise<AutostartStatus> {\n throw new NotImplementedInV1Error(\n 'darwin autostart is planned for post-v1; use manual for now.',\n );\n }\n}\n","/**\n * Linux autostart backend — STUB for post-v1.\n *\n * TODO (linux implementation, post-v1):\n * - install():\n * 1. Create ~/.config/systemd/user/ if absent\n * 2. Write unit file to ~/.config/systemd/user/crontick.service:\n *\n * [Unit]\n * Description=crontick daemon\n * After=default.target\n *\n * [Service]\n * Type=simple\n * ExecStart=/usr/local/bin/crontick-daemon\n * Restart=on-failure\n * RestartSec=5\n *\n * [Install]\n * WantedBy=default.target\n *\n * 3. Run: systemctl --user daemon-reload\n * 4. Run: systemctl --user enable --now crontick.service\n *\n * - remove():\n * 1. Run: systemctl --user disable --now crontick.service\n * 2. Delete ~/.config/systemd/user/crontick.service\n * 3. Run: systemctl --user daemon-reload\n *\n * - status():\n * Run: systemctl --user is-active crontick.service (exit 0 = active)\n */\nimport { NotImplementedInV1Error } from './index.js';\nimport type { AutostartStatus } from './index.js';\n\nexport class LinuxAutostart {\n async install(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'linux autostart is planned for post-v1; use manual for now. ' +\n 'See https://github.com/crontick/crontick for updates.',\n );\n }\n\n async remove(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'linux autostart is planned for post-v1; use manual for now.',\n );\n }\n\n async status(): Promise<AutostartStatus> {\n throw new NotImplementedInV1Error(\n 'linux autostart is planned for post-v1; use manual for now.',\n );\n }\n}\n","/**\n * Autostart abstraction — factory + types.\n * v1: win32 (HKCU Run + VBS shim) and manual (prints instructions).\n * darwin/linux are stubs that throw NotImplementedInV1Error.\n */\nimport { Win32Autostart } from './win32.js';\nimport { ManualAutostart } from './manual.js';\nimport { DarwinAutostart } from './darwin.js';\nimport { LinuxAutostart } from './linux.js';\n\nexport type AutostartBackend = 'win32' | 'darwin' | 'linux' | 'manual';\n\nexport interface AutostartStatus {\n installed: boolean;\n backend: AutostartBackend;\n details?: unknown;\n}\n\nexport interface Autostart {\n install(): Promise<{ ok: true }>;\n remove(): Promise<{ ok: true }>;\n status(): Promise<AutostartStatus>;\n}\n\n/** Thrown by darwin/linux stubs; serialised as HTTP 501 by the daemon API. */\nexport class NotImplementedInV1Error extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NotImplementedInV1Error';\n Object.setPrototypeOf(this, NotImplementedInV1Error.prototype);\n }\n}\n\n/**\n * Factory: default = win32 on Windows, manual everywhere else.\n * An explicit `opts.backend` always overrides the default.\n */\nexport function createAutostart(opts?: { backend?: AutostartBackend }): Autostart {\n const backend: AutostartBackend =\n opts?.backend ?? (process.platform === 'win32' ? 'win32' : 'manual');\n switch (backend) {\n case 'win32': return new Win32Autostart();\n case 'darwin': return new DarwinAutostart();\n case 'linux': return new LinuxAutostart();\n case 'manual':\n default: return new ManualAutostart();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var CrontickError = class _CrontickError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
details;
|
|
7
|
+
constructor(code, message, details) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "CrontickError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
Object.setPrototypeOf(this, _CrontickError.prototype);
|
|
13
|
+
}
|
|
14
|
+
toJSON() {
|
|
15
|
+
return { code: this.code, message: this.message, details: this.details };
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
CrontickError
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=chunk-YMAT5MON.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["export class CrontickError extends Error {\n code: string;\n details?: unknown;\n\n constructor(code: string, message: string, details?: unknown) {\n super(message);\n this.name = 'CrontickError';\n this.code = code;\n this.details = details;\n // Maintain proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, CrontickError.prototype);\n }\n\n toJSON(): { code: string; message: string; details?: unknown } {\n return { code: this.code, message: this.message, details: this.details };\n }\n}\n"],"mappings":";;;AAAO,IAAM,gBAAN,MAAM,uBAAsB,MAAM;AAAA,EACvC;AAAA,EACA;AAAA,EAEA,YAAY,MAAc,SAAiB,SAAmB;AAC5D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,UAAU;AAEf,WAAO,eAAe,MAAM,eAAc,SAAS;AAAA,EACrD;AAAA,EAEA,SAA+D;AAC7D,WAAO,EAAE,MAAM,KAAK,MAAM,SAAS,KAAK,SAAS,SAAS,KAAK,QAAQ;AAAA,EACzE;AACF;","names":[]}
|