crontick 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-FMGZ3SSS.js → chunk-5LHE6MWX.js} +2 -2
- package/dist/{chunk-LPAFZNXK.js → chunk-KNOV44I4.js} +121 -26
- package/dist/chunk-KNOV44I4.js.map +1 -0
- package/dist/cli/index.cjs +120 -25
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/daemon/index.cjs +120 -25
- package/dist/daemon/index.cjs.map +1 -1
- package/dist/daemon/index.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.js +1 -1
- package/package.json +5 -2
- package/dist/chunk-LPAFZNXK.js.map +0 -1
- /package/dist/{chunk-FMGZ3SSS.js.map → chunk-5LHE6MWX.js.map} +0 -0
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ scheduled jobs on Windows, macOS, and Linux.
|
|
|
20
20
|
- `action.kind: "script"` and `action.kind: "exec"`
|
|
21
21
|
- cron, interval, and one-shot schedules
|
|
22
22
|
- stdio MCP transport only
|
|
23
|
-
- Windows autostart via `HKCU\Run
|
|
23
|
+
- Windows autostart via API-based `HKCU\Run` registration; macOS/Linux provide manual guidance for now
|
|
24
24
|
|
|
25
25
|
## Quick start
|
|
26
26
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/version.ts
|
|
4
|
-
var VERSION = "0.1.
|
|
4
|
+
var VERSION = "0.1.1";
|
|
5
5
|
|
|
6
6
|
// src/paths.ts
|
|
7
7
|
import envPaths from "env-paths";
|
|
@@ -54,4 +54,4 @@ export {
|
|
|
54
54
|
autostartDir,
|
|
55
55
|
ensureDirs
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-5LHE6MWX.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
autostartDir
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5LHE6MWX.js";
|
|
5
5
|
|
|
6
6
|
// src/autostart/win32.ts
|
|
7
7
|
import { spawnSync } from "child_process";
|
|
@@ -12,7 +12,17 @@ import {
|
|
|
12
12
|
mkdirSync
|
|
13
13
|
} from "fs";
|
|
14
14
|
import { dirname, join } from "path";
|
|
15
|
-
var RUN_KEY = "
|
|
15
|
+
var RUN_KEY = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
|
16
|
+
var registryJs = null;
|
|
17
|
+
async function loadRegistryJs() {
|
|
18
|
+
const testRegistryJs = globalThis.__crontickRegistryJs;
|
|
19
|
+
if (testRegistryJs) return testRegistryJs;
|
|
20
|
+
if (!registryJs) {
|
|
21
|
+
const imported = await import("registry-js");
|
|
22
|
+
registryJs = imported.default ?? imported;
|
|
23
|
+
}
|
|
24
|
+
return registryJs;
|
|
25
|
+
}
|
|
16
26
|
function getValueName() {
|
|
17
27
|
return process.env["CRONTICK_AUTOSTART_TEST_VALUE"] ?? "crontick-daemon";
|
|
18
28
|
}
|
|
@@ -48,34 +58,120 @@ function buildVbsContent(daemonPath) {
|
|
|
48
58
|
""
|
|
49
59
|
].join("\r\n");
|
|
50
60
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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;
|
|
61
|
+
function getRunKey(registry) {
|
|
62
|
+
return registry.HKEY.HKEY_CURRENT_USER;
|
|
63
|
+
}
|
|
64
|
+
function isMissingRegistryValueError(error) {
|
|
65
|
+
if (!(error instanceof Error)) return false;
|
|
66
|
+
return /not found|cannot find|file not found|ERROR_FILE_NOT_FOUND|ENOENT/i.test(error.message);
|
|
60
67
|
}
|
|
61
|
-
function
|
|
68
|
+
function quotePowerShellLiteral(value) {
|
|
69
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
70
|
+
}
|
|
71
|
+
function runPowerShellRegistryScript(script) {
|
|
62
72
|
const result = spawnSync(
|
|
63
|
-
"
|
|
64
|
-
["
|
|
73
|
+
"powershell.exe",
|
|
74
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
65
75
|
{ encoding: "utf-8", timeout: 5e3, windowsHide: true }
|
|
66
76
|
);
|
|
67
77
|
if (result.status !== 0) {
|
|
68
78
|
throw new Error(
|
|
69
|
-
`
|
|
79
|
+
`PowerShell registry operation failed (exit ${result.status ?? "?"}): ${result.stderr?.trim() ?? "unknown error"}`
|
|
70
80
|
);
|
|
71
81
|
}
|
|
82
|
+
return result.stdout;
|
|
72
83
|
}
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{
|
|
78
|
-
|
|
84
|
+
function queryWithPowerShellRegistryApi(valueName) {
|
|
85
|
+
const literalPath = `Registry::HKEY_CURRENT_USER\\${RUN_KEY}`;
|
|
86
|
+
const script = [
|
|
87
|
+
'$ErrorActionPreference = "Stop";',
|
|
88
|
+
`try { $item = Get-ItemProperty -LiteralPath ${quotePowerShellLiteral(literalPath)} -Name ${quotePowerShellLiteral(valueName)};`,
|
|
89
|
+
`$value = $item.${quotePowerShellLiteral(valueName)};`,
|
|
90
|
+
"if ($null -ne $value) { [Console]::Out.Write([string]$value) } }",
|
|
91
|
+
"catch [System.Management.Automation.ItemNotFoundException] { exit 2 }",
|
|
92
|
+
"catch [System.Management.Automation.PSArgumentException] { exit 2 }",
|
|
93
|
+
"catch { throw }"
|
|
94
|
+
].join(" ");
|
|
95
|
+
try {
|
|
96
|
+
const stdout = runPowerShellRegistryScript(script);
|
|
97
|
+
return stdout.length > 0 ? stdout : null;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error instanceof Error && /exit 2/.test(error.message)) return null;
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function writeWithPowerShellRegistryApi(valueName, data) {
|
|
104
|
+
const literalPath = `Registry::HKEY_CURRENT_USER\\${RUN_KEY}`;
|
|
105
|
+
const script = [
|
|
106
|
+
'$ErrorActionPreference = "Stop"',
|
|
107
|
+
`New-Item -Path ${quotePowerShellLiteral(literalPath)} -Force | Out-Null`,
|
|
108
|
+
`New-ItemProperty -LiteralPath ${quotePowerShellLiteral(literalPath)} -Name ${quotePowerShellLiteral(valueName)} -Value ${quotePowerShellLiteral(data)} -PropertyType String -Force | Out-Null`
|
|
109
|
+
].join("; ");
|
|
110
|
+
runPowerShellRegistryScript(script);
|
|
111
|
+
}
|
|
112
|
+
function deleteWithPowerShellRegistryApi(valueName) {
|
|
113
|
+
const literalPath = `Registry::HKEY_CURRENT_USER\\${RUN_KEY}`;
|
|
114
|
+
const script = [
|
|
115
|
+
"Remove-ItemProperty",
|
|
116
|
+
"-LiteralPath",
|
|
117
|
+
quotePowerShellLiteral(literalPath),
|
|
118
|
+
"-Name",
|
|
119
|
+
quotePowerShellLiteral(valueName),
|
|
120
|
+
"-ErrorAction",
|
|
121
|
+
"SilentlyContinue"
|
|
122
|
+
].join(" ");
|
|
123
|
+
runPowerShellRegistryScript(script);
|
|
124
|
+
}
|
|
125
|
+
async function registryQuery(valueName) {
|
|
126
|
+
try {
|
|
127
|
+
const registry = await loadRegistryJs();
|
|
128
|
+
let values;
|
|
129
|
+
try {
|
|
130
|
+
values = registry.enumerateValues(getRunKey(registry), RUN_KEY);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (isMissingRegistryValueError(error)) return null;
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
const entry = values.find((value) => value.name.toLowerCase() === valueName.toLowerCase());
|
|
136
|
+
return typeof entry?.data === "string" ? entry.data : null;
|
|
137
|
+
} catch {
|
|
138
|
+
return queryWithPowerShellRegistryApi(valueName);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function registryWrite(valueName, data) {
|
|
142
|
+
try {
|
|
143
|
+
const registry = await loadRegistryJs();
|
|
144
|
+
registry.createKey?.(getRunKey(registry), RUN_KEY);
|
|
145
|
+
const ok = registry.setValue(
|
|
146
|
+
getRunKey(registry),
|
|
147
|
+
RUN_KEY,
|
|
148
|
+
valueName,
|
|
149
|
+
registry.RegistryValueType.REG_SZ,
|
|
150
|
+
data
|
|
151
|
+
);
|
|
152
|
+
if (ok) return;
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
writeWithPowerShellRegistryApi(valueName, data);
|
|
156
|
+
}
|
|
157
|
+
async function registryDelete(valueName) {
|
|
158
|
+
let registry;
|
|
159
|
+
try {
|
|
160
|
+
registry = await loadRegistryJs();
|
|
161
|
+
} catch {
|
|
162
|
+
deleteWithPowerShellRegistryApi(valueName);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
if (typeof registry.deleteValue !== "function") {
|
|
167
|
+
deleteWithPowerShellRegistryApi(valueName);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
registry.deleteValue(getRunKey(registry), RUN_KEY, valueName);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (isMissingRegistryValueError(error)) return;
|
|
173
|
+
deleteWithPowerShellRegistryApi(valueName);
|
|
174
|
+
}
|
|
79
175
|
}
|
|
80
176
|
var Win32Autostart = class {
|
|
81
177
|
async install() {
|
|
@@ -89,13 +185,12 @@ var Win32Autostart = class {
|
|
|
89
185
|
const valueName = getValueName();
|
|
90
186
|
mkdirSync(autostartDir(), { recursive: true });
|
|
91
187
|
writeFileSync(vbsPath, buildVbsContent(daemonPath), "utf-8");
|
|
92
|
-
|
|
93
|
-
regWrite(valueName, `wscript.exe "${vbsPath}"`);
|
|
188
|
+
await registryWrite(valueName, `wscript.exe "${vbsPath}"`);
|
|
94
189
|
return { ok: true };
|
|
95
190
|
}
|
|
96
191
|
async remove() {
|
|
97
192
|
const valueName = getValueName();
|
|
98
|
-
|
|
193
|
+
await registryDelete(valueName);
|
|
99
194
|
const vbsPath = getVbsPath();
|
|
100
195
|
if (existsSync(vbsPath)) {
|
|
101
196
|
try {
|
|
@@ -107,7 +202,7 @@ var Win32Autostart = class {
|
|
|
107
202
|
}
|
|
108
203
|
async status() {
|
|
109
204
|
const valueName = getValueName();
|
|
110
|
-
const data =
|
|
205
|
+
const data = await registryQuery(valueName);
|
|
111
206
|
const installed = data !== null;
|
|
112
207
|
return {
|
|
113
208
|
installed,
|
|
@@ -211,4 +306,4 @@ export {
|
|
|
211
306
|
NotImplementedInV1Error,
|
|
212
307
|
createAutostart
|
|
213
308
|
};
|
|
214
|
-
//# sourceMappingURL=chunk-
|
|
309
|
+
//# sourceMappingURL=chunk-KNOV44I4.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 = 'Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run';\n\ntype RegistryValue = {\n readonly name: string;\n readonly type: string;\n readonly data: string | number;\n};\n\ntype RegistryJsModule = {\n readonly HKEY: { readonly HKEY_CURRENT_USER: string };\n readonly RegistryValueType: { readonly REG_SZ: string };\n readonly setValue: (\n key: string,\n subkey: string,\n valueName: string,\n valueType: string,\n valueData: string,\n ) => boolean;\n readonly createKey?: (key: string, subkey: string) => boolean;\n readonly deleteValue?: (key: string, subkey: string, valueName: string) => boolean;\n readonly enumerateValues: (key: string, subkey: string) => ReadonlyArray<RegistryValue>;\n};\n\nlet registryJs: RegistryJsModule | null = null;\n\ntype RegistryGlobal = typeof globalThis & { __crontickRegistryJs?: RegistryJsModule };\n\nasync function loadRegistryJs(): Promise<RegistryJsModule> {\n const testRegistryJs = (globalThis as RegistryGlobal).__crontickRegistryJs;\n if (testRegistryJs) return testRegistryJs;\n if (!registryJs) {\n const imported = await import('registry-js') as RegistryJsModule & { default?: RegistryJsModule };\n registryJs = imported.default ?? imported;\n }\n return registryJs;\n}\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 getRunKey(registry: RegistryJsModule): string {\n return registry.HKEY.HKEY_CURRENT_USER;\n}\n\nfunction isMissingRegistryValueError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return /not found|cannot find|file not found|ERROR_FILE_NOT_FOUND|ENOENT/i.test(error.message);\n}\n\nfunction quotePowerShellLiteral(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\nfunction runPowerShellRegistryScript(script: string): string {\n const result = spawnSync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', script],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n if (result.status !== 0) {\n throw new Error(\n `PowerShell registry operation failed (exit ${result.status ?? '?'}): ${result.stderr?.trim() ?? 'unknown error'}`,\n );\n }\n return result.stdout;\n}\n\nfunction queryWithPowerShellRegistryApi(valueName: string): string | null {\n const literalPath = `Registry::HKEY_CURRENT_USER\\\\${RUN_KEY}`;\n const script = [\n '$ErrorActionPreference = \"Stop\";',\n `try { $item = Get-ItemProperty -LiteralPath ${quotePowerShellLiteral(literalPath)} -Name ${quotePowerShellLiteral(valueName)};`,\n `$value = $item.${quotePowerShellLiteral(valueName)};`,\n 'if ($null -ne $value) { [Console]::Out.Write([string]$value) } }',\n 'catch [System.Management.Automation.ItemNotFoundException] { exit 2 }',\n 'catch [System.Management.Automation.PSArgumentException] { exit 2 }',\n 'catch { throw }',\n ].join(' ');\n\n try {\n const stdout = runPowerShellRegistryScript(script);\n return stdout.length > 0 ? stdout : null;\n } catch (error) {\n if (error instanceof Error && /exit 2/.test(error.message)) return null;\n throw error;\n }\n}\n\nfunction writeWithPowerShellRegistryApi(valueName: string, data: string): void {\n const literalPath = `Registry::HKEY_CURRENT_USER\\\\${RUN_KEY}`;\n const script = [\n '$ErrorActionPreference = \"Stop\"',\n `New-Item -Path ${quotePowerShellLiteral(literalPath)} -Force | Out-Null`,\n `New-ItemProperty -LiteralPath ${quotePowerShellLiteral(literalPath)} -Name ${quotePowerShellLiteral(valueName)} -Value ${quotePowerShellLiteral(data)} -PropertyType String -Force | Out-Null`,\n ].join('; ');\n runPowerShellRegistryScript(script);\n}\n\nfunction deleteWithPowerShellRegistryApi(valueName: string): void {\n const literalPath = `Registry::HKEY_CURRENT_USER\\\\${RUN_KEY}`;\n const script = [\n 'Remove-ItemProperty',\n '-LiteralPath', quotePowerShellLiteral(literalPath),\n '-Name', quotePowerShellLiteral(valueName),\n '-ErrorAction', 'SilentlyContinue',\n ].join(' ');\n runPowerShellRegistryScript(script);\n}\n\nasync function registryQuery(valueName: string): Promise<string | null> {\n try {\n const registry = await loadRegistryJs();\n let values: ReadonlyArray<RegistryValue>;\n try {\n values = registry.enumerateValues(getRunKey(registry), RUN_KEY);\n } catch (error) {\n if (isMissingRegistryValueError(error)) return null;\n throw error;\n }\n const entry = values.find((value) => value.name.toLowerCase() === valueName.toLowerCase());\n return typeof entry?.data === 'string' ? entry.data : null;\n } catch {\n return queryWithPowerShellRegistryApi(valueName);\n }\n}\n\nasync function registryWrite(valueName: string, data: string): Promise<void> {\n try {\n const registry = await loadRegistryJs();\n registry.createKey?.(getRunKey(registry), RUN_KEY);\n const ok = registry.setValue(\n getRunKey(registry),\n RUN_KEY,\n valueName,\n registry.RegistryValueType.REG_SZ,\n data,\n );\n if (ok) return;\n } catch {\n // Fallback below.\n }\n writeWithPowerShellRegistryApi(valueName, data);\n}\n\nasync function registryDelete(valueName: string): Promise<void> {\n let registry: RegistryJsModule;\n try {\n registry = await loadRegistryJs();\n } catch {\n deleteWithPowerShellRegistryApi(valueName);\n return;\n }\n\n try {\n if (typeof registry.deleteValue !== 'function') {\n deleteWithPowerShellRegistryApi(valueName);\n return;\n }\n registry.deleteValue(getRunKey(registry), RUN_KEY, valueName);\n } catch (error) {\n if (isMissingRegistryValueError(error)) return;\n deleteWithPowerShellRegistryApi(valueName);\n }\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 await registryWrite(valueName, `wscript.exe \"${vbsPath}\"`);\n\n return { ok: true };\n }\n\n async remove(): Promise<{ ok: true }> {\n const valueName = getValueName();\n await registryDelete(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 = await registryQuery(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":[]}
|
package/dist/cli/index.cjs
CHANGED
|
@@ -32,7 +32,7 @@ var import_node_path3 = require("path");
|
|
|
32
32
|
var import_node_readline = require("readline");
|
|
33
33
|
|
|
34
34
|
// src/version.ts
|
|
35
|
-
var VERSION = "0.1.
|
|
35
|
+
var VERSION = "0.1.1";
|
|
36
36
|
|
|
37
37
|
// src/paths.ts
|
|
38
38
|
var import_env_paths = __toESM(require("env-paths"), 1);
|
|
@@ -151,7 +151,17 @@ var CrontickError = class _CrontickError extends Error {
|
|
|
151
151
|
var import_node_child_process = require("child_process");
|
|
152
152
|
var import_node_fs2 = require("fs");
|
|
153
153
|
var import_node_path2 = require("path");
|
|
154
|
-
var RUN_KEY = "
|
|
154
|
+
var RUN_KEY = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
|
155
|
+
var registryJs = null;
|
|
156
|
+
async function loadRegistryJs() {
|
|
157
|
+
const testRegistryJs = globalThis.__crontickRegistryJs;
|
|
158
|
+
if (testRegistryJs) return testRegistryJs;
|
|
159
|
+
if (!registryJs) {
|
|
160
|
+
const imported = await import("registry-js");
|
|
161
|
+
registryJs = imported.default ?? imported;
|
|
162
|
+
}
|
|
163
|
+
return registryJs;
|
|
164
|
+
}
|
|
155
165
|
function getValueName() {
|
|
156
166
|
return process.env["CRONTICK_AUTOSTART_TEST_VALUE"] ?? "crontick-daemon";
|
|
157
167
|
}
|
|
@@ -187,34 +197,120 @@ function buildVbsContent(daemonPath) {
|
|
|
187
197
|
""
|
|
188
198
|
].join("\r\n");
|
|
189
199
|
}
|
|
190
|
-
function
|
|
191
|
-
|
|
192
|
-
"reg",
|
|
193
|
-
["query", RUN_KEY, "/v", valueName],
|
|
194
|
-
{ encoding: "utf-8", timeout: 5e3, windowsHide: true }
|
|
195
|
-
);
|
|
196
|
-
if (result.status !== 0 || !result.stdout) return null;
|
|
197
|
-
const match = result.stdout.match(/REG_SZ\s+(.+)/i);
|
|
198
|
-
return match?.[1]?.trim() ?? null;
|
|
200
|
+
function getRunKey(registry) {
|
|
201
|
+
return registry.HKEY.HKEY_CURRENT_USER;
|
|
199
202
|
}
|
|
200
|
-
function
|
|
203
|
+
function isMissingRegistryValueError(error) {
|
|
204
|
+
if (!(error instanceof Error)) return false;
|
|
205
|
+
return /not found|cannot find|file not found|ERROR_FILE_NOT_FOUND|ENOENT/i.test(error.message);
|
|
206
|
+
}
|
|
207
|
+
function quotePowerShellLiteral(value) {
|
|
208
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
209
|
+
}
|
|
210
|
+
function runPowerShellRegistryScript(script) {
|
|
201
211
|
const result = (0, import_node_child_process.spawnSync)(
|
|
202
|
-
"
|
|
203
|
-
["
|
|
212
|
+
"powershell.exe",
|
|
213
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
204
214
|
{ encoding: "utf-8", timeout: 5e3, windowsHide: true }
|
|
205
215
|
);
|
|
206
216
|
if (result.status !== 0) {
|
|
207
217
|
throw new Error(
|
|
208
|
-
`
|
|
218
|
+
`PowerShell registry operation failed (exit ${result.status ?? "?"}): ${result.stderr?.trim() ?? "unknown error"}`
|
|
209
219
|
);
|
|
210
220
|
}
|
|
221
|
+
return result.stdout;
|
|
211
222
|
}
|
|
212
|
-
function
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
{
|
|
217
|
-
|
|
223
|
+
function queryWithPowerShellRegistryApi(valueName) {
|
|
224
|
+
const literalPath = `Registry::HKEY_CURRENT_USER\\${RUN_KEY}`;
|
|
225
|
+
const script = [
|
|
226
|
+
'$ErrorActionPreference = "Stop";',
|
|
227
|
+
`try { $item = Get-ItemProperty -LiteralPath ${quotePowerShellLiteral(literalPath)} -Name ${quotePowerShellLiteral(valueName)};`,
|
|
228
|
+
`$value = $item.${quotePowerShellLiteral(valueName)};`,
|
|
229
|
+
"if ($null -ne $value) { [Console]::Out.Write([string]$value) } }",
|
|
230
|
+
"catch [System.Management.Automation.ItemNotFoundException] { exit 2 }",
|
|
231
|
+
"catch [System.Management.Automation.PSArgumentException] { exit 2 }",
|
|
232
|
+
"catch { throw }"
|
|
233
|
+
].join(" ");
|
|
234
|
+
try {
|
|
235
|
+
const stdout = runPowerShellRegistryScript(script);
|
|
236
|
+
return stdout.length > 0 ? stdout : null;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (error instanceof Error && /exit 2/.test(error.message)) return null;
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function writeWithPowerShellRegistryApi(valueName, data) {
|
|
243
|
+
const literalPath = `Registry::HKEY_CURRENT_USER\\${RUN_KEY}`;
|
|
244
|
+
const script = [
|
|
245
|
+
'$ErrorActionPreference = "Stop"',
|
|
246
|
+
`New-Item -Path ${quotePowerShellLiteral(literalPath)} -Force | Out-Null`,
|
|
247
|
+
`New-ItemProperty -LiteralPath ${quotePowerShellLiteral(literalPath)} -Name ${quotePowerShellLiteral(valueName)} -Value ${quotePowerShellLiteral(data)} -PropertyType String -Force | Out-Null`
|
|
248
|
+
].join("; ");
|
|
249
|
+
runPowerShellRegistryScript(script);
|
|
250
|
+
}
|
|
251
|
+
function deleteWithPowerShellRegistryApi(valueName) {
|
|
252
|
+
const literalPath = `Registry::HKEY_CURRENT_USER\\${RUN_KEY}`;
|
|
253
|
+
const script = [
|
|
254
|
+
"Remove-ItemProperty",
|
|
255
|
+
"-LiteralPath",
|
|
256
|
+
quotePowerShellLiteral(literalPath),
|
|
257
|
+
"-Name",
|
|
258
|
+
quotePowerShellLiteral(valueName),
|
|
259
|
+
"-ErrorAction",
|
|
260
|
+
"SilentlyContinue"
|
|
261
|
+
].join(" ");
|
|
262
|
+
runPowerShellRegistryScript(script);
|
|
263
|
+
}
|
|
264
|
+
async function registryQuery(valueName) {
|
|
265
|
+
try {
|
|
266
|
+
const registry = await loadRegistryJs();
|
|
267
|
+
let values;
|
|
268
|
+
try {
|
|
269
|
+
values = registry.enumerateValues(getRunKey(registry), RUN_KEY);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
if (isMissingRegistryValueError(error)) return null;
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
const entry = values.find((value) => value.name.toLowerCase() === valueName.toLowerCase());
|
|
275
|
+
return typeof entry?.data === "string" ? entry.data : null;
|
|
276
|
+
} catch {
|
|
277
|
+
return queryWithPowerShellRegistryApi(valueName);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async function registryWrite(valueName, data) {
|
|
281
|
+
try {
|
|
282
|
+
const registry = await loadRegistryJs();
|
|
283
|
+
registry.createKey?.(getRunKey(registry), RUN_KEY);
|
|
284
|
+
const ok = registry.setValue(
|
|
285
|
+
getRunKey(registry),
|
|
286
|
+
RUN_KEY,
|
|
287
|
+
valueName,
|
|
288
|
+
registry.RegistryValueType.REG_SZ,
|
|
289
|
+
data
|
|
290
|
+
);
|
|
291
|
+
if (ok) return;
|
|
292
|
+
} catch {
|
|
293
|
+
}
|
|
294
|
+
writeWithPowerShellRegistryApi(valueName, data);
|
|
295
|
+
}
|
|
296
|
+
async function registryDelete(valueName) {
|
|
297
|
+
let registry;
|
|
298
|
+
try {
|
|
299
|
+
registry = await loadRegistryJs();
|
|
300
|
+
} catch {
|
|
301
|
+
deleteWithPowerShellRegistryApi(valueName);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
try {
|
|
305
|
+
if (typeof registry.deleteValue !== "function") {
|
|
306
|
+
deleteWithPowerShellRegistryApi(valueName);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
registry.deleteValue(getRunKey(registry), RUN_KEY, valueName);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
if (isMissingRegistryValueError(error)) return;
|
|
312
|
+
deleteWithPowerShellRegistryApi(valueName);
|
|
313
|
+
}
|
|
218
314
|
}
|
|
219
315
|
var Win32Autostart = class {
|
|
220
316
|
async install() {
|
|
@@ -228,13 +324,12 @@ var Win32Autostart = class {
|
|
|
228
324
|
const valueName = getValueName();
|
|
229
325
|
(0, import_node_fs2.mkdirSync)(autostartDir(), { recursive: true });
|
|
230
326
|
(0, import_node_fs2.writeFileSync)(vbsPath, buildVbsContent(daemonPath), "utf-8");
|
|
231
|
-
|
|
232
|
-
regWrite(valueName, `wscript.exe "${vbsPath}"`);
|
|
327
|
+
await registryWrite(valueName, `wscript.exe "${vbsPath}"`);
|
|
233
328
|
return { ok: true };
|
|
234
329
|
}
|
|
235
330
|
async remove() {
|
|
236
331
|
const valueName = getValueName();
|
|
237
|
-
|
|
332
|
+
await registryDelete(valueName);
|
|
238
333
|
const vbsPath = getVbsPath();
|
|
239
334
|
if ((0, import_node_fs2.existsSync)(vbsPath)) {
|
|
240
335
|
try {
|
|
@@ -246,7 +341,7 @@ var Win32Autostart = class {
|
|
|
246
341
|
}
|
|
247
342
|
async status() {
|
|
248
343
|
const valueName = getValueName();
|
|
249
|
-
const data =
|
|
344
|
+
const data = await registryQuery(valueName);
|
|
250
345
|
const installed = data !== null;
|
|
251
346
|
return {
|
|
252
347
|
installed,
|