@mrsekut/ccron 0.3.0 → 0.3.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/package.json +1 -1
- package/src/commands/test.ts +26 -4
- package/src/generator.ts +6 -1
package/package.json
CHANGED
package/src/commands/test.ts
CHANGED
|
@@ -25,7 +25,7 @@ Checks:
|
|
|
25
25
|
2. claude auth status (logged in)
|
|
26
26
|
3. ulimit -n (file descriptors)
|
|
27
27
|
4. Script file exists
|
|
28
|
-
5. Script path is outside TCC-protected directories
|
|
28
|
+
5. Script path (and cwd, if set) is outside TCC-protected directories
|
|
29
29
|
6. Plist registered in launchd
|
|
30
30
|
7. MCP config exists (if task uses MCP)
|
|
31
31
|
8. MCP auth (if task uses MCP) — runs claude CLI to verify OAuth tokens
|
|
@@ -58,6 +58,7 @@ Example:
|
|
|
58
58
|
checks.push(await checkUlimit());
|
|
59
59
|
checks.push(await checkScriptExists(name));
|
|
60
60
|
checks.push(checkScriptTccSafe(name));
|
|
61
|
+
if (task.cwd) checks.push(checkCwdTccSafe(task.cwd));
|
|
61
62
|
checks.push(await checkPlistRegistered(name));
|
|
62
63
|
|
|
63
64
|
if (task.mcpConfig) {
|
|
@@ -175,11 +176,32 @@ async function checkScriptExists(name: string): Promise<CheckResult> {
|
|
|
175
176
|
};
|
|
176
177
|
}
|
|
177
178
|
|
|
179
|
+
const TCC_DIRS = ['Desktop', 'Documents', 'Downloads'];
|
|
180
|
+
|
|
181
|
+
function tccProtects(path: string): boolean {
|
|
182
|
+
const home = homedir();
|
|
183
|
+
return TCC_DIRS.some(dir => path.startsWith(`${home}/${dir}`));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function checkCwdTccSafe(cwd: string): CheckResult {
|
|
187
|
+
const inTcc = tccProtects(cwd);
|
|
188
|
+
return {
|
|
189
|
+
label: 'TCC protection (cwd)',
|
|
190
|
+
ok: !inTcc,
|
|
191
|
+
detail: inTcc
|
|
192
|
+
? `cwd is in a TCC-protected directory (${cwd})`
|
|
193
|
+
: `cwd is outside TCC-protected directories`,
|
|
194
|
+
// Granting Full Disk Access to /bin/bash is not enough: the claude process
|
|
195
|
+
// gets its own TCC identity and still fails with EPERM on these paths.
|
|
196
|
+
fix: inTcc
|
|
197
|
+
? 'Move the project outside ~/Desktop, ~/Documents, ~/Downloads, or grant Full Disk Access to the claude binary'
|
|
198
|
+
: undefined,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
178
202
|
function checkScriptTccSafe(name: string): CheckResult {
|
|
179
203
|
const path = scriptPath(name);
|
|
180
|
-
const
|
|
181
|
-
const tccDirs = [`${home}/Desktop`, `${home}/Documents`, `${home}/Downloads`];
|
|
182
|
-
const inTcc = tccDirs.some(dir => path.startsWith(dir));
|
|
204
|
+
const inTcc = tccProtects(path);
|
|
183
205
|
return {
|
|
184
206
|
label: 'TCC protection',
|
|
185
207
|
ok: !inTcc,
|
package/src/generator.ts
CHANGED
|
@@ -59,6 +59,11 @@ export function generateScriptContent(
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Generate the launchd plist XML content.
|
|
62
|
+
*
|
|
63
|
+
* WorkingDirectory stays /tmp even when the task sets `cwd`. launchd performs the
|
|
64
|
+
* chdir itself, and that chdir is denied for TCC-protected locations (~/Desktop,
|
|
65
|
+
* ~/Documents, ...), which fails the job before the script runs. The script's own
|
|
66
|
+
* `cd` handles `cwd` instead.
|
|
62
67
|
*/
|
|
63
68
|
export function generatePlistContent(
|
|
64
69
|
task: TaskConfig,
|
|
@@ -102,7 +107,7 @@ export function generatePlistContent(
|
|
|
102
107
|
<string>${escapeXml(pathEntries)}</string>
|
|
103
108
|
</dict>
|
|
104
109
|
<key>WorkingDirectory</key>
|
|
105
|
-
<string
|
|
110
|
+
<string>/tmp</string>
|
|
106
111
|
<key>StartCalendarInterval</key>
|
|
107
112
|
${calendarIntervalXml}
|
|
108
113
|
<key>StandardOutPath</key>
|