@crewx/cron 0.1.10-rc.209 → 0.1.10-rc.210
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/cli.js +7 -6
- package/dist/src/builtins.d.ts +4 -1
- package/dist/src/builtins.js +1 -1
- package/dist/src/engine.d.ts +14 -1
- package/dist/src/engine.js +5 -5
- package/dist/src/run-record.d.ts +26 -0
- package/dist/src/run-record.js +1 -0
- package/dist/src/runtime.d.ts +1 -0
- package/dist/src/runtime.js +1 -1
- package/dist/src/types.d.ts +3 -1
- package/package.json +3 -3
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
3
|
-
@crewx/cron@${
|
|
2
|
+
"use strict";var N=exports&&exports.__createBinding||(Object.create?(function(e,t,r,n){if(n===void 0)n=r;var o=Object.getOwnPropertyDescriptor(t,r);if(!o||("get"in o?!t.__esModule:o.writable||o.configurable)){o={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,o)}):(function(e,t,r,n){if(n===void 0)n=r;e[n]=t[r]}));var R=exports&&exports.__setModuleDefault||(Object.create?(function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}):function(e,t){e["default"]=t});var h=exports&&exports.__importStar||(function(){var e=function(t){e=Object.getOwnPropertyNames||function(r){var n=[];for(var o in r)if(Object.prototype.hasOwnProperty.call(r,o))n[n.length]=o;return n};return e(t)};return function(t){if(t&&t.__esModule)return t;var r={};if(t!=null){for(var n=e(t),o=0;o<n.length;o++)if(n[o]!=="default")N(r,t,n[o])}R(r,t);return r}})();Object.defineProperty(exports,"__esModule",{value:true});exports.CRON_RUNTIME_LIFECYCLE_MANAGED=void 0;exports.formatDisplayTimestamp=g;exports.main=S;const m=h(require("fs"));const f=h(require("path"));let $="unknown";try{const e=m.existsSync(f.join(__dirname,"package.json"))?f.join(__dirname,"package.json"):f.join(__dirname,"..","package.json");const t=JSON.parse(m.readFileSync(e,"utf-8"));if(t?.version)$=String(t.version)}catch{}async function I(){try{return await Promise.resolve().then(()=>h(require("@crewx/shared/skill-tracer")))}catch{return null}}const _=require("@crewx/sdk");const a=require("./src/engine");const k=require("./src/run-record");exports.CRON_RUNTIME_LIFECYCLE_MANAGED="CRON_RUNTIME_LIFECYCLE_MANAGED";function x(e,t){if(e==="APP_LAUNCHER_UNAVAILABLE"){return"This schedule belongs to an App and runs only inside the CrewX server; it cannot be started from the CLI."}if(e==="APP_ROW_INVALID")return"This App schedule is not in its managed form, so it was not run.";if(e==="MODE_UNSUPPORTED")return`Unsupported schedule mode: ${t.mode}`;return"A desktop update is draining active work; cannot start a new schedule run right now."}function v(e){return e.app!==void 0?(0,_.appScheduleCommandLabel)(e.app):e.command}function w(e){const t=new Error(`${exports.CRON_RUNTIME_LIFECYCLE_MANAGED}: cron ${e} is managed by the CrewX server runtime; start the server instead`);t.code=exports.CRON_RUNTIME_LIFECYCLE_MANAGED;return t}const b=20;function C(e){if(e===null)return"-";return`${(e/1e3).toFixed(1)}s`}function A(e,t){if(e.length===0){console.log(t===void 0?"No runs yet.":`No runs yet for ${t}.`);return}console.log(`Recent runs (newest first, ${b} max)`);console.log(`${"STARTED".padEnd(28)}${"STATUS".padEnd(10)}${"MODE".padEnd(9)}${"DURATION".padEnd(10)}${"RUN".padEnd(16)}${"SCHEDULE".padEnd(18)}DETAIL`);for(const r of e){const n=[r.errorCode,r.highFrequency?"high frequency":null].filter(Boolean).join(", ");console.log(`${g(new Date(r.startedAt)).padEnd(28)}${r.status.padEnd(10)}${r.mode.padEnd(9)}${C(r.durationMs).padEnd(10)}${r.id.padEnd(16)}${r.scheduleId.padEnd(18)}`+n)}}function O(e){console.log(`Run: ${e.id}`);console.log(`Schedule: ${e.scheduleId}${e.scheduleName?` (${e.scheduleName})`:""}`);console.log(`Mode: ${e.mode}`);console.log(`Status: ${e.status}`);if(e.errorCode)console.log(`Error: ${e.errorCode}`);if(e.exitCode!==null)console.log(`Exit code: ${e.exitCode}`);if(e.signal)console.log(`Signal: ${e.signal}`);console.log(`Trigger: ${e.trigger}`);console.log(`Started: ${g(new Date(e.startedAt))}`);if(e.finishedAt)console.log(`Finished: ${g(new Date(e.finishedAt))}`);console.log(`Duration: ${C(e.durationMs)}`);if(e.appId)console.log(`App: ${e.appId}`);if(e.command)console.log(`Command: ${e.command}`);if(e.taskId)console.log(`Task: ${e.taskId}`);if(e.outputBytes!==null)console.log(`Output: ${e.outputBytes} bytes${e.outputTruncated?" (truncated during the run)":""}`);console.log("\u2500".repeat(40));if(e.outputTail===null){console.log(e.mode==="app"?"(App runs keep no output tail)":"(no output captured)")}else if(e.outputTail===""){console.log("(no output)")}else{console.log(e.outputTail)}}function U(e){try{return new _.ScheduleRunRepository().get(e)}catch(t){console.warn(`Run ${e} record could not be read; the exit code follows the run's own result: ${t.message}`);return void 0}}function i(e,t,r){for(let n=0;n<e.length;n++){const o=e[n];if(!o)continue;if(o===t||r&&o===r){return e[n+1]}if(o.startsWith(t+"=")){return o.slice(t.length+1)}if(r&&o.startsWith(r+"=")){return o.slice(r.length+1)}}return void 0}function u(e,t,r){return e.includes(t)||(r?e.includes(r):false)}function T(){const e=f.join(__dirname,"..","SKILL.md");if(m.existsSync(e)){process.stdout.write(m.readFileSync(e,"utf-8"))}else{console.log("No SKILL.md found. Use --help for usage.")}}function g(e){const t=e.toISOString();return`${t.slice(0,10)} ${t.slice(11,19)} UTC`}function y(){console.log(`
|
|
3
|
+
@crewx/cron@${$} - Cron-based task scheduler for AI agents
|
|
4
4
|
|
|
5
5
|
Usage:
|
|
6
6
|
cron <command> [options]
|
|
@@ -14,6 +14,7 @@ Commands:
|
|
|
14
14
|
cron update <id> [options] Update a schedule
|
|
15
15
|
cron info <id> Show schedule details
|
|
16
16
|
cron run <id> Run a schedule immediately
|
|
17
|
+
cron runs [cron_\u2026 | crun_\u2026] List recent runs, or show one run with its output
|
|
17
18
|
cron start Start the cron daemon
|
|
18
19
|
cron stop Stop the cron daemon
|
|
19
20
|
cron status Check daemon status
|
|
@@ -30,7 +31,7 @@ Examples:
|
|
|
30
31
|
cron start
|
|
31
32
|
|
|
32
33
|
For detailed usage guide: cron usage
|
|
33
|
-
`)}async function
|
|
34
|
-
Schedules (${
|
|
35
|
-
`);console.log("| ID | Name | Cron | Status | Command |");console.log("|--------|----------------|-------------|--------|----------------------------|");for(const c of
|
|
36
|
-
Schedule: ${
|
|
34
|
+
`)}async function S(e){const t=e??process.argv.slice(2);const r=t[0];if(u(t,"--version")){console.log($);return}if(!r||r==="help"||u(t,"--help","-h")){y();return}switch(r){case"usage":{T();break}case"add":{const n=[];for(let d=1;d<t.length;d++){const p=t[d];if(!p)continue;if(p.startsWith("-")){if(["--name","-n","--mode","-m","--timezone","-t","--dir","-d","--timeout","--model","--provider"].includes(p)){d++}continue}n.push(p)}if(n.length<2){console.error("Usage: cron add <schedule> <command> [--name <name>] [--mode <mode>] [--model <model>] [--provider <provider>]");process.exit(1)}const o=n[0];const c=n.slice(1).join(" ");const s=t.slice(1);const l=(0,a.addSchedule)(o,c,{name:i(s,"--name","-n"),mode:i(s,"--mode","-m"),timezone:i(s,"--timezone","-t"),dir:i(s,"--dir","-d"),timeout:i(s,"--timeout"),allowConcurrent:u(s,"--allow-concurrent"),model:i(s,"--model"),provider:i(s,"--provider")});console.log(`Schedule created: ${l.id}`);console.log(`Cron: ${o} (${(0,a.describeCron)(o)})`);console.log(`Command: ${c}`);console.log(`Mode: ${l.mode}`);if(l.model)console.log(`Model: ${l.model}`);if(l.provider)console.log(`Provider: ${l.provider}`);if(l.timezone)console.log(`Timezone: ${l.timezone}`);if(l.next_run)console.log(`Next run: ${g(new Date(l.next_run))}`);break}case"list":case"ls":{const n=u(t,"--json");const o=(0,a.loadSchedules)();if(n){console.log(JSON.stringify(o,null,2));return}if(o.length===0){console.log("No schedules found.");return}console.log(`
|
|
35
|
+
Schedules (${o.length}):
|
|
36
|
+
`);console.log("| ID | Name | Cron | Status | Command |");console.log("|--------|----------------|-------------|--------|----------------------------|");for(const c of o){const s=(0,a.effectiveEnabled)(c)?"ON ":"OFF";const l=(c.name??"-").substring(0,14).padEnd(14);const d=c.cron.substring(0,11).padEnd(11);const p=v(c).substring(0,26).padEnd(26);console.log(`| ${c.id} | ${l} | ${d} | ${s} | ${p} |`)}console.log("");break}case"remove":case"rm":{const n=t[1];if(!n){console.error("Usage: cron remove <id>");process.exit(1)}try{const o=(0,a.removeSchedule)(n);console.log(`Removed schedule: ${n}`);console.log(`Cron: ${o.cron}`);console.log(`Command: ${o.command}`)}catch(o){const c=o;console.error(c.message);process.exit(1)}break}case"enable":{const n=t[1];if(!n){console.error("Usage: cron enable <id>");process.exit(1)}try{(0,a.enableSchedule)(n);console.log(`Enabled schedule: ${n}`)}catch(o){const c=o;console.error(c.message);process.exit(1)}break}case"disable":{const n=t[1];if(!n){console.error("Usage: cron disable <id>");process.exit(1)}try{(0,a.disableSchedule)(n);console.log(`Disabled schedule: ${n}`)}catch(o){const c=o;console.error(c.message);process.exit(1)}break}case"update":{const n=t[1];if(!n){console.error("Usage: cron update <id> [--cron <expr>] [--command <cmd>] [--name <name>] [--model <model>] [--clear-model] [--provider <provider>] [--clear-provider]");process.exit(1)}const o=t.slice(1);try{const c={cron:i(o,"--cron","-c"),command:i(o,"--command","-C"),name:i(o,"--name","-n"),mode:i(o,"--mode","-m"),timezone:i(o,"--timezone","-t"),working_directory:i(o,"--dir","-d"),timeout_ms:i(o,"--timeout")?parseInt(i(o,"--timeout"),10):void 0,allow_concurrent:u(o,"--allow-concurrent")?true:u(o,"--no-allow-concurrent")?false:void 0,model:u(o,"--clear-model")?null:i(o,"--model"),provider:u(o,"--clear-provider")?null:i(o,"--provider")};const{schedule:s,changes:l}=(0,a.updateSchedule)(n,c);if(l.length===0){console.log("No changes specified. Use --cron, --command, --name, etc.");process.exit(1)}console.log(`Updated schedule: ${n}`);l.forEach(d=>console.log(` ${d}`));if(s.next_run){console.log(`Next run: ${g(new Date(s.next_run))}`)}}catch(c){const s=c;console.error(s.message);process.exit(1)}break}case"info":{const n=t[1];if(!n){console.error("Usage: cron info <id>");process.exit(1)}const o=u(t,"--json");const c=(0,a.loadSchedules)();const s=c.find(l=>l.id===n);if(!s){console.error(`Schedule not found: ${n}`);process.exit(1)}if(o){console.log(JSON.stringify(s,null,2));return}console.log(`
|
|
37
|
+
Schedule: ${s.id}`);console.log("\u2500".repeat(40));console.log(`Name: ${s.name??"-"}`);console.log(`Cron: ${s.cron} (${(0,a.describeCron)(s.cron)})`);console.log(`Command: ${v(s)}`);console.log(`Mode: ${s.mode}`);console.log(`Model: ${s.model??"(agent default)"}`);console.log(`Provider: ${s.provider??"(agent default)"}`);console.log(`Status: ${(0,a.effectiveEnabled)(s)?"Enabled":"Disabled"}`);if(s.app!==void 0)console.log(`App: ${s.app.appId} (${s.app.actionId}); change it from the App`);console.log(`Timezone: ${s.timezone??"Local"}`);console.log(`Working Dir: ${s.working_directory??"Project root"}`);console.log(`Timeout: ${s.timeout_ms/1e3}s`);console.log(`Allow Concurrent: ${s.allow_concurrent?"Yes":"No"}`);console.log("\u2500".repeat(40));console.log(`Created: ${g(new Date(s.created_at))}`);console.log(`Updated: ${g(new Date(s.updated_at))}`);console.log(`Last Run: ${s.last_run?g(new Date(s.last_run)):"Never"}`);console.log(`Next Run: ${s.next_run?g(new Date(s.next_run)):"Unknown"}`);console.log(`Run Count: ${s.run_count??0}`);console.log("");break}case"run":{const n=t[1];if(!n){console.error("Usage: cron run <id>");process.exit(1)}const o=(0,a.loadSchedules)();const c=o.find(D=>D.id===n);if(!c){console.error(`Schedule not found: ${n}`);process.exit(1)}console.log(`Running schedule: ${n}`);const s=await(0,a.executeSchedule)(c,{trigger:"cron_manual"});if(s.status==="blocked"){console.error(x(s.reason,c));process.exit(1)}if(s.status==="conflict"){console.error(`Schedule already running (run: ${s.runningRunId??"unknown"})`);process.exit(1)}if(s.status==="skipped"){console.error(`Schedule not run: ${s.reason}`);break}console.log(`Run started: ${s.runId}`);if(s.taskId!==void 0)console.log(`Task: ${s.taskId}`);const l=await s.done;const d=U(s.runId);const p=!l.success||d?.status==="failed"||d?.status==="lost";console.log(`Result: ${p?"Failed":"Success"}`);const E=l.error??d?.errorCode;if(E)console.log(`Error: ${E}`);if(p)process.exit(1);break}case"runs":{const n=t[1];const o=new _.ScheduleRunRepository;const c=(0,k.runWorkspaceId)(process.cwd());if(n!==void 0&&n.startsWith("crun_")){const l=o.get(n);if(l===void 0||l.workspaceId!==c){console.error(`Run not found in this workspace: ${n}`);process.exit(1)}O(l);break}const s=n===void 0?o.listByWorkspace(c,{limit:b}):o.listBySchedule(c,n,b);A(s,n);break}case"start":{throw w(r)}case"stop":{throw w(r)}case"status":{const n=u(t,"--json");const o=(0,a.getDaemonStatus)();if(n){console.log(JSON.stringify(o,null,2));return}if(o.running&&o.pid){console.log(`Daemon is running (PID: ${o.pid})`);if(o.started_at){console.log(`Started: ${g(new Date(o.started_at))}`)}}else{console.log("Daemon is not running")}console.log(`Schedules: ${o.schedules.enabled}/${o.schedules.total} enabled`);break}case"daemon":{if(u(t,"--foreground")){(0,a.runDaemonForeground)()}else{throw w(r)}break}default:{console.error(`Unknown command: ${r}`);y();process.exit(1)}}}if(require.main===module){const e=process.argv.slice(2);const t=e[0]==="daemon"&&e.includes("--foreground");(t?Promise.resolve(null):I()).then(r=>{const n=r?{skillVersion:r.getOwnSkillVersion(__dirname)}:{};return r?r.run("crewx/cron",()=>S(),n):S()}).catch(r=>{console.error(r.message);process.exit(1)})}
|
package/dist/src/builtins.d.ts
CHANGED
|
@@ -5,9 +5,12 @@ export interface BuiltinScheduleDef {
|
|
|
5
5
|
cron: string;
|
|
6
6
|
mode: ExecutionMode;
|
|
7
7
|
buildCommand: () => string;
|
|
8
|
+
cliArgs: readonly string[];
|
|
9
|
+
isLegacyCommand: (command: string) => boolean;
|
|
10
|
+
isFrozenPathCommand: (command: string) => boolean;
|
|
8
11
|
}
|
|
12
|
+
export declare function normalizeBuiltinCommand(command: string): string;
|
|
9
13
|
export declare function getProjectRoot(): string;
|
|
10
|
-
export declare function getBuiltinMemoryCliPath(): string;
|
|
11
14
|
export declare const BUILTIN_SCHEDULES: BuiltinScheduleDef[];
|
|
12
15
|
export declare function findBuiltinByName(name: string | null | undefined): BuiltinScheduleDef | undefined;
|
|
13
16
|
export declare function findBuiltinById(builtinId: string): BuiltinScheduleDef | undefined;
|
package/dist/src/builtins.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.BUILTIN_SCHEDULES=void 0;exports.normalizeBuiltinCommand=t;exports.getProjectRoot=m;exports.findBuiltinByName=d;exports.findBuiltinById=u;const r=require("child_process");function t(e){return e.trim().replace(/\s+/g," ")}function m(){try{return(0,r.execSync)("git rev-parse --show-toplevel",{encoding:"utf8"}).trim()}catch{return process.cwd()}}const n=/^node .+[\\/]packages[\\/]built-in[\\/]memory[\\/]dist[\\/]cli\.js summarize-dirty$/;const o=[n,/^npx memory summarize-dirty$/,/^npx @crewx\/memory summarize-dirty$/];exports.BUILTIN_SCHEDULES=[{builtin_id:"memory-debounce",name:"memory-debounce",cron:"*/1 * * * *",mode:"command",buildCommand:()=>"crewx memory summarize-dirty",cliArgs:["memory","summarize-dirty"],isLegacyCommand:e=>o.some(i=>i.test(e)),isFrozenPathCommand:e=>n.test(e)}];function d(e){if(!e)return void 0;return exports.BUILTIN_SCHEDULES.find(i=>i.name===e)}function u(e){return exports.BUILTIN_SCHEDULES.find(i=>i.builtin_id===e)}
|
package/dist/src/engine.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { BuiltinScheduleDef } from './builtins';
|
|
|
6
6
|
export type { Schedule, ExecutionMode, ExecuteResult, ExecuteScheduleOptions, ExecuteScheduleOutcome, ExecuteScheduleSkipped, AppScheduleBinding, AppScheduleLaunchDecision, AppScheduleLauncher, AppScheduleOwner, AppScheduleSettle, AppScheduleChildExit, AppScheduleSkipRecord, AppScheduleTemplate, AppScheduleWrite, ScheduleTrigger, DaemonStatus, UpdateOptions, StartDaemonResult, CronStoreErrorCode, ScheduleStore, ScheduleStoreLock, ScheduleStoreUpdate, ClaimOccurrenceOptions, ClaimOccurrenceResult, RecordFinishedOptions, RecordStartedOptions, };
|
|
7
7
|
export { CronStoreError };
|
|
8
8
|
export type { BuiltinScheduleDef };
|
|
9
|
-
export { BUILTIN_SCHEDULES, getProjectRoot };
|
|
9
|
+
export { BUILTIN_SCHEDULES, getProjectRoot, recognizeBuiltinRow };
|
|
10
10
|
export declare function getLocalTimestamp(): string;
|
|
11
11
|
export declare function logUsage(dirOrMessage?: string, ...args: string[]): void;
|
|
12
12
|
export declare function acquireWorkspaceLock(workspacePath: string, timeout?: number): ScheduleStoreLock;
|
|
@@ -19,6 +19,7 @@ export declare function loadSchedules(dir?: string): Schedule[];
|
|
|
19
19
|
export declare function saveSchedules(schedules: Schedule[], dir?: string): void;
|
|
20
20
|
export declare function getRemovedBuiltins(dir?: string): string[];
|
|
21
21
|
export declare function seedBuiltinSchedules(dir?: string): string[];
|
|
22
|
+
declare function recognizeBuiltinRow(schedule: Schedule): BuiltinScheduleDef | undefined;
|
|
22
23
|
export declare function acquireLock(timeout?: number, dir?: string): Promise<boolean>;
|
|
23
24
|
export declare function releaseLock(dir?: string): void;
|
|
24
25
|
export declare function releaseRunLock(scheduleId: string, leaseId: string, dir?: string): boolean;
|
|
@@ -37,6 +38,18 @@ export declare function startDaemonSafe(dir?: string, probe?: DaemonProcessProbe
|
|
|
37
38
|
export declare function ensureDaemonRunning(dir?: string, probe?: DaemonProcessProbe): void;
|
|
38
39
|
export declare function getDaemonStatus(dir?: string): DaemonStatus;
|
|
39
40
|
export declare function executeSchedule(schedule: Schedule, options?: ExecuteScheduleOptions): Promise<ExecuteScheduleOutcome>;
|
|
41
|
+
export declare function isHighFrequencyCron(cronExpr: string, now: Date, timezone?: string | null): boolean;
|
|
42
|
+
export declare const SCHEDULE_RUN_SWEEP_INTERVAL_MS: number;
|
|
43
|
+
export interface ScheduleRunSweepResult {
|
|
44
|
+
lost: number;
|
|
45
|
+
logsRemoved: number;
|
|
46
|
+
deleted: number;
|
|
47
|
+
tailsCleared: number;
|
|
48
|
+
}
|
|
49
|
+
export declare function sweepScheduleRuns(options?: {
|
|
50
|
+
dir?: string;
|
|
51
|
+
now?: Date;
|
|
52
|
+
}): ScheduleRunSweepResult;
|
|
40
53
|
export declare function getLocalMinuteKey(now: Date, timezone?: string | null): string;
|
|
41
54
|
export declare function buildOccurrenceKey(cronExpression: string, scheduledMinute: string): string;
|
|
42
55
|
export declare function daemonTick(dir?: string): Promise<void>;
|
package/dist/src/engine.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`;f.appendFileSync(sn(r),s)}function z(e){const n=F(e);if(!f.existsSync(n)){f.mkdirSync(n,{recursive:true})}}function se(e){try{return JSON.parse(f.readFileSync(e,"utf8"))}catch{return null}}const Sn=new Int32Array(new SharedArrayBuffer(4));function yn(){Atomics.wait(Sn,0,0,fn)}function ve(e){try{const n=JSON.parse(f.readFileSync(e,"utf8"));if(typeof n.token!=="string"||typeof n.pid!=="number"||typeof n.created_at!=="number"){return null}return n}catch{return null}}function Y(e,n=ke){const t=m.resolve(e);z(t);const r=Ie(t);const i=(0,Z.randomUUID)();const c=Date.now()+Math.max(0,n);const o={workspacePath:t,lockPath:r,token:i};while(true){const s={token:i,pid:process.pid,created_at:Date.now()};try{f.writeFileSync(r,JSON.stringify(s),{flag:"wx",mode:384});return o}catch(a){const d=a;if(d.code!=="EEXIST")throw a;const l=ve(r);if(l&&Date.now()-l.created_at>mn){W({...o,token:l.token});continue}if(Date.now()>=c){throw new O.CronStoreError("CRON_STORE_LOCK_TIMEOUT",`Timed out waiting for cron store lock: ${r}`,r)}yn()}}}function W(e){const n=ve(e.lockPath);if(!n||n.token!==e.token)return false;try{f.unlinkSync(e.lockPath);return true}catch(t){const r=t;if(r.code==="ENOENT")return false;throw t}}const ue=(0,x.findBuiltinById)("memory-debounce");function _n(e){if(!e.includes("/skills/memory-v2/memory-v2.js")){return e}return ue.buildCommand()}function hn(e=(0,x.getProjectRoot)()){const n=m.resolve(e);const t=m.join(n,"skills","cron",".cron-data.json");if(!f.existsSync(t)){return}const r=se(t);if(!Array.isArray(r)){return}const i=r.find(a=>a.name===ue.name);if(!i){return}const c=I(n);const o=c.list();if(o.some(a=>a.name===ue.name)){return}const s={...i,command:_n(i.command),updated_at:new Date().toISOString(),next_run:M(i.cron,i.timezone)};c.create(s)}function Re(e){if(e.includes("--overdrive")){console.warn("warning: --overdrive in cron command is ignored and may silently override --model")}}function de(e){if(e==="query")return"query";if(e==="command")return"command";return"execute"}function C(e){return{...e,...e.env?{env:{...e.env}}:{}}}function ne(e){let n;try{n=f.readFileSync(e,"utf8")}catch(r){const i=r;if(i.code==="ENOENT")return[];throw r}let t;try{t=JSON.parse(n)}catch(r){throw new O.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store is not valid JSON: ${e}`,e)}if(!Array.isArray(t)){throw new O.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store must contain a top-level array: ${e}`,e)}for(const r of t)wn(r,e);return t}const gn=["apps","skills","bundled"];function Q(e){return e.app!==void 0?e.app.enabled===true:e.enabled===true}function wn(e,n){if(typeof e!=="object"||e===null||Array.isArray(e)){throw new O.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has a row that is not an object: ${n}`,n)}const t=e;if(t.mode==="app"){throw new O.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has a row in the retired app mode: ${n}`,n)}if(t.app!==void 0&&!En(t.app)){throw new O.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has a malformed app binding: ${n}`,n)}if(t.last_error_code!==void 0&&(t.app===void 0||!(0,g.isAppScheduleCode)(t.last_error_code))){throw new O.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has an error code that is not a managed row's stable code: ${n}`,n)}}function Le(e){if(typeof e!=="object"||e===null)return false;const n=e;return typeof n.appId==="string"&&n.appId.length>0&&typeof n.actionId==="string"&&n.actionId.length>0&&typeof n.source==="string"&&gn.includes(n.source)}function En(e){return Le(e)&&typeof e.enabled==="boolean"}function Ne(e,n){if(n===void 0||n===null)delete e.last_error_code;else e.last_error_code=n}function le(e){return new O.CronStoreError("CRON_SCHEDULE_MANAGED",`CRON_SCHEDULE_MANAGED: ${e.id} is managed by app ${e.app?.appId??"(unknown)"}; change it from the App`)}function Dn(e,n){if(e.app===void 0)return;const t=Object.entries(n).every(([r,i])=>i===void 0||r==="enabled"&&i===false);if(!t)throw le(e)}function On(e){if(process.platform==="win32")return;try{const n=f.openSync(e,"r");try{f.fsyncSync(n)}finally{f.closeSync(n)}}catch{}}function $e(e,n){const t=m.dirname(e);const r=m.join(t,`.${m.basename(e)}.${process.pid}.${(0,Z.randomUUID)()}.tmp`);const i=JSON.stringify(n,null,2);let c;try{c=f.openSync(r,"wx",384);f.writeFileSync(c,i);f.fsyncSync(c);f.closeSync(c);c=void 0;f.renameSync(r,e);On(t)}finally{if(c!==void 0){try{f.closeSync(c)}catch{}}try{f.unlinkSync(r)}catch{}}}function G(e,n){const t=e.find(r=>r.id===n);if(!t){throw new O.CronStoreError("CRON_SCHEDULE_NOT_FOUND",`Schedule not found: ${n}`)}return t}function N(e,n){const t=Y(e);try{const r=ae(e);const i=ne(r);const c=n(i);$e(r,i);return c}finally{W(t)}}function I(e=w){const n=m.resolve(e);const t=F(n);const r=ae(n);const i=Ie(n);return{workspacePath:n,dataDir:t,schedulesFile:r,lockFile:i,list(){return ne(r).map(C)},get(c){const o=ne(r).find(s=>s.id===c);return o?C(o):void 0},create(c){if(c.app!==void 0){throw new O.CronStoreError("CRON_SCHEDULE_MANAGED","CRON_SCHEDULE_MANAGED: an app schedule is created only by the App path")}return N(n,o=>{if(o.some(s=>s.id===c.id)){throw new O.CronStoreError("CRON_SCHEDULE_EXISTS",`Schedule already exists: ${c.id}`)}o.push(C(c));return C(c)})},update(c,o){return N(n,s=>{const a=G(s,c);Dn(a,o);if(o.cron!==void 0)a.cron=o.cron;if(o.command!==void 0)a.command=o.command;if(o.mode!==void 0)a.mode=o.mode;if(o.enabled!==void 0){if(a.app!==void 0)a.app={...a.app,enabled:o.enabled};else a.enabled=o.enabled}if(o.name!==void 0)a.name=o.name;if(o.working_directory!==void 0)a.working_directory=o.working_directory;if(o.timezone!==void 0)a.timezone=o.timezone;if(o.timeout_ms!==void 0)a.timeout_ms=o.timeout_ms;if(o.allow_concurrent!==void 0)a.allow_concurrent=o.allow_concurrent;if(o.env!==void 0){if(o.env===null)delete a.env;else a.env={...o.env}}if(o.model!==void 0){if(o.model===null)delete a.model;else a.model=o.model}if(o.provider!==void 0){if(o.provider===null)delete a.provider;else a.provider=o.provider}a.updated_at=new Date().toISOString();a.next_run=a.app!==void 0&&!a.app.enabled?null:M(a.cron,a.timezone);return C(a)})},remove(c){return N(n,o=>{const s=o.findIndex(d=>d.id===c);if(s===-1){throw new O.CronStoreError("CRON_SCHEDULE_NOT_FOUND",`Schedule not found: ${c}`)}if(o[s].app!==void 0)throw le(o[s]);const[a]=o.splice(s,1);return C(a)})},toggle(c,o){return N(n,s=>{const a=G(s,c);const d=o??!Q(a);const l=new Date().toISOString();if(a.app!==void 0){if(d)throw le(a);a.app={...a.app,enabled:false};a.next_run=null;a.updated_at=l;return C(a)}a.enabled=d;a.updated_at=l;if(a.enabled){a.next_run=M(a.cron,a.timezone)}return C(a)})},setAppSchedule(c,o,s){if(!Le(c))throw new TypeError("setAppSchedule needs an owner with appId, actionId and source");return N(n,a=>{const d=new Date().toISOString();let l=a.find(_=>_.app?.appId===c.appId);const P=l?.app?.enabled===true;if(l===void 0){l={id:(0,g.generateId)("cron"),cron:o.cron,command:g.APP_SCHEDULE_INERT_COMMAND,mode:"command",enabled:false,name:o.name,working_directory:null,timezone:null,timeout_ms:o.timeout_ms,allow_concurrent:false,created_at:d,updated_at:d,run_count:0};a.push(l)}const D=s??l.app?.enabled??false;l.mode="command";l.command=g.APP_SCHEDULE_INERT_COMMAND;l.enabled=false;l.app={appId:c.appId,actionId:c.actionId,source:c.source,enabled:D};l.cron=o.cron;l.timeout_ms=o.timeout_ms;l.name=o.name;l.allow_concurrent=false;l.next_run=D?M(l.cron,l.timezone):null;l.updated_at=d;return{schedule:C(l),started:!P&&D}})},recordSkipped(c,o){if(o.errorCode!==null&&!(0,g.isAppScheduleCode)(o.errorCode)){throw new TypeError("recordSkipped needs a stable error code")}return N(n,s=>{const a=G(s,c);if(a.app===void 0)throw new TypeError("recordSkipped closes only a managed row");const d=o.finishedAt??new Date().toISOString();a.last_run=d;a.last_outcome=o.outcome;Ne(a,o.errorCode);a.updated_at=d;return C(a)})},removeAppSchedule(c){return N(n,o=>{const s=o.findIndex(d=>d.app?.appId===c);if(s===-1)return void 0;const[a]=o.splice(s,1);return C(a)})},claimOccurrence(c,o){return N(n,s=>{const a=G(s,typeof c==="string"?c:c.id);if(a.last_occurrence_key===o.occurrenceKey){return{claimed:false,schedule:C(a)}}const d=o.startedAt??new Date().toISOString();a.last_started_at=d;a.last_occurrence_key=o.occurrenceKey;a.updated_at=d;return{claimed:true,schedule:C(a)}})},recordStarted(c,o){return N(n,s=>{const a=G(s,typeof c==="string"?c:c.id);const d=typeof o==="string"?{startedAt:o}:o;const l=d?.startedAt??new Date().toISOString();a.last_started_at=l;if(d?.occurrenceKey!==void 0){a.last_occurrence_key=d.occurrenceKey}a.updated_at=l;return C(a)})},recordFinished(c,o){if(o?.errorCode!==void 0&&!(0,g.isAppScheduleCode)(o.errorCode)){throw new TypeError("recordFinished needs a stable error code")}return N(n,s=>{const a=G(s,typeof c==="string"?c:c.id);const d=o?.finishedAt??new Date().toISOString();a.last_run=d;a.run_count=(a.run_count||0)+1;a.next_run=o?.nextRun!==void 0?o.nextRun:M(a.cron,a.timezone);if(o?.outcome!==void 0)a.last_outcome=o.outcome;else if(o?.success!==void 0)a.last_outcome=o.success?"success":"failure";if(a.app!==void 0)Ne(a,o?.errorCode);a.updated_at=d;return C(a)})}}}function Cn(e){return I(e??w).list()}function In(e,n){const t=m.resolve(n??w);const r=Y(t);try{const i=ae(t);ne(i);$e(i,e.map(C))}finally{W(r)}}function be(e){const n=se(Ae(e));return{removed_builtins:Array.isArray(n?.removed_builtins)?n.removed_builtins:[]}}function An(e,n){z(n);const t=Ae(n);const r=`${t}.tmp`;f.writeFileSync(r,JSON.stringify(e,null,2));f.renameSync(r,t)}function Ue(e){return be(e).removed_builtins}function Pn(e,n){const t=be(n);if(!t.removed_builtins.includes(e)){t.removed_builtins.push(e);An(t,n)}}function kn(e){const n=I(e??w);const t=n.list();const r=new Set(t.map(o=>o.name));const i=new Set(Ue(e));const c=[];for(const o of x.BUILTIN_SCHEDULES){if(r.has(o.name))continue;if(i.has(o.builtin_id))continue;const s=new Date().toISOString();const a={id:(0,g.generateId)("cron"),cron:o.cron,command:o.buildCommand(),mode:o.mode,enabled:true,name:o.name,working_directory:null,timezone:null,timeout_ms:6e5,allow_concurrent:false,created_at:s,updated_at:s,run_count:0,next_run:M(o.cron,null)};n.create(a);r.add(o.name);c.push(o.builtin_id)}return c}const fe=new Map;async function Tn(e=ke,n){const t=m.resolve(n??w);try{fe.set(t,Y(t,e));return true}catch(r){if(r instanceof O.CronStoreError&&r.code==="CRON_STORE_LOCK_TIMEOUT")return false;throw r}}function vn(e){const n=m.resolve(e??w);const t=fe.get(n);if(!t)return;fe.delete(n);W(t)}function ee(e){return se(e)}function Rn(e,n){const t=m.dirname(e);const r=m.join(t,`.${m.basename(e)}.${process.pid}.${(0,Z.randomUUID)()}.tmp`);let i;try{i=f.openSync(r,"wx",384);f.writeFileSync(i,JSON.stringify(n));f.fsyncSync(i);f.closeSync(i);i=void 0;f.renameSync(r,e)}finally{if(i!==void 0){try{f.closeSync(i)}catch{}}try{f.unlinkSync(r)}catch{}}}function me(e,n,t){const r=Y(e);try{return t(Pe(n,e))}finally{W(r)}}function Ln(e){try{return Math.max(0,Date.now()-f.statSync(e).mtimeMs)}catch{return null}}function Nn(e,n){if(e.startTime!==null&&n.startTime!==null){return e.startTime===n.startTime}if(e.commandLine!==null&&n.commandLine!==null){return e.commandLine===n.commandLine}return null}function $n(e,n,t){if(e.phase!=="child"){const s=Ln(n);if(s===null)return false;const a=e.hostPid??e.pid;const d=Se(a);return d===false||s>t+Te}const r=e.childPid??e.pid;const i=Se(r);if(i===false)return true;if(i!==true)return false;if(!e.childIdentity)return false;const c=He(r);if(!c)return false;const o=Nn(e.childIdentity,c);if(o===false)return true;return false}function bn(e,n,t,r){const i=m.resolve(r??w);z(i);const c=Pe(e,i);const o=(0,Z.randomUUID)();const s=(0,Z.randomUUID)();const a={leaseId:o,ownerToken:s,phase:"admitting",hostPid:process.pid,pid:process.pid,taskId:n,startedAt:new Date().toISOString()};return me(i,e,()=>{for(let l=0;l<2;l++){try{f.writeFileSync(c,JSON.stringify(a),{flag:"wx",mode:384});return{acquired:true,lease:{scheduleId:e,workspacePath:i,lockFile:c,leaseId:o,ownerToken:s,taskId:n}}}catch(P){const D=P;if(D.code!=="EEXIST")throw D;const _=ee(c);if(!_){return{acquired:false,runningTaskId:"unknown",reason:"execution_lease"}}if($n(_,c,t)){const T=ee(c);if(T?.leaseId!==void 0&&T.leaseId!==_.leaseId){continue}try{f.unlinkSync(c)}catch{}continue}return{acquired:false,runningTaskId:_.taskId,reason:"execution_lease"}}}const d=ee(c);return{acquired:false,runningTaskId:d?.taskId??"unknown",reason:"execution_lease"}})}function Un(e,n,t){return me(e.workspacePath,e.scheduleId,r=>{const i=ee(r);if(!i||i.leaseId!==e.leaseId||i.ownerToken!==e.ownerToken){return false}Rn(r,{...i,phase:"child",pid:n,childPid:n,childIdentity:t});return true})}function Fe(e,n,t){const r=m.resolve(t??w);z(r);return me(r,e,i=>{const c=ee(i);if(!c||c.leaseId!==n)return false;try{f.unlinkSync(i);return true}catch(o){const s=o;if(s.code==="ENOENT")return false;throw o}})}const Fn={SUN:0,MON:1,TUE:2,WED:3,THU:4,FRI:5,SAT:6};const Mn={JAN:1,FEB:2,MAR:3,APR:4,MAY:5,JUN:6,JUL:7,AUG:8,SEP:9,OCT:10,NOV:11,DEC:12};function q(e,n){const t=e.toUpperCase();if(n===4){const r=Fn[t];if(r!==void 0)return r;const i=parseInt(e,10);return i===7?0:i}if(n===3){const r=Mn[t];if(r!==void 0)return r}return parseInt(e,10)}function jn(e,n,t){if(e==="*")return true;if(e.includes("/")){const r=e.indexOf("/");const i=e.slice(0,r);const c=parseInt(e.slice(r+1),10);if(isNaN(c)||c<=0)return false;if(i==="*"){return n%c===0}if(i.includes("-")){const s=i.indexOf("-");const a=q(i.slice(0,s),t);const d=q(i.slice(s+1),t);return n>=a&&n<=d&&(n-a)%c===0}const o=q(i,t);return n>=o&&(n-o)%c===0}if(e.includes("-")){const r=e.indexOf("-");const i=q(e.slice(0,r),t);const c=q(e.slice(r+1),t);if(i<=c){return n>=i&&n<=c}return n>=i||n<=c}return q(e,t)===n}function k(e,n,t){return e.split(",").some(r=>jn(r.trim(),n,t))}function V(e){try{Intl.DateTimeFormat("en-US",{timeZone:e});return true}catch{return false}}function Me(e,n,t){let r=n;if(t){if(!V(t)){console.error(`Invalid timezone: ${t}, skipping execution`);return false}else{const b=new Intl.DateTimeFormat("en-US",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false});const A=b.formatToParts(n);const E=S=>parseInt(A.find(h=>h.type===S)?.value??"0",10);const p=E("year");const $=E("month");const u=E("day");r={getMinutes:()=>E("minute"),getHours:()=>E("hour"),getDate:()=>E("day"),getMonth:()=>E("month")-1,getDay:()=>new Date(p,$-1,u).getDay()}}}const i=e.trim().split(/\s+/);if(i.length!==5){console.error(`Invalid cron expression: ${e}`);return false}const[c,o,s,a,d]=i;const l=r.getMinutes();const P=r.getHours();const D=r.getDate();const _=r.getMonth()+1;const T=r.getDay();return k(c,l,0)&&k(o,P,1)&&k(s,D,2)&&k(a,_,3)&&k(d,T,4)}function xn(e){const n=e.trim().split(/\s+/);if(n.length!==5)return e;const[t,r,i,c,o]=n;if(t==="0"&&r!=="*"&&i==="*"&&c==="*"&&o==="*"){return`Daily at ${r}:00`}if(t!=="*"&&r!=="*"&&i==="*"&&c==="*"&&o==="*"){return`Daily at ${r}:${t.padStart(2,"0")}`}if(e==="* * * * *"){return"Every minute"}if(t==="*/5"&&r==="*"&&i==="*"&&c==="*"&&o==="*"){return"Every 5 minutes"}return e}function pe(e,n){if(n&&V(n)){const t=new Intl.DateTimeFormat("en-US",{timeZone:n,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false,weekday:"short"});const r=t.formatToParts(e);const i=s=>parseInt(r.find(a=>a.type===s)?.value??"0",10);const c=r.find(s=>s.type==="weekday")?.value??"";const o={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};return{minute:i("minute"),hour:i("hour"),day:i("day"),month:i("month"),weekday:o[c]??e.getDay()}}return{minute:e.getMinutes(),hour:e.getHours(),day:e.getDate(),month:e.getMonth()+1,weekday:e.getDay()}}function Hn(e,n){const t=e.toLocaleString("en-US",{timeZone:"UTC"});const r=e.toLocaleString("en-US",{timeZone:n});return(new Date(r).getTime()-new Date(t).getTime())/6e4}function M(e,n){const t=e.trim().split(/\s+/);if(t.length!==5)return null;const[r,i,c,o,s]=t;const a=[];for(let _=0;_<24;_++){if(k(i,_,1))a.push(_)}const d=[];for(let _=0;_<60;_++){if(k(r,_,0))d.push(_)}if(a.length===0||d.length===0)return null;const l=new Date;const P=n&&V(n);const D=pe(l,n);for(let _=0;_<=366;_++){const T=new Date(l.getTime()+_*864e5);const b=pe(T,n);if(!k(o,b.month,3))continue;if(!k(c,b.day,2))continue;if(!k(s,b.weekday,4))continue;for(const A of a){for(const E of d){if(_===0&&(A<D.hour||A===D.hour&&E<=D.minute)){continue}let p;if(P){const u=Hn(T,n);p=new Date(T);p.setUTCHours(A-Math.floor(u/60),E-u%60,0,0)}else{p=new Date(T);p.setHours(A,E,0,0)}if(p.getTime()<=l.getTime())continue;const $=pe(p,n);if($.hour===A&&$.minute===E&&k(c,$.day,2)&&k(o,$.month,3)&&k(s,$.weekday,4)){return p.toISOString()}}}}return null}function B(e){try{const n=f.readFileSync(K(e),"utf8").trim();if(!/^\d+$/.test(n))return null;const t=Number(n);return Number.isSafeInteger(t)&&t>0?t:null}catch{return null}}function je(e,n){z(n);f.writeFileSync(K(n),`${e}
|
|
3
|
-
`)}function te(e){try{f.unlinkSync(K(e))}catch{}}function Se(e){try{process.kill(e,0);return true}catch(n){const t=n;return t.code==="ESRCH"?false:"unknown"}}function xe(e){try{const n=process.platform==="win32"?(0,j.execFileSync)("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}):(0,j.execFileSync)("ps",["-ww","-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return n.trim()||null}catch{return null}}function zn(e){try{const n=process.platform==="win32"?(0,j.execFileSync)("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CreationDate.ToUniversalTime().ToString("o")`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}):(0,j.execFileSync)("ps",["-p",String(e),"-o","lstart="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return n.trim()||null}catch{return null}}function He(e){const n={commandLine:xe(e),startTime:zn(e)};return n.commandLine!==null||n.startTime!==null?n:null}const J={isAlive:Se,getCommandLine:xe};function ze(e){const n=e.replace(/\\/g,"/");return process.platform==="win32"?n.toLowerCase():n}function Bn(){try{const e=ze(Be()).split("/").filter(Boolean);const n=e.slice(-3).join("/");return n||null}catch{return null}}function Kn(e){if(!e?.trim())return"unknown";const n=Bn();if(!n)return"unknown";const t=ze(e);return t.includes("daemon --foreground")&&t.includes(n)?"running":"stale"}function Be(){const e=[m.join(__dirname,"..","cli.js"),m.join(__dirname,"..","dist","cli.js")];const n=e.find(t=>f.existsSync(t));if(n){return n}throw new Error(`Cron CLI entrypoint not found: ${e[0]}`)}function re(e,n=J){const t=B(e);if(!t){te(e);return"stale"}let r;try{r=n.isAlive(t)}catch{r="unknown"}if(!r){te(e);return"stale"}let i;try{i=n.getCommandLine(t)}catch{return"unknown"}const c=Kn(i);if(c==="stale"){te(e)}return c}function ye(e,n=J){return re(e,n)==="running"}function Ke(e,n=j.spawn){if((0,g.isDurablyQuiescing)()){throw new Error("Cannot start cron daemon: a desktop update is draining active work")}z(e);const t=Be();const r={...process.env};if(process.versions.electron){r.ELECTRON_RUN_AS_NODE="1"}const i=n(process.execPath,[t,"daemon","--foreground"],{cwd:e||void 0,detached:true,stdio:"ignore",windowsHide:true,env:r});if(!i.pid){throw new Error("Failed to start daemon: no PID returned")}i.unref();je(i.pid,e);return i.pid}function Wn(e,n=J){const t=re(e,n);if(t==="running"){const r=B(e);if(r)return r;throw new Error("Daemon is already running")}if(t==="unknown"){const r=B(e);throw new Error(`Unable to determine cron daemon liveness (pid=${r??"unknown"}, pidFile=${K(e)}); refusing to start`)}return Ke(e,n.spawnImpl)}function Gn(e,n=J){if(re(e,n)!=="running")return false;const t=B(e);if(!t)return false;process.kill(t,"SIGTERM");return true}function We(e,n=J){const t=re(e,n);if(t==="running"){return{started:false}}if(t==="unknown"){return{started:false,error:`Unable to determine cron daemon liveness (pid=${B(e)??"unknown"}, pidFile=${K(e)}); refusing to start`}}try{const r=Ke(e,n.spawnImpl);return{started:true,pid:r}}catch(r){const i=r;return{started:false,error:i.message}}}function qn(e,n=J){if(ye(e,n))return;console.log("\u26A1 Cron daemon is not running; starting it automatically...");const t=We(e,n);if(!t.started){console.error("Failed to auto-start daemon:",t.error);process.exit(1)}}function Vn(e){const n=I(e??w).list();const t=n.filter(s=>Q(s)).length;const r=ye(e);const i=r?B(e):null;let c=null;const o=K(e);if(r&&f.existsSync(o)){try{c=f.statSync(o).mtime.toISOString()}catch{c=null}}return{running:r,pid:r?i:null,started_at:c,schedules:{total:n.length,enabled:t}}}async function Ge(e,n){const t=n?.dir;const r=m.resolve(t??w);const i=n?.trigger??"cron";const c=e.timeout_ms||6e5;const o=(0,g.generateId)("tsk");if(e.app!==void 0){if(e.mode!=="command"||e.command!==g.APP_SCHEDULE_INERT_COMMAND){return{status:"blocked",reason:"APP_ROW_INVALID"}}if(n?.launchApp===void 0)return{status:"blocked",reason:"APP_LAUNCHER_UNAVAILABLE"}}else{if(!rt(e.mode))return{status:"blocked",reason:"MODE_UNSUPPORTED"};if(i==="app_enable")return{status:"blocked",reason:"TRIGGER_UNSUPPORTED"}}let s;if(!e.allow_concurrent){const u=bn(e.id,o,c,t);if(!u.acquired){console.log(`[${y()}] Schedule ${e.id} already running (task ${u.runningTaskId}), skipping`);return{status:"conflict",runningTaskId:u.runningTaskId,reason:u.reason}}s=u.lease}const a=()=>{if(s){Fe(e.id,s.leaseId,t);s=void 0}dn(o)};if(!un(o,e.id,c)){console.log(`[${y()}] Schedule ${e.id} blocked: could not durably record the update-admission reservation`);a();return{status:"blocked",reason:"ADMISSION_UNKNOWN"}}if((0,g.isDurablyQuiescing)()){console.log(`[${y()}] Schedule ${e.id} blocked: a desktop update is draining active work`);a();return{status:"blocked",reason:"UPDATE_QUIESCING"}}try{const u=I(r);const S=new Date().toISOString();if(n?.occurrenceKey!==void 0){const h=u.claimOccurrence(e.id,{occurrenceKey:n.occurrenceKey,startedAt:S});if(!h.claimed){a();console.log(`[${y()}] Schedule ${e.id} occurrence ${n.occurrenceKey} already claimed, skipping`);return{status:"conflict",runningTaskId:"",reason:"occurrence_claim"}}}else{if(u.get(e.id)){u.recordStarted(e.id,{startedAt:S})}}}catch(u){a();throw u}let d;let l;if(e.app!==void 0){let u;try{u=await n.launchApp(e);if(u.kind!=="spawn")it(r,e,u)}catch(S){he(r,e.id,"APP_LAUNCH_FAILED");a();throw S}if(u.kind!=="spawn"){a();const S=u.kind==="refresh"?"APP_SCHEDULE_REFRESHED":u.code;console.log(`[${y()}] Schedule ${e.id} app row ${u.kind}: ${S}`);return{status:"skipped",reason:S,lifecycle:u.kind}}d=u.child;l=typeof u.settle==="function"?u.settle:void 0}const P=e.working_directory||n?.dir||(0,x.getProjectRoot)();const D=e.mode;const _=D==="execute"?"x":"q";const T=n?.overrides?.model??e.model;const b=n?.overrides?.provider??e.provider;console.log(`[${y()}] Executing schedule ${e.id}: ${e.name??e.cron} (task ${o})`);console.log(`[${y()}] Command: ${e.command}`);const A=(0,g.withoutCrewxRootContext)({...process.env,...e.env,CREWX_TRACE_ID:o});delete A["CLAUDECODE"];if(!e.env||!("CREWX_CONFIG"in e.env)){delete A["CREWX_CONFIG"]}A["CREWX_WORKSPACE"]=P;const E=[_,e.command];if(T){E.push("--model",T)}if(D!=="command"&&b){E.push("--provider",b)}E.push("--metadata",JSON.stringify({trigger:i,schedule_id:e.id}));let p;try{if(d!==void 0){p=d;if(p.pid===void 0)throw new Error("App launcher returned a child that did not start")}else if(e.app!==void 0){throw new Error("managed row has no launched child")}else if(D==="command"){p=(0,j.spawn)("sh",["-c",e.command],{cwd:P,stdio:"ignore",windowsHide:true,detached:true,env:A})}else{const u=(0,g.resolveCrewxExecutable)({env:A,cwd:P});if(!u.ok){const R=new Error((0,g.formatCrewxExecutableFailure)(u));Object.assign(R,{code:"CLI_UNRESOLVABLE"});throw R}const S=(0,g.createCrewxChildInvocation)(u,{baseEnv:A});const h=(0,g.resolveWindowsSpawnProgram)({command:S.command,env:S.env,cwd:P,packageName:"crewx",allowShellFallback:true});const v=(0,g.materializeWindowsSpawnProgram)(h,[...S.args,...E]);p=(0,j.spawn)(v.command,v.argv,{cwd:P,stdio:"ignore",windowsHide:v.windowsHide,detached:true,env:S.env,shell:v.shell??false})}if(d===void 0){await new Promise((u,S)=>{p.once("spawn",()=>u());p.once("error",h=>S(h))})}}catch(u){const S=u;console.error(`[${y()}] Schedule ${e.id} failed to spawn: ${S.message}`);if(e.app!==void 0)he(r,e.id,"APP_SPAWN_FAILED");a();throw S}if(s&&p.pid){const u=Un(s,p.pid,He(p.pid));if(!u){const S=new Error("Cron execution lease was replaced before child ownership was established");console.error(`[${y()}] Schedule ${e.id} failed to hand off its execution lease: ${S.message}`);try{p.kill("SIGTERM")}catch{}if(e.app!==void 0)he(r,e.id,"APP_HANDOFF_FAILED");a();throw S}}p.unref();const $=new Promise(u=>{let S=false;let h=false;let v;let R;let Ee=false;const De=()=>{if(R!==void 0||!p.stdout&&!p.stderr)return;R=setTimeout(()=>{Ee=true;p.stdout?.destroy();p.stderr?.destroy()},Xn);if(typeof R==="object"&&R!==null&&"unref"in R){R.unref()}};if(e.app!==void 0){p.once("exit",De);if(p.exitCode!==null||p.signalCode!==null)De()}const Oe=setTimeout(()=>{S=true;console.log(`[${y()}] Schedule ${e.id} timeout, killing process`);try{p.kill("SIGTERM")}catch(L){const ie=L;console.error(`Failed to kill process: ${ie.message}`)}v=setTimeout(()=>{try{p.kill("SIGKILL")}catch{}},Te);if(typeof v==="object"&&v!==null&&"unref"in v){v.unref()}if(!h){h=true;u({success:false,error:"Timeout"})}},c);p.on("close",(L,ie)=>{clearTimeout(Oe);if(v)clearTimeout(v);if(R)clearTimeout(R);a();const U=e.app!==void 0&&!S?Zn({code:L,signal:ie},l,Ee):void 0;const Je=new Date().toISOString();const Xe=S?"timeout":U!==void 0?U.outcome:L===0?"success":"failure";const Ze=e.app===void 0?void 0:S?Jn:U?.outcome==="failure"?U.code:void 0;try{I(r).recordFinished(e.id,{finishedAt:Je,outcome:Xe,errorCode:Ze})}catch(ce){const Ye=ce;if(!(ce instanceof O.CronStoreError&&ce.code==="CRON_SCHEDULE_NOT_FOUND")){console.error(`[${y()}] Failed to record schedule ${e.id} completion: ${Ye.message}`)}}if(S){console.log(`[${y()}] Schedule ${e.id} terminated after timeout`);if(!h){h=true;u({success:false,error:"Timeout"})}}else if(U!==void 0){if(U.outcome==="success"){console.log(`[${y()}] Schedule ${e.id} completed successfully`);if(!h){h=true;u({success:true})}}else{console.log(`[${y()}] Schedule ${e.id} failed with ${U.code}`);if(!h){h=true;u({success:false,error:U.code})}}}else if(L===0){console.log(`[${y()}] Schedule ${e.id} completed successfully`);if(!h){h=true;u({success:true})}}else{console.log(`[${y()}] Schedule ${e.id} failed with code ${L}`);if(!h){h=true;u({success:false,error:`Exit code: ${L}`})}}});p.on("error",L=>{clearTimeout(Oe);console.error(`[${y()}] Schedule ${e.id} error: ${L.message}`);if(!h){h=true;u({success:false,error:L.message})}})});return{status:"running",taskId:o,done:$}}const Jn="APP_TIMEOUT";const Xn=5e3;function Zn(e,n,t){if(e.signal!==null)return X("APP_SIGNALED");if(e.code!==0)return X("APP_EXIT_NONZERO");if(t)return X("APP_STDIO_NOT_DRAINED");if(n===void 0)return X("APP_VERDICT_FAILED");let r;try{r=n(e)}catch{return X("APP_VERDICT_FAILED")}return et(r)}const Yn=64;const Qn=3;function et(e){try{if(typeof e==="object"&&e!==null&&!Array.isArray(e)&&typeof e.then!=="function"){const n=Object.keys(e);const{outcome:t,code:r}=e;if(t==="success"&&n.length===1)return{outcome:"success"};if(t==="failure"&&n.length===2&&n.includes("code")){return(0,g.isAppScheduleCode)(r)?{outcome:"failure",code:r}:_e(e,"APP_OUTPUT_INVALID")}}return _e(e,"APP_VERDICT_FAILED")}catch{return _e(e,"APP_VERDICT_FAILED")}}function _e(e,n){nt(e);return X(n)}const oe=()=>void 0;function nt(e){const n=[{value:e,depth:0}];for(let t=0;t<Yn&&n.length>0;t+=1){const{value:r,depth:i}=n.shift();if(typeof r!=="object"&&typeof r!=="function"||r===null)continue;try{if(Object.getPrototypeOf(r)===Promise.prototype){Promise.prototype.then.call(r,oe,oe);continue}const c=r.then;if(typeof c==="function"){c.call(r,oe,oe);continue}if(i<Qn){for(const o of Object.keys(r)){const s=Object.getOwnPropertyDescriptor(r,o);if(s!==void 0&&"value"in s)n.push({value:s.value,depth:i+1})}}}catch{}}}function X(e){return{outcome:"failure",code:e}}const tt=["query","execute","command"];function rt(e){return tt.includes(e)}function ot(e){return{appId:e.appId,actionId:e.actionId,source:e.source}}function it(e,n,t){const r=I(e);const i=ot(n.app);const c={cron:n.cron,timeout_ms:n.timeout_ms,name:n.name};switch(t.kind){case"skip":{const o=r.setAppSchedule(i,c).schedule;r.recordSkipped(o.id,{outcome:t.code,errorCode:t.code});return}case"disable":{const o=r.setAppSchedule(i,c,false).schedule;r.recordSkipped(o.id,{outcome:t.code,errorCode:t.code});return}case"remove":r.removeAppSchedule(i.appId);return;case"refresh":{const o=r.setAppSchedule(t.owner,t.template).schedule;r.recordSkipped(o.id,{outcome:"APP_SCHEDULE_REFRESHED",errorCode:null});return}}}function he(e,n,t){try{I(e).recordSkipped(n,{outcome:t,errorCode:t})}catch(r){if(r instanceof O.CronStoreError&&r.code==="CRON_SCHEDULE_NOT_FOUND")return;console.error(`[${y()}] Schedule ${n} could not record its ${t} outcome: ${r.message}`)}}function qe(e,n){if(!n||!V(n)){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")} ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}const t=new Intl.DateTimeFormat("en-CA",{timeZone:n,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false});return t.format(e)}function Ve(e,n){return`${e.trim()}|${n}`}async function ge(e){if((0,g.isDurablyQuiescing)()){console.log(`[${y()}] Daemon tick skipped: a desktop update is draining active work`);return}const n=new Date;const t=I(e??w).list();const r=t.filter(i=>Q(i));if(r.length===0){return}for(const i of r){if(Me(i.cron,n,i.timezone)){const c=qe(n,i.timezone);const o=Ve(i.cron,c);try{await Ge(i,{dir:e,occurrenceKey:o})}catch(s){const a=s;console.error(`[${y()}] Schedule ${i.id} failed to spawn: ${a.message}`)}}}}var we=require("./runtime");Object.defineProperty(exports,"createCronRuntime",{enumerable:true,get:function(){return we.createCronRuntime}});Object.defineProperty(exports,"CRON_RUNTIME_PROCESS_LEASE_FILENAME",{enumerable:true,get:function(){return we.CRON_RUNTIME_PROCESS_LEASE_FILENAME}});Object.defineProperty(exports,"scheduledPeriodicAvailability",{enumerable:true,get:function(){return we.scheduledPeriodicAvailability}});function ct(e){je(process.pid,e);let n=false;const t=()=>{if(n)return;n=true;const c=B(e);if(c===process.pid){te(e)}};process.on("SIGTERM",()=>{t();process.exit(0)});process.on("SIGINT",()=>{t();process.exit(0)});process.on("exit",t);console.log(`[${y()}] Cron daemon starting in foreground mode`);console.log(`[${y()}] Check interval: 1 minute`);console.log(`[${y()}] Press Ctrl+C to stop
|
|
4
|
-
`);const r=
|
|
5
|
-
`);void
|
|
1
|
+
"use strict";var Rn=exports&&exports.__createBinding||(Object.create?(function(e,n,t,r){if(r===void 0)r=t;var i=Object.getOwnPropertyDescriptor(n,t);if(!i||("get"in i?!n.__esModule:i.writable||i.configurable)){i={enumerable:true,get:function(){return n[t]}}}Object.defineProperty(e,r,i)}):(function(e,n,t,r){if(r===void 0)r=t;e[r]=n[t]}));var On=exports&&exports.__setModuleDefault||(Object.create?(function(e,n){Object.defineProperty(e,"default",{enumerable:true,value:n})}):function(e,n){e["default"]=n});var Ve=exports&&exports.__importStar||(function(){var e=function(n){e=Object.getOwnPropertyNames||function(t){var r=[];for(var i in t)if(Object.prototype.hasOwnProperty.call(t,i))r[r.length]=i;return r};return e(n)};return function(n){if(n&&n.__esModule)return n;var t={};if(n!=null){for(var r=e(n),i=0;i<r.length;i++)if(r[i]!=="default")Rn(t,n,r[i])}On(t,n);return t}})();Object.defineProperty(exports,"__esModule",{value:true});exports.DATA_PATHS=exports.scheduledPeriodicAvailability=exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME=exports.createCronRuntime=exports.SCHEDULE_RUN_SWEEP_INTERVAL_MS=exports.getProjectRoot=exports.BUILTIN_SCHEDULES=exports.CronStoreError=void 0;exports.recognizeBuiltinRow=ye;exports.getLocalTimestamp=S;exports.logUsage=jn;exports.acquireWorkspaceLock=ne;exports.releaseWorkspaceLock=Z;exports.migrateLegacyMemoryDebounceSchedule=zn;exports.normalizeMode=Oe;exports.effectiveEnabled=me;exports.createScheduleStore=A;exports.loadSchedules=tn;exports.saveSchedules=Zn;exports.getRemovedBuiltins=on;exports.seedBuiltinSchedules=et;exports.acquireLock=tt;exports.releaseLock=rt;exports.releaseRunLock=sn;exports.shouldRunNow=Ne;exports.describeCron=ft;exports.calculateNextRun=K;exports.isDaemonRunning=be;exports.startDaemon=_t;exports.stopDaemon=gt;exports.startDaemonSafe=_n;exports.ensureDaemonRunning=ht;exports.getDaemonStatus=wt;exports.executeSchedule=wn;exports.isHighFrequencyCron=En;exports.sweepScheduleRuns=kt;exports.getLocalMinuteKey=In;exports.buildOccurrenceKey=Cn;exports.daemonTick=xe;exports.runDaemonForeground=Ht;exports.addSchedule=Wt;exports.removeSchedule=Bt;exports.enableSchedule=zt;exports.disableSchedule=Kt;exports.updateSchedule=Gt;const V=require("child_process");const le=require("crypto");const m=Ve(require("path"));const f=Ve(require("fs"));const C=require("./types");Object.defineProperty(exports,"CronStoreError",{enumerable:true,get:function(){return C.CronStoreError}});const p=require("@crewx/sdk");const F=require("./builtins");Object.defineProperty(exports,"BUILTIN_SCHEDULES",{enumerable:true,get:function(){return F.BUILTIN_SCHEDULES}});Object.defineProperty(exports,"getProjectRoot",{enumerable:true,get:function(){return F.getProjectRoot}});const k=require("./run-record");const w=m.resolve(process.cwd());const J=m.join(w,".crewx");const Tn=m.join(J,".cron-data.json");const kn=m.join(J,".cron-daemon.log");const Pn=m.join(J,".cron-data.json.lock");const Ln=m.join(J,"cron-usage.log");const Nn=m.join(J,".cron-daemon.pid");const vn=m.join(J,".cron-builtins.json");function z(e){return m.join(m.resolve(e??w),".crewx")}function fe(e){return m.join(z(e),".cron-data.json")}function Je(e){return m.join(z(e),".cron-data.json.lock")}function $n(e){return m.join(z(e),"cron-usage.log")}function ee(e){return m.join(z(e),".cron-daemon.pid")}function Xe(e){return m.join(z(e),".cron-builtins.json")}function bn(e,n,t,r){const i=(0,p.reserveUpdateAdmission)(e,n,t,r);if(!i){console.error(`[${S()}] Failed to record update-admission reservation for task ${e}`)}return i}function Un(e){(0,p.releaseUpdateAdmissionReservation)(e)}function Ce(e,n){return m.join(z(n),`.cron-run-${e}.lock`)}const Fn=60*1e3;const Ze=5e3;const Mn=25;const xn=3e4;const De=5e3;function S(){const e=new Date;const n=e.getFullYear();const t=String(e.getMonth()+1).padStart(2,"0");const r=String(e.getDate()).padStart(2,"0");const i=String(e.getHours()).padStart(2,"0");const c=String(e.getMinutes()).padStart(2,"0");const o=String(e.getSeconds()).padStart(2,"0");return`${n}-${t}-${r} ${i}:${c}:${o}`}function jn(e,...n){const t=a=>a!==void 0&&(a==="."||a===".."||m.isAbsolute(a)||a.includes(m.sep)||a.includes("/")||a.includes("\\")||a.endsWith(".crewx")||(()=>{try{return f.statSync(a).isDirectory()}catch{return false}})());let r;let i;if(n.length>0&&(e===void 0||t(e))){r=e;i=n}else if(n.length===0&&t(e)){r=e;i=[]}else if(n.length===1&&t(n[0])){r=n[0];i=e===void 0?[]:[e]}else{r=void 0;i=e===void 0?n:[e,...n]}X(r);const c=S();const o=i.join(" ");const s=`${c} | [cron] ${o}
|
|
2
|
+
`;f.appendFileSync($n(r),s)}function X(e){const n=z(e);if(!f.existsSync(n)){f.mkdirSync(n,{recursive:true})}}function Ae(e){try{return JSON.parse(f.readFileSync(e,"utf8"))}catch{return null}}const Hn=new Int32Array(new SharedArrayBuffer(4));function Wn(){Atomics.wait(Hn,0,0,Mn)}function Ye(e){try{const n=JSON.parse(f.readFileSync(e,"utf8"));if(typeof n.token!=="string"||typeof n.pid!=="number"||typeof n.created_at!=="number"){return null}return n}catch{return null}}function ne(e,n=Ze){const t=m.resolve(e);X(t);const r=Je(t);const i=(0,le.randomUUID)();const c=Date.now()+Math.max(0,n);const o={workspacePath:t,lockPath:r,token:i};while(true){const s={token:i,pid:process.pid,created_at:Date.now()};try{f.writeFileSync(r,JSON.stringify(s),{flag:"wx",mode:384});return o}catch(a){const l=a;if(l.code!=="EEXIST")throw a;const u=Ye(r);if(u&&Date.now()-u.created_at>xn){Z({...o,token:u.token});continue}if(Date.now()>=c){throw new C.CronStoreError("CRON_STORE_LOCK_TIMEOUT",`Timed out waiting for cron store lock: ${r}`,r)}Wn()}}}function Z(e){const n=Ye(e.lockPath);if(!n||n.token!==e.token)return false;try{f.unlinkSync(e.lockPath);return true}catch(t){const r=t;if(r.code==="ENOENT")return false;throw t}}const Re=(0,F.findBuiltinById)("memory-debounce");function Bn(e){if(!e.includes("/skills/memory-v2/memory-v2.js")){return e}return Re.buildCommand()}function zn(e=(0,F.getProjectRoot)()){const n=m.resolve(e);const t=m.join(n,"skills","cron",".cron-data.json");if(!f.existsSync(t)){return}const r=Ae(t);if(!Array.isArray(r)){return}const i=r.find(a=>a.name===Re.name);if(!i){return}const c=A(n);const o=c.list();if(o.some(a=>a.name===Re.name)){return}const s={...i,command:Bn(i.command),updated_at:new Date().toISOString(),next_run:K(i.cron,i.timezone)};c.create(s)}function Qe(e){if(e.includes("--overdrive")){console.warn("warning: --overdrive in cron command is ignored and may silently override --model")}}function Oe(e){if(e==="query")return"query";if(e==="command")return"command";return"execute"}function D(e){return{...e,...e.env?{env:{...e.env}}:{}}}function te(e){let n;try{n=f.readFileSync(e,"utf8")}catch(r){const i=r;if(i.code==="ENOENT")return[];throw r}let t;try{t=JSON.parse(n)}catch(r){throw new C.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store is not valid JSON: ${e}`,e)}if(!Array.isArray(t)){throw new C.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store must contain a top-level array: ${e}`,e)}for(const r of t)Gn(r,e);return t}const Kn=["apps","skills","bundled"];function me(e){return e.app!==void 0?e.app.enabled===true:e.enabled===true}function Gn(e,n){if(typeof e!=="object"||e===null||Array.isArray(e)){throw new C.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has a row that is not an object: ${n}`,n)}const t=e;if(t.mode==="app"){throw new C.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has a row in the retired app mode: ${n}`,n)}if(t.app!==void 0&&!qn(t.app)){throw new C.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has a malformed app binding: ${n}`,n)}if(t.last_error_code!==void 0&&(t.app===void 0||!(0,p.isAppScheduleCode)(t.last_error_code))){throw new C.CronStoreError("CRON_STORE_CORRUPT",`Cron schedule store has an error code that is not a managed row's stable code: ${n}`,n)}}function en(e){if(typeof e!=="object"||e===null)return false;const n=e;return typeof n.appId==="string"&&n.appId.length>0&&typeof n.actionId==="string"&&n.actionId.length>0&&typeof n.source==="string"&&Kn.includes(n.source)}function qn(e){return en(e)&&typeof e.enabled==="boolean"}function nn(e,n){if(n===void 0||n===null)delete e.last_error_code;else e.last_error_code=n}function Te(e){return new C.CronStoreError("CRON_SCHEDULE_MANAGED",`CRON_SCHEDULE_MANAGED: ${e.id} is managed by app ${e.app?.appId??"(unknown)"}; change it from the App`)}function Vn(e,n){if(e.app===void 0)return;const t=Object.entries(n).every(([r,i])=>i===void 0||r==="enabled"&&i===false);if(!t)throw Te(e)}function Jn(e){if(process.platform==="win32")return;try{const n=f.openSync(e,"r");try{f.fsyncSync(n)}finally{f.closeSync(n)}}catch{}}function ke(e,n){const t=m.dirname(e);const r=m.join(t,`.${m.basename(e)}.${process.pid}.${(0,le.randomUUID)()}.tmp`);const i=JSON.stringify(n,null,2);let c;try{c=f.openSync(r,"wx",384);f.writeFileSync(c,i);f.fsyncSync(c);f.closeSync(c);c=void 0;f.renameSync(r,e);Jn(t)}finally{if(c!==void 0){try{f.closeSync(c)}catch{}}try{f.unlinkSync(r)}catch{}}}function re(e,n){const t=e.find(r=>r.id===n);if(!t){throw new C.CronStoreError("CRON_SCHEDULE_NOT_FOUND",`Schedule not found: ${n}`)}return t}function M(e,n){const t=ne(e);try{const r=fe(e);const i=te(r);const c=n(i);ke(r,i);return c}finally{Z(t)}}function Xn(e,n){const t=ne(e);try{const r=fe(e);const i=te(r);const c=n(i);if(c)ke(r,i);return c}finally{Z(t)}}function A(e=w){const n=m.resolve(e);const t=z(n);const r=fe(n);const i=Je(n);return{workspacePath:n,dataDir:t,schedulesFile:r,lockFile:i,list(){return te(r).map(D)},get(c){const o=te(r).find(s=>s.id===c);return o?D(o):void 0},create(c){if(c.app!==void 0){throw new C.CronStoreError("CRON_SCHEDULE_MANAGED","CRON_SCHEDULE_MANAGED: an app schedule is created only by the App path")}return M(n,o=>{if(o.some(s=>s.id===c.id)){throw new C.CronStoreError("CRON_SCHEDULE_EXISTS",`Schedule already exists: ${c.id}`)}o.push(D(c));return D(c)})},update(c,o){return M(n,s=>{const a=re(s,c);Vn(a,o);if(o.cron!==void 0)a.cron=o.cron;if(o.command!==void 0)a.command=o.command;if(o.mode!==void 0)a.mode=o.mode;if(o.enabled!==void 0){if(a.app!==void 0)a.app={...a.app,enabled:o.enabled};else a.enabled=o.enabled}if(o.name!==void 0)a.name=o.name;if(o.working_directory!==void 0)a.working_directory=o.working_directory;if(o.timezone!==void 0)a.timezone=o.timezone;if(o.timeout_ms!==void 0)a.timeout_ms=o.timeout_ms;if(o.allow_concurrent!==void 0)a.allow_concurrent=o.allow_concurrent;if(o.env!==void 0){if(o.env===null)delete a.env;else a.env={...o.env}}if(o.model!==void 0){if(o.model===null)delete a.model;else a.model=o.model}if(o.provider!==void 0){if(o.provider===null)delete a.provider;else a.provider=o.provider}a.updated_at=new Date().toISOString();a.next_run=a.app!==void 0&&!a.app.enabled?null:K(a.cron,a.timezone);return D(a)})},remove(c){return M(n,o=>{const s=o.findIndex(l=>l.id===c);if(s===-1){throw new C.CronStoreError("CRON_SCHEDULE_NOT_FOUND",`Schedule not found: ${c}`)}if(o[s].app!==void 0)throw Te(o[s]);const[a]=o.splice(s,1);return D(a)})},toggle(c,o){return M(n,s=>{const a=re(s,c);const l=o??!me(a);const u=new Date().toISOString();if(a.app!==void 0){if(l)throw Te(a);a.app={...a.app,enabled:false};a.next_run=null;a.updated_at=u;return D(a)}a.enabled=l;a.updated_at=u;if(a.enabled){a.next_run=K(a.cron,a.timezone)}return D(a)})},setAppSchedule(c,o,s){if(!en(c))throw new TypeError("setAppSchedule needs an owner with appId, actionId and source");return M(n,a=>{const l=new Date().toISOString();let u=a.find(y=>y.app?.appId===c.appId);const R=u?.app?.enabled===true;if(u===void 0){u={id:(0,p.generateId)("cron"),cron:o.cron,command:p.APP_SCHEDULE_INERT_COMMAND,mode:"command",enabled:false,name:o.name,working_directory:null,timezone:null,timeout_ms:o.timeout_ms,allow_concurrent:false,created_at:l,updated_at:l,run_count:0};a.push(u)}const E=s??u.app?.enabled??false;u.mode="command";u.command=p.APP_SCHEDULE_INERT_COMMAND;u.enabled=false;u.app={appId:c.appId,actionId:c.actionId,source:c.source,enabled:E};u.cron=o.cron;u.timeout_ms=o.timeout_ms;u.name=o.name;u.allow_concurrent=false;u.next_run=E?K(u.cron,u.timezone):null;u.updated_at=l;return{schedule:D(u),started:!R&&E}})},recordSkipped(c,o){if(o.errorCode!==null&&!(0,p.isAppScheduleCode)(o.errorCode)){throw new TypeError("recordSkipped needs a stable error code")}return M(n,s=>{const a=re(s,c);if(a.app===void 0)throw new TypeError("recordSkipped closes only a managed row");const l=o.finishedAt??new Date().toISOString();a.last_run=l;a.last_outcome=o.outcome;nn(a,o.errorCode);a.updated_at=l;return D(a)})},removeAppSchedule(c){return M(n,o=>{const s=o.findIndex(l=>l.app?.appId===c);if(s===-1)return void 0;const[a]=o.splice(s,1);return D(a)})},claimOccurrence(c,o){return M(n,s=>{const a=re(s,typeof c==="string"?c:c.id);if(a.last_occurrence_key===o.occurrenceKey){return{claimed:false,schedule:D(a)}}const l=o.startedAt??new Date().toISOString();a.last_started_at=l;a.last_occurrence_key=o.occurrenceKey;a.updated_at=l;return{claimed:true,schedule:D(a)}})},recordStarted(c,o){return M(n,s=>{const a=re(s,typeof c==="string"?c:c.id);const l=typeof o==="string"?{startedAt:o}:o;const u=l?.startedAt??new Date().toISOString();a.last_started_at=u;if(l?.occurrenceKey!==void 0){a.last_occurrence_key=l.occurrenceKey}a.updated_at=u;return D(a)})},recordFinished(c,o){if(o?.errorCode!==void 0&&!(0,p.isAppScheduleCode)(o.errorCode)){throw new TypeError("recordFinished needs a stable error code")}return M(n,s=>{const a=re(s,typeof c==="string"?c:c.id);const l=o?.finishedAt??new Date().toISOString();a.last_run=l;a.run_count=(a.run_count||0)+1;a.next_run=o?.nextRun!==void 0?o.nextRun:K(a.cron,a.timezone);if(o?.outcome!==void 0)a.last_outcome=o.outcome;else if(o?.success!==void 0)a.last_outcome=o.success?"success":"failure";if(a.app!==void 0)nn(a,o?.errorCode);a.updated_at=l;return D(a)})}}}function tn(e){return A(e??w).list()}function Zn(e,n){const t=m.resolve(n??w);const r=ne(t);try{const i=fe(t);te(i);ke(i,e.map(D))}finally{Z(r)}}function rn(e){const n=Ae(Xe(e));return{removed_builtins:Array.isArray(n?.removed_builtins)?n.removed_builtins:[]}}function Yn(e,n){X(n);const t=Xe(n);const r=`${t}.tmp`;f.writeFileSync(r,JSON.stringify(e,null,2));f.renameSync(r,t)}function on(e){return rn(e).removed_builtins}function Qn(e,n){const t=rn(n);if(!t.removed_builtins.includes(e)){t.removed_builtins.push(e);Yn(t,n)}}function et(e){const n=A(e??w);const t=n.list();const r=new Set(t.map(o=>o.name));const i=new Set(on(e));const c=[];for(const o of F.BUILTIN_SCHEDULES){if(r.has(o.name))continue;if(i.has(o.builtin_id))continue;const s=new Date().toISOString();const a={id:(0,p.generateId)("cron"),cron:o.cron,command:o.buildCommand(),mode:o.mode,enabled:true,name:o.name,working_directory:null,timezone:null,timeout_ms:6e5,allow_concurrent:false,created_at:s,updated_at:s,run_count:0,next_run:K(o.cron,null)};n.create(a);r.add(o.name);c.push(o.builtin_id)}nt(m.resolve(e??w));return c}function ye(e){if(e.app!==void 0)return void 0;const n=(0,F.findBuiltinByName)(e.name);if(!n||e.mode!==n.mode||typeof e.command!=="string")return void 0;const t=(0,F.normalizeBuiltinCommand)(e.command);return t===n.buildCommand()||n.isLegacyCommand(t)?n:void 0}function cn(e){const n=ye(e);return n?.isFrozenPathCommand((0,F.normalizeBuiltinCommand)(e.command))?n:void 0}function nt(e){if(!te(fe(e)).some(n=>cn(n)!==void 0)){return}Xn(e,n=>{let t=false;for(const r of n){const i=cn(r);if(i===void 0)continue;r.command=i.buildCommand();t=true}return t})}const Pe=new Map;async function tt(e=Ze,n){const t=m.resolve(n??w);try{Pe.set(t,ne(t,e));return true}catch(r){if(r instanceof C.CronStoreError&&r.code==="CRON_STORE_LOCK_TIMEOUT")return false;throw r}}function rt(e){const n=m.resolve(e??w);const t=Pe.get(n);if(!t)return;Pe.delete(n);Z(t)}function oe(e){return Ae(e)}function ot(e,n){const t=m.dirname(e);const r=m.join(t,`.${m.basename(e)}.${process.pid}.${(0,le.randomUUID)()}.tmp`);let i;try{i=f.openSync(r,"wx",384);f.writeFileSync(i,JSON.stringify(n));f.fsyncSync(i);f.closeSync(i);i=void 0;f.renameSync(r,e)}finally{if(i!==void 0){try{f.closeSync(i)}catch{}}try{f.unlinkSync(r)}catch{}}}function Le(e,n,t){const r=ne(e);try{return t(Ce(n,e))}finally{Z(r)}}function it(e){try{return Math.max(0,Date.now()-f.statSync(e).mtimeMs)}catch{return null}}function an(e,n){if(e.startTime!==null&&n.startTime!==null){return e.startTime===n.startTime}if(e.commandLine!==null&&n.commandLine!==null){return e.commandLine===n.commandLine}return null}function ct(e,n,t){if(e.phase!=="child"){const s=it(n);if(s===null)return false;const a=e.hostPid??e.pid;const l=ae(a);return l===false||s>t+De}const r=e.childPid??e.pid;const i=ae(r);if(i===false)return true;if(i!==true)return false;if(!e.childIdentity)return false;const c=$e(r);if(!c)return false;const o=an(e.childIdentity,c);if(o===false)return true;return false}function at(e,n,t,r){const i=m.resolve(r??w);X(i);const c=Ce(e,i);const o=(0,le.randomUUID)();const s=(0,le.randomUUID)();const a={leaseId:o,ownerToken:s,phase:"admitting",hostPid:process.pid,pid:process.pid,runId:n,startedAt:new Date().toISOString()};return Le(i,e,()=>{for(let u=0;u<2;u++){try{f.writeFileSync(c,JSON.stringify(a),{flag:"wx",mode:384});return{acquired:true,lease:{scheduleId:e,workspacePath:i,lockFile:c,leaseId:o,ownerToken:s,runId:n}}}catch(R){const E=R;if(E.code!=="EEXIST")throw E;const y=oe(c);if(!y){return{acquired:false,runningTaskId:"",reason:"execution_lease"}}if(ct(y,c,t)){const L=oe(c);if(L?.leaseId!==void 0&&L.leaseId!==y.leaseId){continue}try{f.unlinkSync(c)}catch{}continue}return{acquired:false,runningTaskId:y.taskId??"",runningRunId:y.runId,reason:"execution_lease"}}}const l=oe(c);return{acquired:false,runningTaskId:l?.taskId??"",runningRunId:l?.runId,reason:"execution_lease"}})}function st(e,n,t,r){return Le(e.workspacePath,e.scheduleId,i=>{const c=oe(i);if(!c||c.leaseId!==e.leaseId||c.ownerToken!==e.ownerToken){return false}ot(i,{...c,phase:"child",pid:n,childPid:n,childIdentity:t,...r===void 0?{}:{taskId:r}});return true})}function sn(e,n,t){const r=m.resolve(t??w);X(r);return Le(r,e,i=>{const c=oe(i);if(!c||c.leaseId!==n)return false;try{f.unlinkSync(i);return true}catch(o){const s=o;if(s.code==="ENOENT")return false;throw o}})}const ut={SUN:0,MON:1,TUE:2,WED:3,THU:4,FRI:5,SAT:6};const dt={JAN:1,FEB:2,MAR:3,APR:4,MAY:5,JUN:6,JUL:7,AUG:8,SEP:9,OCT:10,NOV:11,DEC:12};function ie(e,n){const t=e.toUpperCase();if(n===4){const r=ut[t];if(r!==void 0)return r;const i=parseInt(e,10);return i===7?0:i}if(n===3){const r=dt[t];if(r!==void 0)return r}return parseInt(e,10)}function lt(e,n,t){if(e==="*")return true;if(e.includes("/")){const r=e.indexOf("/");const i=e.slice(0,r);const c=parseInt(e.slice(r+1),10);if(isNaN(c)||c<=0)return false;if(i==="*"){return n%c===0}if(i.includes("-")){const s=i.indexOf("-");const a=ie(i.slice(0,s),t);const l=ie(i.slice(s+1),t);return n>=a&&n<=l&&(n-a)%c===0}const o=ie(i,t);return n>=o&&(n-o)%c===0}if(e.includes("-")){const r=e.indexOf("-");const i=ie(e.slice(0,r),t);const c=ie(e.slice(r+1),t);if(i<=c){return n>=i&&n<=c}return n>=i||n<=c}return ie(e,t)===n}function P(e,n,t){return e.split(",").some(r=>lt(r.trim(),n,t))}const un=new Map;function ce(e){const n=un.get(e);if(n!==void 0)return n;let t;try{Intl.DateTimeFormat("en-US",{timeZone:e});t=true}catch{t=false}un.set(e,t);return t}const dn=new Map;function ln(e,n,t){const r=`${e}:${n}`;let i=dn.get(r);if(i===void 0){i=new Intl.DateTimeFormat("en-US",t);dn.set(r,i)}return i}function Ne(e,n,t){let r=n;if(t){if(!ce(t)){console.error(`Invalid timezone: ${t}, skipping execution`);return false}else{const O=ln("cron",t,{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false});const $=O.formatToParts(n);const I=j=>parseInt($.find(H=>H.type===j)?.value??"0",10);const N=I("year");const b=I("month");const G=I("day");r={getMinutes:()=>I("minute"),getHours:()=>I("hour"),getDate:()=>I("day"),getMonth:()=>I("month")-1,getDay:()=>new Date(N,b-1,G).getDay()}}}const i=e.trim().split(/\s+/);if(i.length!==5){console.error(`Invalid cron expression: ${e}`);return false}const[c,o,s,a,l]=i;const u=r.getMinutes();const R=r.getHours();const E=r.getDate();const y=r.getMonth()+1;const L=r.getDay();return P(c,u,0)&&P(o,R,1)&&P(s,E,2)&&P(a,y,3)&&P(l,L,4)}function ft(e){const n=e.trim().split(/\s+/);if(n.length!==5)return e;const[t,r,i,c,o]=n;if(t==="0"&&r!=="*"&&i==="*"&&c==="*"&&o==="*"){return`Daily at ${r}:00`}if(t!=="*"&&r!=="*"&&i==="*"&&c==="*"&&o==="*"){return`Daily at ${r}:${t.padStart(2,"0")}`}if(e==="* * * * *"){return"Every minute"}if(t==="*/5"&&r==="*"&&i==="*"&&c==="*"&&o==="*"){return"Every 5 minutes"}return e}function ve(e,n){if(n&&ce(n)){const t=ln("parts",n,{timeZone:n,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false,weekday:"short"});const r=t.formatToParts(e);const i=s=>parseInt(r.find(a=>a.type===s)?.value??"0",10);const c=r.find(s=>s.type==="weekday")?.value??"";const o={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};return{minute:i("minute"),hour:i("hour"),day:i("day"),month:i("month"),weekday:o[c]??e.getDay()}}return{minute:e.getMinutes(),hour:e.getHours(),day:e.getDate(),month:e.getMonth()+1,weekday:e.getDay()}}function mt(e,n){const t=e.toLocaleString("en-US",{timeZone:"UTC"});const r=e.toLocaleString("en-US",{timeZone:n});return(new Date(r).getTime()-new Date(t).getTime())/6e4}function K(e,n){const t=e.trim().split(/\s+/);if(t.length!==5)return null;const[r,i,c,o,s]=t;const a=[];for(let y=0;y<24;y++){if(P(i,y,1))a.push(y)}const l=[];for(let y=0;y<60;y++){if(P(r,y,0))l.push(y)}if(a.length===0||l.length===0)return null;const u=new Date;const R=n&&ce(n);const E=ve(u,n);for(let y=0;y<=366;y++){const L=new Date(u.getTime()+y*864e5);const O=ve(L,n);if(!P(o,O.month,3))continue;if(!P(c,O.day,2))continue;if(!P(s,O.weekday,4))continue;for(const $ of a){for(const I of l){if(y===0&&($<E.hour||$===E.hour&&I<=E.minute)){continue}let N;if(R){const G=mt(L,n);N=new Date(L);N.setUTCHours($-Math.floor(G/60),I-G%60,0,0)}else{N=new Date(L);N.setHours($,I,0,0)}if(N.getTime()<=u.getTime())continue;const b=ve(N,n);if(b.hour===$&&b.minute===I&&P(c,b.day,2)&&P(o,b.month,3)&&P(s,b.weekday,4)){return N.toISOString()}}}}return null}function Y(e){try{const n=f.readFileSync(ee(e),"utf8").trim();if(!/^\d+$/.test(n))return null;const t=Number(n);return Number.isSafeInteger(t)&&t>0?t:null}catch{return null}}function fn(e,n){X(n);f.writeFileSync(ee(n),`${e}
|
|
3
|
+
`)}function _e(e){try{f.unlinkSync(ee(e))}catch{}}function ae(e){try{process.kill(e,0);return true}catch(n){const t=n;return t.code==="ESRCH"?false:"unknown"}}function mn(e){try{const n=process.platform==="win32"?(0,V.execFileSync)("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}):(0,V.execFileSync)("ps",["-ww","-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return n.trim()||null}catch{return null}}function pt(e){try{const n=process.platform==="win32"?(0,V.execFileSync)("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CreationDate.ToUniversalTime().ToString("o")`],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}):(0,V.execFileSync)("ps",["-p",String(e),"-o","lstart="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return n.trim()||null}catch{return null}}function $e(e){const n={commandLine:mn(e),startTime:pt(e)};return n.commandLine!==null||n.startTime!==null?n:null}const se={isAlive:ae,getCommandLine:mn};function pn(e){const n=e.replace(/\\/g,"/");return process.platform==="win32"?n.toLowerCase():n}function St(){try{const e=pn(Sn()).split("/").filter(Boolean);const n=e.slice(-3).join("/");return n||null}catch{return null}}function yt(e){if(!e?.trim())return"unknown";const n=St();if(!n)return"unknown";const t=pn(e);return t.includes("daemon --foreground")&&t.includes(n)?"running":"stale"}function Sn(){const e=[m.join(__dirname,"..","cli.js"),m.join(__dirname,"..","dist","cli.js")];const n=e.find(t=>f.existsSync(t));if(n){return n}throw new Error(`Cron CLI entrypoint not found: ${e[0]}`)}function ge(e,n=se){const t=Y(e);if(!t){_e(e);return"stale"}let r;try{r=n.isAlive(t)}catch{r="unknown"}if(!r){_e(e);return"stale"}let i;try{i=n.getCommandLine(t)}catch{return"unknown"}const c=yt(i);if(c==="stale"){_e(e)}return c}function be(e,n=se){return ge(e,n)==="running"}function yn(e,n=V.spawn){if((0,p.isDurablyQuiescing)()){throw new Error("Cannot start cron daemon: a desktop update is draining active work")}X(e);const t=Sn();const r={...process.env};if(process.versions.electron){r.ELECTRON_RUN_AS_NODE="1"}const i=n(process.execPath,[t,"daemon","--foreground"],{cwd:e||void 0,detached:true,stdio:"ignore",windowsHide:true,env:r});if(!i.pid){throw new Error("Failed to start daemon: no PID returned")}i.unref();fn(i.pid,e);return i.pid}function _t(e,n=se){const t=ge(e,n);if(t==="running"){const r=Y(e);if(r)return r;throw new Error("Daemon is already running")}if(t==="unknown"){const r=Y(e);throw new Error(`Unable to determine cron daemon liveness (pid=${r??"unknown"}, pidFile=${ee(e)}); refusing to start`)}return yn(e,n.spawnImpl)}function gt(e,n=se){if(ge(e,n)!=="running")return false;const t=Y(e);if(!t)return false;process.kill(t,"SIGTERM");return true}function _n(e,n=se){const t=ge(e,n);if(t==="running"){return{started:false}}if(t==="unknown"){return{started:false,error:`Unable to determine cron daemon liveness (pid=${Y(e)??"unknown"}, pidFile=${ee(e)}); refusing to start`}}try{const r=yn(e,n.spawnImpl);return{started:true,pid:r}}catch(r){const i=r;return{started:false,error:i.message}}}function ht(e,n=se){if(be(e,n))return;console.log("\u26A1 Cron daemon is not running; starting it automatically...");const t=_n(e,n);if(!t.started){console.error("Failed to auto-start daemon:",t.error);process.exit(1)}}function wt(e){const n=A(e??w).list();const t=n.filter(s=>me(s)).length;const r=be(e);const i=r?Y(e):null;let c=null;const o=ee(e);if(r&&f.existsSync(o)){try{c=f.statSync(o).mtime.toISOString()}catch{c=null}}return{running:r,pid:r?i:null,started_at:c,schedules:{total:n.length,enabled:t}}}function he(e,n){try{n()}catch(t){console.error(`[${S()}] ${e} failed: ${t.message}`)}}function gn(e,n){he(`Run ${e} record finish`,()=>{new p.ScheduleRunRepository().finish(e,n)})}function hn(e){try{return(0,k.readRunOutputTail)(e)}catch{return{tail:null,bytes:0}}}function Et(e){try{const n=new p.TaskRepository;let t=n.getTask(e);if(t===void 0)return{status:"failed",errorCode:"TASK_MISSING"};if((0,p.normalizeTaskStatus)(t)==="pending"){n.failPendingTask(e,"RUNNER_NOT_ADOPTED");return{status:"failed",errorCode:"RUNNER_NOT_ADOPTED"}}switch((0,p.normalizeTaskStatus)(t)){case"success":return{status:"success",errorCode:null};case"stopped":return{status:"failed",errorCode:"TASK_STOPPED"};case"failed":return{status:"failed",errorCode:"TASK_FAILED"};default:return{status:"failed",errorCode:"TASK_UNFINISHED"}}}catch{return{status:"failed",errorCode:"TASK_UNREADABLE"}}}function Ue(e,n){he(`Task ${e} close`,()=>{new p.TaskRepository().failPendingTask(e,n)})}function It(e){const{taskId:n,schedule:t,modeFlag:r,trigger:i,workingDir:c}=e;const o=f.existsSync(m.join(c,"crewx.yaml"))||f.existsSync(m.join(c,"crewx.yml"));const s=/^@(\S+)/.exec(t.command)?.[1]??"crewx";new p.TaskRepository().startTask({id:n,agentId:s,actorKind:"system",actorId:`cron:${t.id}`,prompt:t.command,mode:r==="x"?"execute":"query",status:"pending",startedAt:e.startedAt,pid:null,traceId:n,command:`crewx ${r} ${t.command}`,metadata:JSON.stringify({trigger:i,schedule_id:t.id}),workspaceId:o?(0,p.hashWorkspaceId)((0,p.resolveWorkspaceOwnerPath)(c)):null,cwd:(0,p.normalizeWorkspacePath)(c),platform:"cli",threadId:null,model:e.model??null})}function Ct(e,n){const t=(0,p.resolveCrewxExecutable)({env:e,cwd:n});if(!t.ok)return e;const r=Object.keys(e).find(c=>c.toUpperCase()==="PATH")??"PATH";const i=(0,p.createCrewxChildInvocation)(t,{baseEnv:e}).env[r];if(i===void 0)return e;return{...e,[r]:i}}async function wn(e,n){const t=n?.dir;const r=m.resolve(t??w);const i=n?.trigger??"cron";const c=e.timeout_ms||6e5;const o=(0,p.generateId)("crun");const s=(0,p.generateId)("tsk");const a=e.app!==void 0?"app":e.mode==="command"?"command":"agent";if(e.app!==void 0){if(e.mode!=="command"||e.command!==p.APP_SCHEDULE_INERT_COMMAND){return{status:"blocked",reason:"APP_ROW_INVALID"}}if(n?.launchApp===void 0)return{status:"blocked",reason:"APP_LAUNCHER_UNAVAILABLE"}}else{if(!Mt(e.mode))return{status:"blocked",reason:"MODE_UNSUPPORTED"};if(i==="app_enable")return{status:"blocked",reason:"TRIGGER_UNSUPPORTED"}}let l;if(!e.allow_concurrent){const d=at(e.id,o,c,t);if(!d.acquired){console.log(`[${S()}] Schedule ${e.id} already running (run ${d.runningRunId??"unknown"}), skipping`);return{status:"conflict",runningTaskId:d.runningTaskId,...d.runningRunId===void 0?{}:{runningRunId:d.runningRunId},reason:d.reason}}l=d.lease}const u=()=>{if(l){sn(e.id,l.leaseId,t);l=void 0}Un(s)};const R=d=>({id:o,scheduleId:e.id,workspaceId:(0,k.runWorkspaceId)(r),mode:a,trigger:i,occurrenceKey:n?.occurrenceKey??null,taskId:d??null,appId:e.app?.appId??null,scheduleName:e.name,builtinId:ye(e)?.builtin_id??null,command:a==="app"?(0,p.appScheduleCommandLabel)(e.app):e.command,highFrequency:En(e.cron,new Date,e.timezone)});const E=(d,g)=>{const _=new Date().toISOString();he(`Schedule ${e.id} run record`,()=>{new p.ScheduleRunRepository().insert({...R(),status:"failed",errorCode:d,startedAt:g,finishedAt:_,durationMs:Math.max(0,Date.parse(_)-Date.parse(g)),pid:null,hostPid:process.pid})})};if(!bn(s,e.id,c,o)){console.log(`[${S()}] Schedule ${e.id} blocked: could not durably record the update-admission reservation`);u();return{status:"blocked",reason:"ADMISSION_UNKNOWN"}}if((0,p.isDurablyQuiescing)()){console.log(`[${S()}] Schedule ${e.id} blocked: a desktop update is draining active work`);u();return{status:"blocked",reason:"UPDATE_QUIESCING"}}try{const d=A(r);const g=new Date().toISOString();if(n?.occurrenceKey!==void 0){const _=d.claimOccurrence(e.id,{occurrenceKey:n.occurrenceKey,startedAt:g});if(!_.claimed){u();console.log(`[${S()}] Schedule ${e.id} occurrence ${n.occurrenceKey} already claimed, skipping`);return{status:"conflict",runningTaskId:"",reason:"occurrence_claim"}}}else{if(d.get(e.id)){d.recordStarted(e.id,{startedAt:g})}}}catch(d){u();throw d}let y;let L;if(e.app!==void 0){let d;const g=new Date().toISOString();try{d=await n.launchApp(e);if(d.kind!=="spawn")jt(r,e,d)}catch(_){Me(r,e.id,"APP_LAUNCH_FAILED");E("APP_LAUNCH_FAILED",g);u();throw _}if(d.kind!=="spawn"){u();const _=d.kind==="refresh"?"APP_SCHEDULE_REFRESHED":d.code;console.log(`[${S()}] Schedule ${e.id} app row ${d.kind}: ${_}`);return{status:"skipped",reason:_,lifecycle:d.kind}}y=d.child;L=typeof d.settle==="function"?d.settle:void 0}const O=e.working_directory||n?.dir||(0,F.getProjectRoot)();const $=e.mode;const I=ye(e);const N=$==="execute"?"x":"q";const b=n?.overrides?.model??e.model;const G=n?.overrides?.provider??e.provider;const j=(0,k.cronRunLogPath)(r,o);const H=(0,p.withoutCrewxRunnerIdentity)((0,p.withoutCrewxRootContext)({...process.env,...e.env,CREWX_TRACE_ID:s}));delete H["CLAUDECODE"];if(!e.env||!("CREWX_CONFIG"in e.env)){delete H["CREWX_CONFIG"]}H["CREWX_WORKSPACE"]=O;const pe=I!==void 0?[...I.cliArgs]:[N,e.command];if(I===void 0){if(b){pe.push("--model",b)}if($!=="command"&&G){pe.push("--provider",G)}pe.push("--metadata",JSON.stringify({trigger:i,schedule_id:e.id}))}const Q=new Date().toISOString();let W=false;if(a==="agent"){try{It({taskId:s,schedule:e,modeFlag:N,trigger:i,workingDir:O,model:b,startedAt:Q});W=true}catch(d){console.error(`[${S()}] Schedule ${e.id} could not create its task row: ${d.message}`);E("TASK_CREATE_FAILED",Q);u();throw d}}console.log(`[${S()}] Executing schedule ${e.id}: ${e.name??e.cron} (run ${o}${W?`, task ${s}`:""})`);console.log(`[${S()}] Command: ${e.command}`);let h;let x;try{if(y!==void 0){h=y;if(h.pid===void 0)throw new Error("App launcher returned a child that did not start")}else if(e.app!==void 0){throw new Error("managed row has no launched child")}else{x=(0,k.openRunLog)(j);if($==="command"&&I===void 0){h=(0,V.spawn)("sh",["-c",e.command],{cwd:O,stdio:["ignore",x,x],windowsHide:true,detached:true,env:Ct(H,O)})}else{const d=(0,p.resolveCrewxExecutable)({env:H,cwd:O});if(!d.ok){const U=new Error((0,p.formatCrewxExecutableFailure)(d));Object.assign(U,{code:"CLI_UNRESOLVABLE"});throw U}const g=(0,p.createCrewxChildInvocation)(d,{baseEnv:H});const _=(0,p.resolveWindowsSpawnProgram)({command:g.command,env:g.env,cwd:O,packageName:"crewx",allowShellFallback:true});const v=(0,p.materializeWindowsSpawnProgram)(_,[...g.args,...pe]);h=(0,V.spawn)(v.command,v.argv,{cwd:O,stdio:["ignore",x,x],windowsHide:v.windowsHide,detached:true,env:W?{...g.env,CREWX_DETACHED_RUNNER:"1",CREWX_ASSIGNED_TASK_ID:s}:g.env,shell:v.shell??false})}f.closeSync(x);x=void 0}if(y===void 0){await new Promise((d,g)=>{h.once("spawn",()=>d());h.once("error",_=>g(_))})}}catch(d){const g=d;console.error(`[${S()}] Schedule ${e.id} failed to spawn: ${g.message}`);if(x!==void 0){try{f.closeSync(x)}catch{}}if(e.app===void 0)(0,k.removeRunLog)(j);if(e.app!==void 0)Me(r,e.id,"APP_SPAWN_FAILED");if(W)Ue(s,"SPAWN_FAILED");E(e.app!==void 0?"APP_SPAWN_FAILED":"SPAWN_FAILED",Q);u();throw g}he(`Schedule ${e.id} run record`,()=>{new p.ScheduleRunRepository().insert({...R(W?s:void 0),status:"running",startedAt:Q,pid:h.pid??null,hostPid:process.pid})});if(l&&h.pid){const d=st(l,h.pid,$e(h.pid),W?s:void 0);if(!d){const g=new Error("Cron execution lease was replaced before child ownership was established");console.error(`[${S()}] Schedule ${e.id} failed to hand off its execution lease: ${g.message}`);try{h.kill("SIGTERM")}catch{}if(e.app!==void 0)Me(r,e.id,"APP_HANDOFF_FAILED");if(W)Ue(s,"LEASE_HANDOFF_FAILED");const _=new Date().toISOString();gn(o,{status:"failed",errorCode:e.app!==void 0?"APP_HANDOFF_FAILED":"LEASE_HANDOFF_FAILED",finishedAt:_,durationMs:Math.max(0,Date.parse(_)-Date.parse(Q))});if(e.app===void 0)(0,k.removeRunLog)(j);u();throw g}}h.unref();const He=e.app===void 0?(0,k.watchRunLogLimit)(j):void 0;const Dn=new Promise(d=>{let g=false;let _=false;let v;let U;let We=false;const Be=()=>{if(U!==void 0||!h.stdout&&!h.stderr)return;U=setTimeout(()=>{We=true;h.stdout?.destroy();h.stderr?.destroy()},Lt);if(typeof U==="object"&&U!==null&&"unref"in U){U.unref()}};if(e.app!==void 0){h.once("exit",Be);if(h.exitCode!==null||h.signalCode!==null)Be()}const ze=setTimeout(()=>{g=true;console.log(`[${S()}] Schedule ${e.id} timeout, killing process`);try{h.kill("SIGTERM")}catch(T){const Se=T;console.error(`Failed to kill process: ${Se.message}`)}v=setTimeout(()=>{try{h.kill("SIGKILL")}catch{}},De);if(typeof v==="object"&&v!==null&&"unref"in v){v.unref()}if(!_){_=true;d({success:false,error:"Timeout"})}},c);h.on("close",(T,Se)=>{clearTimeout(ze);if(v)clearTimeout(v);if(U)clearTimeout(U);u();He?.stop();const B=e.app!==void 0&&!g?Nt({code:T,signal:Se},L,We):void 0;const Ee=new Date().toISOString();const Ke=g?"timeout":B!==void 0?B.outcome:T===0?"success":"failure";const Ge=e.app===void 0?void 0:g?Pt:B?.outcome==="failure"?B.code:void 0;try{A(r).recordFinished(e.id,{finishedAt:Ee,outcome:Ke,errorCode:Ge})}catch(de){const An=de;if(!(de instanceof C.CronStoreError&&de.code==="CRON_SCHEDULE_NOT_FOUND")){console.error(`[${S()}] Failed to record schedule ${e.id} completion: ${An.message}`)}}let q;if(e.app!==void 0){q={status:Ke==="success"?"success":"failed",errorCode:Ge??null}}else if(a==="agent"){const de=Et(s);q=g?{status:"failed",errorCode:"TIMEOUT"}:de}else if(g){q={status:"failed",errorCode:"TIMEOUT"}}else if(T===0){q={status:"success",errorCode:null}}else{q={status:"failed",errorCode:T===null?"SIGNALED":"EXIT_NONZERO"}}const Ie=e.app===void 0?hn(j):void 0;const qe=He?.state();gn(o,{status:q.status,errorCode:q.errorCode,exitCode:T,signal:Se,finishedAt:Ee,durationMs:Math.max(0,Date.parse(Ee)-Date.parse(Q)),outputTail:Ie?.tail??null,outputBytes:Ie===void 0?null:(qe?.droppedBytes??0)+Ie.bytes,outputTruncated:qe?.truncated??false});if(e.app===void 0&&!(0,k.removeRunLog)(j)){console.warn(`[${S()}] Run ${o} output file could not be removed; the sweep will retry`)}if(g){console.log(`[${S()}] Schedule ${e.id} terminated after timeout`);if(!_){_=true;d({success:false,error:"Timeout"})}}else if(B!==void 0){if(B.outcome==="success"){console.log(`[${S()}] Schedule ${e.id} completed successfully`);if(!_){_=true;d({success:true})}}else{console.log(`[${S()}] Schedule ${e.id} failed with ${B.code}`);if(!_){_=true;d({success:false,error:B.code})}}}else if(T===0){console.log(`[${S()}] Schedule ${e.id} completed successfully`);if(!_){_=true;d({success:true})}}else{console.log(`[${S()}] Schedule ${e.id} failed with code ${T}`);if(!_){_=true;d({success:false,error:`Exit code: ${T}`})}}});h.on("error",T=>{clearTimeout(ze);console.error(`[${S()}] Schedule ${e.id} error: ${T.message}`);if(!_){_=true;d({success:false,error:T.message})}})});return{status:"running",runId:o,...W?{taskId:s}:{},done:Dn}}const Dt=24;function En(e,n,t){const r=60*1e3;const i=n.getTime()+24*60*r;let c=0;try{for(let o=(Math.floor(n.getTime()/r)+1)*r;o<=i;o+=r){if(!Ne(e,new Date(o),t))continue;c++;if(c>Dt)return true}}catch{return false}return false}exports.SCHEDULE_RUN_SWEEP_INTERVAL_MS=60*60*1e3;function At(e,n){const t=oe(Ce(n.scheduleId,e));if(t!==null&&t.runId===n.id&&t.phase==="child"){const i=t.childPid??t.pid;const c=ae(i);if(c===false)return"dead";if(c!==true||!t.childIdentity)return"unknown";const o=$e(i);if(!o)return"unknown";const s=an(t.childIdentity,o);if(s===false)return"dead";return s===null?"unknown":"alive"}if(n.pid===null)return"unknown";const r=ae(n.pid);if(r===false)return"dead";return r===true?"alive":"unknown"}function Rt(e){try{return tn(e)}catch{return[]}}function Ot(e,n,t,r,i){const c=new Map(Rt(n).map(s=>[s.id,s.timeout_ms]));for(const s of e.listRunning(t)){const a=s.hostPid===null?"unknown":ae(s.hostPid);if(a!==false)continue;const l=At(n,s);const u=Math.max(0,r.getTime()-Date.parse(s.startedAt));const R=c.get(s.scheduleId)||6e5;if(l!=="dead"&&u<=R+De)continue;const E=s.mode==="app"?void 0:hn((0,k.cronRunLogPath)(n,s.id));const y=e.markLost(s.id,{finishedAt:r.toISOString(),durationMs:u,errorCode:"RUNNER_LOST",outputTail:E?.tail??null,outputBytes:E===void 0?null:E.bytes,outputTruncated:s.outputTruncated});if(!y)continue;i.lost++;if(s.taskId!==null)Ue(s.taskId,"RUNNER_LOST")}const o=e.prune(t,r);i.deleted=o.deleted;i.tailsCleared=o.tailsCleared}function Tt(e,n,t,r,i){const c=(0,k.cronRunLogDir)(n);let o;try{o=f.readdirSync(c)}catch{return}for(const s of o){if(!s.endsWith(".log"))continue;const a=m.join(c,s);const l=s.slice(0,-".log".length);let u;try{u=t?e.get(l):void 0}catch{continue}if(u?.status==="running")continue;if(u===void 0){let R;try{R=f.statSync(a).mtimeMs}catch{continue}if(r.getTime()-R<k.CRON_RUN_ORPHAN_LOG_GRACE_MS)continue}if((0,k.removeRunLog)(a))i.logsRemoved++}}function kt(e={}){const n=m.resolve(e.dir??w);const t=e.now??new Date;const r={lost:0,logsRemoved:0,deleted:0,tailsCleared:0};const i=new p.ScheduleRunRepository;let c=false;try{c=f.existsSync(i.resolveDbPath())}catch(o){console.warn(`[${S()}] Run record sweep: database unavailable: ${o.message}`)}if(c){try{Ot(i,n,(0,k.runWorkspaceId)(n),t,r)}catch(o){console.warn(`[${S()}] Run record sweep failed: ${o.message}`)}}try{Tt(i,n,c,t,r)}catch(o){console.warn(`[${S()}] Run output sweep failed: ${o.message}`)}return r}const Pt="APP_TIMEOUT";const Lt=5e3;function Nt(e,n,t){if(e.signal!==null)return ue("APP_SIGNALED");if(e.code!==0)return ue("APP_EXIT_NONZERO");if(t)return ue("APP_STDIO_NOT_DRAINED");if(n===void 0)return ue("APP_VERDICT_FAILED");let r;try{r=n(e)}catch{return ue("APP_VERDICT_FAILED")}return bt(r)}const vt=64;const $t=3;function bt(e){try{if(typeof e==="object"&&e!==null&&!Array.isArray(e)&&typeof e.then!=="function"){const n=Object.keys(e);const{outcome:t,code:r}=e;if(t==="success"&&n.length===1)return{outcome:"success"};if(t==="failure"&&n.length===2&&n.includes("code")){return(0,p.isAppScheduleCode)(r)?{outcome:"failure",code:r}:Fe(e,"APP_OUTPUT_INVALID")}}return Fe(e,"APP_VERDICT_FAILED")}catch{return Fe(e,"APP_VERDICT_FAILED")}}function Fe(e,n){Ut(e);return ue(n)}const we=()=>void 0;function Ut(e){const n=[{value:e,depth:0}];for(let t=0;t<vt&&n.length>0;t+=1){const{value:r,depth:i}=n.shift();if(typeof r!=="object"&&typeof r!=="function"||r===null)continue;try{if(Object.getPrototypeOf(r)===Promise.prototype){Promise.prototype.then.call(r,we,we);continue}const c=r.then;if(typeof c==="function"){c.call(r,we,we);continue}if(i<$t){for(const o of Object.keys(r)){const s=Object.getOwnPropertyDescriptor(r,o);if(s!==void 0&&"value"in s)n.push({value:s.value,depth:i+1})}}}catch{}}}function ue(e){return{outcome:"failure",code:e}}const Ft=["query","execute","command"];function Mt(e){return Ft.includes(e)}function xt(e){return{appId:e.appId,actionId:e.actionId,source:e.source}}function jt(e,n,t){const r=A(e);const i=xt(n.app);const c={cron:n.cron,timeout_ms:n.timeout_ms,name:n.name};switch(t.kind){case"skip":{const o=r.setAppSchedule(i,c).schedule;r.recordSkipped(o.id,{outcome:t.code,errorCode:t.code});return}case"disable":{const o=r.setAppSchedule(i,c,false).schedule;r.recordSkipped(o.id,{outcome:t.code,errorCode:t.code});return}case"remove":r.removeAppSchedule(i.appId);return;case"refresh":{const o=r.setAppSchedule(t.owner,t.template).schedule;r.recordSkipped(o.id,{outcome:"APP_SCHEDULE_REFRESHED",errorCode:null});return}}}function Me(e,n,t){try{A(e).recordSkipped(n,{outcome:t,errorCode:t})}catch(r){if(r instanceof C.CronStoreError&&r.code==="CRON_SCHEDULE_NOT_FOUND")return;console.error(`[${S()}] Schedule ${n} could not record its ${t} outcome: ${r.message}`)}}function In(e,n){if(!n||!ce(n)){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")} ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}const t=new Intl.DateTimeFormat("en-CA",{timeZone:n,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false});return t.format(e)}function Cn(e,n){return`${e.trim()}|${n}`}async function xe(e){if((0,p.isDurablyQuiescing)()){console.log(`[${S()}] Daemon tick skipped: a desktop update is draining active work`);return}const n=new Date;const t=A(e??w).list();const r=t.filter(i=>me(i));if(r.length===0){return}for(const i of r){if(Ne(i.cron,n,i.timezone)){const c=In(n,i.timezone);const o=Cn(i.cron,c);try{await wn(i,{dir:e,occurrenceKey:o})}catch(s){const a=s;console.error(`[${S()}] Schedule ${i.id} failed to spawn: ${a.message}`)}}}}var je=require("./runtime");Object.defineProperty(exports,"createCronRuntime",{enumerable:true,get:function(){return je.createCronRuntime}});Object.defineProperty(exports,"CRON_RUNTIME_PROCESS_LEASE_FILENAME",{enumerable:true,get:function(){return je.CRON_RUNTIME_PROCESS_LEASE_FILENAME}});Object.defineProperty(exports,"scheduledPeriodicAvailability",{enumerable:true,get:function(){return je.scheduledPeriodicAvailability}});function Ht(e){fn(process.pid,e);let n=false;const t=()=>{if(n)return;n=true;const c=Y(e);if(c===process.pid){_e(e)}};process.on("SIGTERM",()=>{t();process.exit(0)});process.on("SIGINT",()=>{t();process.exit(0)});process.on("exit",t);console.log(`[${S()}] Cron daemon starting in foreground mode`);console.log(`[${S()}] Check interval: 1 minute`);console.log(`[${S()}] Press Ctrl+C to stop
|
|
4
|
+
`);const r=A(e??w).list();const i=r.filter(c=>me(c)).length;console.log(`[${S()}] Active schedules: ${i}/${r.length}
|
|
5
|
+
`);void xe(e);setInterval(()=>{void xe(e)},Fn)}function Wt(e,n,t,r){if(t.timezone&&!ce(t.timezone)){throw new Error(`Invalid timezone: ${t.timezone}`)}Qe(n);const i={id:(0,p.generateId)("cron"),cron:e,command:n,mode:Oe(t.mode??"execute"),enabled:true,name:t.name??null,working_directory:t.dir??null,timezone:t.timezone??null,timeout_ms:parseInt(t.timeout??"600000",10),allow_concurrent:t.allowConcurrent??false,created_at:new Date().toISOString(),updated_at:new Date().toISOString(),run_count:0};if(t.model){i.model=t.model}if(t.provider){i.provider=t.provider}i.next_run=K(e,i.timezone);return A(r??w).create(i)}function Bt(e,n){const t=A(n??w).remove(e);const r=(0,F.findBuiltinByName)(t.name);if(r){Qn(r.builtin_id,n)}return t}function zt(e,n){return A(n??w).toggle(e,true)}function Kt(e,n){return A(n??w).toggle(e,false)}function Gt(e,n,t){if(n.timezone!==void 0&&n.timezone!==null&&!ce(n.timezone)){throw new Error(`Invalid timezone: ${n.timezone}`)}const r=A(t??w);const i=r.get(e);if(!i){throw new Error(`Schedule not found: ${e}`)}const c=[];const o={};if(n.cron!==void 0){o.cron=n.cron;c.push(`cron: ${n.cron}`)}if(n.command!==void 0){Qe(n.command);o.command=n.command;c.push(`command: ${n.command}`)}if(n.name!==void 0){o.name=n.name;c.push(`name: ${n.name}`)}if(n.mode!==void 0){o.mode=Oe(n.mode);c.push(`mode: ${o.mode}`)}if(n.timezone!==void 0){o.timezone=n.timezone;c.push(`timezone: ${n.timezone}`)}if(n.working_directory!==void 0){o.working_directory=n.working_directory;c.push(`working_directory: ${n.working_directory}`)}if(n.timeout_ms!==void 0){o.timeout_ms=n.timeout_ms;c.push(`timeout: ${n.timeout_ms}ms`)}if(n.allow_concurrent!==void 0){o.allow_concurrent=n.allow_concurrent;c.push(`allow_concurrent: ${n.allow_concurrent}`)}if(n.model!==void 0){if(n.model===null){o.model=null;c.push("model: (cleared, reverts to agent default)")}else{o.model=n.model;c.push(`model: ${n.model}`)}}if(n.provider!==void 0){if(n.provider===null){o.provider=null;c.push("provider: (cleared, reverts to agent default)")}else{o.provider=n.provider;c.push(`provider: ${n.provider}`)}}return{schedule:r.update(i.id,o),changes:c}}exports.DATA_PATHS={DATA_DIR:J,SCHEDULES_FILE:Tn,LOG_FILE:kn,LOCK_FILE:Pn,USAGE_LOG_FILE:Ln,PID_FILE:Nn,BUILTINS_META_FILE:vn};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const CRON_RUN_LOG_DIR_NAME = "cron-runs";
|
|
2
|
+
export declare const CRON_RUN_TAIL_MAX_BYTES: number;
|
|
3
|
+
export declare const CRON_RUN_TAIL_MAX_LINES = 200;
|
|
4
|
+
export declare const CRON_RUN_LOG_MAX_BYTES: number;
|
|
5
|
+
export declare const CRON_RUN_LOG_WATCH_MS = 5000;
|
|
6
|
+
export declare const CRON_RUN_ORPHAN_LOG_GRACE_MS: number;
|
|
7
|
+
export declare function cronRunLogDir(workspacePath: string): string;
|
|
8
|
+
export declare function cronRunLogPath(workspacePath: string, runId: string): string;
|
|
9
|
+
export declare function runWorkspaceId(workspacePath: string): string;
|
|
10
|
+
export declare function openRunLog(logPath: string): number;
|
|
11
|
+
export interface RunOutputTail {
|
|
12
|
+
tail: string | null;
|
|
13
|
+
bytes: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function readRunOutputTail(logPath: string): RunOutputTail;
|
|
16
|
+
export declare function enforceRunLogLimit(logPath: string): number | null;
|
|
17
|
+
export interface RunOutputWatch {
|
|
18
|
+
stop(): void;
|
|
19
|
+
state(): {
|
|
20
|
+
droppedBytes: number;
|
|
21
|
+
truncated: boolean;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export declare function watchRunLogLimit(logPath: string, intervalMs?: number): RunOutputWatch;
|
|
25
|
+
export declare function removeRunLog(logPath: string): boolean;
|
|
26
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var O=exports&&exports.__createBinding||(Object.create?(function(t,e,n,r){if(r===void 0)r=n;var u=Object.getOwnPropertyDescriptor(e,n);if(!u||("get"in u?!e.__esModule:u.writable||u.configurable)){u={enumerable:true,get:function(){return e[n]}}}Object.defineProperty(t,r,u)}):(function(t,e,n,r){if(r===void 0)r=n;t[r]=e[n]}));var L=exports&&exports.__setModuleDefault||(Object.create?(function(t,e){Object.defineProperty(t,"default",{enumerable:true,value:e})}):function(t,e){t["default"]=e});var s=exports&&exports.__importStar||(function(){var t=function(e){t=Object.getOwnPropertyNames||function(n){var r=[];for(var u in n)if(Object.prototype.hasOwnProperty.call(n,u))r[r.length]=u;return r};return t(e)};return function(e){if(e&&e.__esModule)return e;var n={};if(e!=null){for(var r=t(e),u=0;u<r.length;u++)if(r[u]!=="default")O(n,e,r[u])}L(n,e);return n}})();Object.defineProperty(exports,"__esModule",{value:true});exports.CRON_RUN_ORPHAN_LOG_GRACE_MS=exports.CRON_RUN_LOG_WATCH_MS=exports.CRON_RUN_LOG_MAX_BYTES=exports.CRON_RUN_TAIL_MAX_LINES=exports.CRON_RUN_TAIL_MAX_BYTES=exports.CRON_RUN_LOG_DIR_NAME=void 0;exports.cronRunLogDir=R;exports.cronRunLogPath=d;exports.runWorkspaceId=y;exports.openRunLog=A;exports.readRunOutputTail=S;exports.enforceRunLogLimit=N;exports.watchRunLogLimit=p;exports.removeRunLog=g;const i=s(require("fs"));const a=s(require("path"));const f=require("@crewx/sdk");exports.CRON_RUN_LOG_DIR_NAME="cron-runs";exports.CRON_RUN_TAIL_MAX_BYTES=16*1024;exports.CRON_RUN_TAIL_MAX_LINES=200;exports.CRON_RUN_LOG_MAX_BYTES=32*1024*1024;exports.CRON_RUN_LOG_WATCH_MS=5e3;exports.CRON_RUN_ORPHAN_LOG_GRACE_MS=60*60*1e3;function R(t){return a.join(t,".crewx",exports.CRON_RUN_LOG_DIR_NAME)}function d(t,e){return a.join(R(t),`${e}.log`)}function y(t){return(0,f.hashWorkspaceId)((0,f.resolveWorkspaceOwnerPath)(t))}function A(t){i.mkdirSync(a.dirname(t),{recursive:true});return i.openSync(t,"a")}function S(t){let e;try{e=i.statSync(t).size}catch{return{tail:null,bytes:0}}if(e===0)return{tail:"",bytes:0};const n=Math.max(0,e-exports.CRON_RUN_TAIL_MAX_BYTES);const r=e-n;const u=new Uint8Array(r);const _=i.openSync(t,"r");try{i.readSync(_,u,0,r,n)}finally{i.closeSync(_)}let o=Buffer.from(u).toString("utf8");if(n>0){const l=o.indexOf("\n");o=l===-1?"":o.slice(l+1)}const c=o.split("\n");if(c.length>0&&c[c.length-1]==="")c.pop();return{tail:c.slice(-exports.CRON_RUN_TAIL_MAX_LINES).join("\n"),bytes:e}}function N(t){let e;try{e=i.statSync(t).size}catch{return null}if(e<=exports.CRON_RUN_LOG_MAX_BYTES)return null;try{i.truncateSync(t,0);return e}catch(n){console.warn(`[cron] could not truncate run output ${t}: ${n.message}`);return null}}function p(t,e=exports.CRON_RUN_LOG_WATCH_MS){let n=0;let r=false;const u=setInterval(()=>{const _=N(t);if(_===null)return;n+=_;r=true},e);u.unref();return{stop:()=>clearInterval(u),state:()=>({droppedBytes:n,truncated:r})}}function g(t){try{i.unlinkSync(t);return true}catch(e){if(e.code==="ENOENT")return true;return false}}
|
package/dist/src/runtime.d.ts
CHANGED
package/dist/src/runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var p=exports&&exports.__createBinding||(Object.create?(function(r,e,s,i){if(i===void 0)i=s;var t=Object.getOwnPropertyDescriptor(e,s);if(!t||("get"in t?!e.__esModule:t.writable||t.configurable)){t={enumerable:true,get:function(){return e[s]}}}Object.defineProperty(r,i,t)}):(function(r,e,s,i){if(i===void 0)i=s;r[i]=e[s]}));var f=exports&&exports.__setModuleDefault||(Object.create?(function(r,e){Object.defineProperty(r,"default",{enumerable:true,value:e})}):function(r,e){r["default"]=e});var k=exports&&exports.__importStar||(function(){var r=function(e){r=Object.getOwnPropertyNames||function(s){var i=[];for(var t in s)if(Object.prototype.hasOwnProperty.call(s,t))i[i.length]=t;return i};return r(e)};return function(e){if(e&&e.__esModule)return e;var s={};if(e!=null){for(var i=r(e),t=0;t<i.length;t++)if(i[t]!=="default")p(s,e,i[t])}f(s,e);return s}})();Object.defineProperty(exports,"__esModule",{value:true});exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME=void 0;exports.scheduledPeriodicAvailability=v;exports.createCronRuntime=y;const w=require("node:crypto");const g=k(require("node:path"));const h=require("@crewx/sdk");const d=require("./engine");exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME="cron-runtime-process-lease.json";const l=5e3;function v(r){if(r.draining||r.role==="draining")return{periodic:"unavailable",reason:"draining"};if(!r.enabled||r.stopped||r.role==="disabled"||r.role==="stopped"){return{periodic:"unavailable",reason:"disabled"}}if(r.role!=="owner")return{periodic:"unavailable",reason:"standby"};const e=r.workspace;if(e===void 0||e.state!=="ready"||e.fenced){return{periodic:"unavailable",reason:"degraded"}}return{periodic:"available"}}const c=new Map;function u(r){const e=r;return{...typeof e?.code==="string"?{code:e.code}:{},message:e?.message instanceof String?e.message.toString():e&&typeof e.message==="string"?e.message:String(r)}}function m(r){return{...r,...r.lastError?{lastError:{...r.lastError}}:{}}}function b(r,e){return`${r}\0${e}`}function P(r){try{return(0,h.resolveProcessLeasePath)(r)}catch{return g.resolve(r)}}function R(r){if(r===void 0)return l;if(!Number.isFinite(r))return l;return Math.max(0,r)}class T{constructor(e={}){this.runtimeToken=Symbol("cron-runtime");this.enabled=false;this.draining=false;this.stopped=false;this.role="standby";this.ownerId=null;this.leaseId=null;this.workspaces=new Map;this.workspaceRevisions=new Map;this.workspaceFences=new Map;this.operations=new Set;this.reconcileQueue=Promise.resolve();this.requestedLeasePath=e.leasePath??exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME;this.resolvedLeasePath=P(this.requestedLeasePath);this.configuredOwnerId=e.ownerId;this.leaseProvider=e.processLease??e.leaseProvider??{acquire:h.acquireProcessLease};this.storeFactory=e.storeFactory??(s=>(0,d.createScheduleStore)(s.path));this.executor=e.executeSchedule??e.executor??d.executeSchedule;this.runPredicate=e.shouldRunNow??d.shouldRunNow;this.testHooks=e.testHooks}nextWorkspaceRevision(e){const s=(this.workspaceRevisions.get(e)??0)+1;this.workspaceRevisions.set(e,s);return s}isWorkspaceFenced(e){return(this.workspaceFences.get(e)?.size??0)>0}setWorkspaceFenceStatus(e,s){const i=this.workspaces.get(e);if(!i)return;i.status={...i.status,fenced:s}}register(e){if(this.stopped||this.draining)return this.status();const s=this.workspaces.get(e.id);const i=s&&s.workspace.path===e.path?s.revision:this.nextWorkspaceRevision(e.id);this.workspaces.set(e.id,{workspace:{...e},revision:i,status:{id:e.id,path:e.path,state:"registered",scheduleCount:0,revision:i,fenced:this.isWorkspaceFenced(e.id)}});return this.status()}unregister(e){if(this.workspaces.delete(e))this.nextWorkspaceRevision(e);this.workspaceFences.delete(e);return this.status()}fence(e){const s=(0,w.randomUUID)();const i=this.workspaceFences.get(e)??new Set;i.add(s);this.workspaceFences.set(e,i);this.setWorkspaceFenceStatus(e,true);return{token:s,status:this.status(e)}}releaseFence(e,s){const i=this.workspaceFences.get(e);if(i?.delete(s)){if(i.size===0)this.workspaceFences.delete(e);this.setWorkspaceFenceStatus(e,this.isWorkspaceFenced(e))}return this.status(e)}reconcile(e){const s=this.reconcileQueue.then(()=>this.applyReconcile(e));this.reconcileQueue=s.then(()=>void 0,()=>void 0);return this.track(s)}async tick(e=new Date){if(this.activeTickPromise){return this.skippedTick("reentrant",e,true)}const s=this.track(this.performTick(new Date(e.getTime())));this.activeTickPromise=s;void s.then(()=>this.clearActiveTick(s),()=>this.clearActiveTick(s));return s}beginDrain(){if(this.stopped)return;this.draining=true;this.role="draining"}stop(e={}){if(this.stopped&&this.stopPromise)return this.stopPromise;if(this.stopPromise)return this.stopPromise;this.beginDrain();const s=this.waitForDrain(R(e.deadlineMs)).then(i=>{if(!i){return{status:"timeout",timedOut:true,drained:false,leaseReleased:false,role:this.publicRole(),activeTick:this.activeTickPromise!==void 0}}this.stopped=true;const t=this.releaseLease();this.role="stopped";return{status:"stopped",timedOut:false,drained:true,leaseReleased:t,role:this.publicRole(),activeTick:this.activeTickPromise!==void 0}});this.stopPromise=s;void s.then(i=>{if(i.status==="timeout")this.stopPromise=void 0});return s}status(e){const s=Array.from(this.workspaces.values(),({status:t})=>m(t));const i=e===void 0?void 0:s.find(t=>t.id===e);return{enabled:this.enabled,role:this.publicRole(),activeTick:this.activeTickPromise!==void 0,draining:this.draining,stopped:this.stopped,ownerId:this.ownerId,leaseId:this.leaseId,leasePath:this.resolvedLeasePath,...this.standbyReason?{standbyReason:this.standbyReason}:{},workspaces:s,...i?{workspace:i}:{}}}async applyReconcile(e){if(this.stopped||this.draining)return this.status();this.enabled=e.enabled;const s=new Set(e.workspaces.map(t=>t.id));for(const t of this.workspaces.keys()){if(!s.has(t))this.nextWorkspaceRevision(t)}const i=new Map;for(const t of e.workspaces){const a=this.workspaces.get(t.id);const n=a&&a.workspace.path===t.path?a.revision:this.nextWorkspaceRevision(t.id);i.set(t.id,{workspace:{...t},revision:n,status:a&&a.workspace.path===t.path?{...a.status,path:t.path,revision:n,fenced:this.isWorkspaceFenced(t.id)}:{id:t.id,path:t.path,state:"registered",scheduleCount:0,revision:n,fenced:this.isWorkspaceFenced(t.id)}})}this.workspaces.clear();for(const[t,a]of i)this.workspaces.set(t,a);await Promise.all(Array.from(this.workspaces.values(),t=>this.inspectWorkspace(t)));if(this.enabled&&!this.draining&&!this.stopped){this.ensureOwner()}else if(!this.enabled){this.role="disabled"}return this.status()}inspectWorkspace(e){try{const s=this.storeFactory(e.workspace).list();e.status={id:e.workspace.id,path:e.workspace.path,state:"ready",scheduleCount:s.length,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id)}}catch(s){e.status={id:e.workspace.id,path:e.workspace.path,state:"degraded",scheduleCount:0,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id),lastError:u(s)}}}async performTick(e){if(this.stopped)return this.skippedTick("stopped",e,false);if(this.draining)return this.skippedTick("draining",e,false);if(!this.enabled)return this.skippedTick("disabled",e,false);if(!this.ensureOwner())return this.skippedTick("standby",e,false);const s=Array.from(this.workspaces.values());const i=await Promise.all(s.map(t=>this.tickWorkspace(t,e)));return{status:"completed",skipped:false,role:this.publicRole(),now:e.toISOString(),activeTick:true,dispatched:i.reduce((t,a)=>t+a.dispatched,0),workspaces:i}}async tickWorkspace(e,s){if(this.draining||this.stopped){return{id:e.workspace.id,path:e.workspace.path,status:"skipped",scheduleCount:e.status.scheduleCount,dueCount:0,dispatched:0,schedules:[]}}let i;try{i=this.storeFactory(e.workspace).list();e.status={id:e.workspace.id,path:e.workspace.path,state:"ready",scheduleCount:i.length,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id)}}catch(n){const o=u(n);e.status={id:e.workspace.id,path:e.workspace.path,state:"degraded",scheduleCount:0,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id),lastError:o};return{id:e.workspace.id,path:e.workspace.path,status:"degraded",scheduleCount:0,dueCount:0,dispatched:0,schedules:[],error:o}}const t=[];for(const n of i){if(!(0,d.effectiveEnabled)(n))continue;try{if(!this.runPredicate(n.cron,s,n.timezone))continue;const o=(0,d.getLocalMinuteKey)(s,n.timezone);t.push({schedule:n,occurrenceKey:(0,d.buildOccurrenceKey)(n.cron,o)})}catch{}}const a=await Promise.all(t.map(n=>this.admitSchedule(e.workspace,e.revision,n.schedule,n.occurrenceKey)));return{id:e.workspace.id,path:e.workspace.path,status:"completed",scheduleCount:i.length,dueCount:t.length,dispatched:a.filter(n=>n.accepted).length,schedules:a}}async admitSchedule(e,s,i,t){if(this.draining||this.stopped){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:this.stopped?"stopped":"draining"}}const a=this.testHooks?.beforeExecutorAdmission;if(a){await a({workspace:e,schedule:i,occurrenceKey:t,revision:s})}if(this.draining||this.stopped){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:this.stopped?"stopped":"draining"}}const n=this.workspaces.get(e.id);if(!n||n.workspace.path!==e.path||n.revision!==s){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:"workspace-unregistered"}}if(this.isWorkspaceFenced(e.id)){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:"workspace-fenced"}}try{const o=await this.executor(i,{dir:e.path,trigger:"cron",occurrenceKey:t});return{scheduleId:i.id,occurrenceKey:t,status:o.status,accepted:o.status==="running",..."taskId"in o?{taskId:o.taskId}:{},..."reason"in o&&o.reason?{reason:o.reason}:{}}}catch(o){return{scheduleId:i.id,occurrenceKey:t,status:"error",accepted:false,error:u(o).message}}}ensureOwner(){if(this.lease){try{if(this.lease.renew&&!this.lease.renew()){this.forgetLease()}else{this.role="owner";this.standbyReason=void 0;return true}}catch{this.forgetLease()}}if(this.stopped||this.draining||!this.enabled)return false;let e;try{const t={leasePath:this.requestedLeasePath,...this.configuredOwnerId?{ownerId:this.configuredOwnerId}:{}};e=this.leaseProvider.acquire(t)}catch(t){this.role="standby";this.standbyReason=`lease-error:${u(t).message}`;return false}if(!e.acquired){this.role="standby";this.standbyReason=e.reason;this.ownerId=e.record?.ownerId??null;this.leaseId=e.record?.leaseId??null;return false}const s=b(this.resolvedLeasePath,e.ownerId);const i=c.get(s);if(i&&i.runtimeToken!==this.runtimeToken){this.role="standby";this.standbyReason="process-local-owner";this.ownerId=e.ownerId;this.leaseId=e.leaseId;return false}this.lease=e.lease;this.leaseKey=s;this.ownerId=e.ownerId;this.leaseId=e.leaseId;c.set(s,{runtimeToken:this.runtimeToken,ownerId:e.ownerId,lease:e.lease});this.role="owner";this.standbyReason=void 0;return true}forgetLease(){if(this.leaseKey){const e=c.get(this.leaseKey);if(e?.runtimeToken===this.runtimeToken)c.delete(this.leaseKey)}this.lease=void 0;this.leaseKey=void 0;this.ownerId=null;this.leaseId=null;this.role="standby";this.standbyReason="lease-lost"}releaseLease(){if(!this.lease)return true;let e=false;try{e=this.lease.release()}catch{e=false}if(e)this.forgetLease();return e}publicRole(){if(this.stopped)return"stopped";if(this.draining)return"draining";if(!this.enabled)return"disabled";return this.role}skippedTick(e,s,i){return{status:"skipped",skipped:true,reason:e,role:this.publicRole(),now:s.toISOString(),activeTick:i||this.activeTickPromise!==void 0,dispatched:0,workspaces:[]}}clearActiveTick(e){if(this.activeTickPromise===e)this.activeTickPromise=void 0}track(e){let s;s=e.finally(()=>this.operations.delete(s));this.operations.add(s);return s}async waitForDrain(e){const s=Array.from(this.operations);if(s.length===0)return true;const i=Promise.allSettled(s).then(()=>true);if(e<=0)return false;let t;const a=new Promise(o=>{t=setTimeout(()=>o(false),e)});const n=await Promise.race([i,a]);if(t!==void 0)clearTimeout(t);return n}}function y(r={}){return new T(r)}
|
|
1
|
+
"use strict";var p=exports&&exports.__createBinding||(Object.create?(function(r,e,s,i){if(i===void 0)i=s;var t=Object.getOwnPropertyDescriptor(e,s);if(!t||("get"in t?!e.__esModule:t.writable||t.configurable)){t={enumerable:true,get:function(){return e[s]}}}Object.defineProperty(r,i,t)}):(function(r,e,s,i){if(i===void 0)i=s;r[i]=e[s]}));var f=exports&&exports.__setModuleDefault||(Object.create?(function(r,e){Object.defineProperty(r,"default",{enumerable:true,value:e})}):function(r,e){r["default"]=e});var k=exports&&exports.__importStar||(function(){var r=function(e){r=Object.getOwnPropertyNames||function(s){var i=[];for(var t in s)if(Object.prototype.hasOwnProperty.call(s,t))i[i.length]=t;return i};return r(e)};return function(e){if(e&&e.__esModule)return e;var s={};if(e!=null){for(var i=r(e),t=0;t<i.length;t++)if(i[t]!=="default")p(s,e,i[t])}f(s,e);return s}})();Object.defineProperty(exports,"__esModule",{value:true});exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME=void 0;exports.scheduledPeriodicAvailability=v;exports.createCronRuntime=S;const w=require("node:crypto");const g=k(require("node:path"));const h=require("@crewx/sdk");const d=require("./engine");exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME="cron-runtime-process-lease.json";const l=5e3;function v(r){if(r.draining||r.role==="draining")return{periodic:"unavailable",reason:"draining"};if(!r.enabled||r.stopped||r.role==="disabled"||r.role==="stopped"){return{periodic:"unavailable",reason:"disabled"}}if(r.role!=="owner")return{periodic:"unavailable",reason:"standby"};const e=r.workspace;if(e===void 0||e.state!=="ready"||e.fenced){return{periodic:"unavailable",reason:"degraded"}}return{periodic:"available"}}const u=new Map;function c(r){const e=r;return{...typeof e?.code==="string"?{code:e.code}:{},message:e?.message instanceof String?e.message.toString():e&&typeof e.message==="string"?e.message:String(r)}}function m(r){return{...r,...r.lastError?{lastError:{...r.lastError}}:{}}}function b(r,e){return`${r}\0${e}`}function R(r){try{return(0,h.resolveProcessLeasePath)(r)}catch{return g.resolve(r)}}function P(r){if(r===void 0)return l;if(!Number.isFinite(r))return l;return Math.max(0,r)}class I{constructor(e={}){this.runtimeToken=Symbol("cron-runtime");this.enabled=false;this.draining=false;this.stopped=false;this.role="standby";this.ownerId=null;this.leaseId=null;this.workspaces=new Map;this.workspaceRevisions=new Map;this.workspaceFences=new Map;this.operations=new Set;this.reconcileQueue=Promise.resolve();this.requestedLeasePath=e.leasePath??exports.CRON_RUNTIME_PROCESS_LEASE_FILENAME;this.resolvedLeasePath=R(this.requestedLeasePath);this.configuredOwnerId=e.ownerId;this.leaseProvider=e.processLease??e.leaseProvider??{acquire:h.acquireProcessLease};this.storeFactory=e.storeFactory??(s=>(0,d.createScheduleStore)(s.path));this.executor=e.executeSchedule??e.executor??d.executeSchedule;this.runPredicate=e.shouldRunNow??d.shouldRunNow;this.testHooks=e.testHooks}nextWorkspaceRevision(e){const s=(this.workspaceRevisions.get(e)??0)+1;this.workspaceRevisions.set(e,s);return s}isWorkspaceFenced(e){return(this.workspaceFences.get(e)?.size??0)>0}setWorkspaceFenceStatus(e,s){const i=this.workspaces.get(e);if(!i)return;i.status={...i.status,fenced:s}}register(e){if(this.stopped||this.draining)return this.status();const s=this.workspaces.get(e.id);const i=s&&s.workspace.path===e.path?s.revision:this.nextWorkspaceRevision(e.id);this.workspaces.set(e.id,{workspace:{...e},revision:i,status:{id:e.id,path:e.path,state:"registered",scheduleCount:0,revision:i,fenced:this.isWorkspaceFenced(e.id)}});return this.status()}unregister(e){if(this.workspaces.delete(e))this.nextWorkspaceRevision(e);this.workspaceFences.delete(e);return this.status()}fence(e){const s=(0,w.randomUUID)();const i=this.workspaceFences.get(e)??new Set;i.add(s);this.workspaceFences.set(e,i);this.setWorkspaceFenceStatus(e,true);return{token:s,status:this.status(e)}}releaseFence(e,s){const i=this.workspaceFences.get(e);if(i?.delete(s)){if(i.size===0)this.workspaceFences.delete(e);this.setWorkspaceFenceStatus(e,this.isWorkspaceFenced(e))}return this.status(e)}reconcile(e){const s=this.reconcileQueue.then(()=>this.applyReconcile(e));this.reconcileQueue=s.then(()=>void 0,()=>void 0);return this.track(s)}async tick(e=new Date){if(this.activeTickPromise){return this.skippedTick("reentrant",e,true)}const s=this.track(this.performTick(new Date(e.getTime())));this.activeTickPromise=s;void s.then(()=>this.clearActiveTick(s),()=>this.clearActiveTick(s));return s}beginDrain(){if(this.stopped)return;this.draining=true;this.role="draining"}stop(e={}){if(this.stopped&&this.stopPromise)return this.stopPromise;if(this.stopPromise)return this.stopPromise;this.beginDrain();const s=this.waitForDrain(P(e.deadlineMs)).then(i=>{if(!i){return{status:"timeout",timedOut:true,drained:false,leaseReleased:false,role:this.publicRole(),activeTick:this.activeTickPromise!==void 0}}this.stopped=true;const t=this.releaseLease();this.role="stopped";return{status:"stopped",timedOut:false,drained:true,leaseReleased:t,role:this.publicRole(),activeTick:this.activeTickPromise!==void 0}});this.stopPromise=s;void s.then(i=>{if(i.status==="timeout")this.stopPromise=void 0});return s}status(e){const s=Array.from(this.workspaces.values(),({status:t})=>m(t));const i=e===void 0?void 0:s.find(t=>t.id===e);return{enabled:this.enabled,role:this.publicRole(),activeTick:this.activeTickPromise!==void 0,draining:this.draining,stopped:this.stopped,ownerId:this.ownerId,leaseId:this.leaseId,leasePath:this.resolvedLeasePath,...this.standbyReason?{standbyReason:this.standbyReason}:{},workspaces:s,...i?{workspace:i}:{}}}async applyReconcile(e){if(this.stopped||this.draining)return this.status();this.enabled=e.enabled;const s=new Set(e.workspaces.map(t=>t.id));for(const t of this.workspaces.keys()){if(!s.has(t))this.nextWorkspaceRevision(t)}const i=new Map;for(const t of e.workspaces){const o=this.workspaces.get(t.id);const n=o&&o.workspace.path===t.path?o.revision:this.nextWorkspaceRevision(t.id);i.set(t.id,{workspace:{...t},revision:n,status:o&&o.workspace.path===t.path?{...o.status,path:t.path,revision:n,fenced:this.isWorkspaceFenced(t.id)}:{id:t.id,path:t.path,state:"registered",scheduleCount:0,revision:n,fenced:this.isWorkspaceFenced(t.id)}})}this.workspaces.clear();for(const[t,o]of i)this.workspaces.set(t,o);await Promise.all(Array.from(this.workspaces.values(),t=>this.inspectWorkspace(t)));if(this.enabled&&!this.draining&&!this.stopped){this.ensureOwner()}else if(!this.enabled){this.role="disabled"}return this.status()}inspectWorkspace(e){try{const s=this.storeFactory(e.workspace).list();e.status={id:e.workspace.id,path:e.workspace.path,state:"ready",scheduleCount:s.length,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id)}}catch(s){e.status={id:e.workspace.id,path:e.workspace.path,state:"degraded",scheduleCount:0,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id),lastError:c(s)}}}async performTick(e){if(this.stopped)return this.skippedTick("stopped",e,false);if(this.draining)return this.skippedTick("draining",e,false);if(!this.enabled)return this.skippedTick("disabled",e,false);if(!this.ensureOwner())return this.skippedTick("standby",e,false);const s=Array.from(this.workspaces.values());const i=await Promise.all(s.map(t=>this.tickWorkspace(t,e)));return{status:"completed",skipped:false,role:this.publicRole(),now:e.toISOString(),activeTick:true,dispatched:i.reduce((t,o)=>t+o.dispatched,0),workspaces:i}}async tickWorkspace(e,s){if(this.draining||this.stopped){return{id:e.workspace.id,path:e.workspace.path,status:"skipped",scheduleCount:e.status.scheduleCount,dueCount:0,dispatched:0,schedules:[]}}let i;try{i=this.storeFactory(e.workspace).list();e.status={id:e.workspace.id,path:e.workspace.path,state:"ready",scheduleCount:i.length,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id)}}catch(n){const a=c(n);e.status={id:e.workspace.id,path:e.workspace.path,state:"degraded",scheduleCount:0,revision:e.revision,fenced:this.isWorkspaceFenced(e.workspace.id),lastError:a};return{id:e.workspace.id,path:e.workspace.path,status:"degraded",scheduleCount:0,dueCount:0,dispatched:0,schedules:[],error:a}}this.sweepRunRecords(e,s);const t=[];for(const n of i){if(!(0,d.effectiveEnabled)(n))continue;try{if(!this.runPredicate(n.cron,s,n.timezone))continue;const a=(0,d.getLocalMinuteKey)(s,n.timezone);t.push({schedule:n,occurrenceKey:(0,d.buildOccurrenceKey)(n.cron,a)})}catch{}}const o=await Promise.all(t.map(n=>this.admitSchedule(e.workspace,e.revision,n.schedule,n.occurrenceKey)));return{id:e.workspace.id,path:e.workspace.path,status:"completed",scheduleCount:i.length,dueCount:t.length,dispatched:o.filter(n=>n.accepted).length,schedules:o}}sweepRunRecords(e,s){if(e.nextRunSweepAt!==void 0&&s.getTime()<e.nextRunSweepAt)return;e.nextRunSweepAt=s.getTime()+d.SCHEDULE_RUN_SWEEP_INTERVAL_MS;try{(0,d.sweepScheduleRuns)({dir:e.workspace.path,now:s})}catch(i){console.warn(`[cron] run record sweep failed for ${e.workspace.path}: ${c(i).message}`)}}async admitSchedule(e,s,i,t){if(this.draining||this.stopped){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:this.stopped?"stopped":"draining"}}const o=this.testHooks?.beforeExecutorAdmission;if(o){await o({workspace:e,schedule:i,occurrenceKey:t,revision:s})}if(this.draining||this.stopped){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:this.stopped?"stopped":"draining"}}const n=this.workspaces.get(e.id);if(!n||n.workspace.path!==e.path||n.revision!==s){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:"workspace-unregistered"}}if(this.isWorkspaceFenced(e.id)){return{scheduleId:i.id,occurrenceKey:t,status:"skipped",accepted:false,reason:"workspace-fenced"}}try{const a=await this.executor(i,{dir:e.path,trigger:"cron",occurrenceKey:t});return{scheduleId:i.id,occurrenceKey:t,status:a.status,accepted:a.status==="running",..."runId"in a?{runId:a.runId}:{},..."taskId"in a&&a.taskId!==void 0?{taskId:a.taskId}:{},..."reason"in a&&a.reason?{reason:a.reason}:{}}}catch(a){return{scheduleId:i.id,occurrenceKey:t,status:"error",accepted:false,error:c(a).message}}}ensureOwner(){if(this.lease){try{if(this.lease.renew&&!this.lease.renew()){this.forgetLease()}else{this.role="owner";this.standbyReason=void 0;return true}}catch{this.forgetLease()}}if(this.stopped||this.draining||!this.enabled)return false;let e;try{const t={leasePath:this.requestedLeasePath,...this.configuredOwnerId?{ownerId:this.configuredOwnerId}:{}};e=this.leaseProvider.acquire(t)}catch(t){this.role="standby";this.standbyReason=`lease-error:${c(t).message}`;return false}if(!e.acquired){this.role="standby";this.standbyReason=e.reason;this.ownerId=e.record?.ownerId??null;this.leaseId=e.record?.leaseId??null;return false}const s=b(this.resolvedLeasePath,e.ownerId);const i=u.get(s);if(i&&i.runtimeToken!==this.runtimeToken){this.role="standby";this.standbyReason="process-local-owner";this.ownerId=e.ownerId;this.leaseId=e.leaseId;return false}this.lease=e.lease;this.leaseKey=s;this.ownerId=e.ownerId;this.leaseId=e.leaseId;u.set(s,{runtimeToken:this.runtimeToken,ownerId:e.ownerId,lease:e.lease});this.role="owner";this.standbyReason=void 0;return true}forgetLease(){if(this.leaseKey){const e=u.get(this.leaseKey);if(e?.runtimeToken===this.runtimeToken)u.delete(this.leaseKey)}this.lease=void 0;this.leaseKey=void 0;this.ownerId=null;this.leaseId=null;this.role="standby";this.standbyReason="lease-lost"}releaseLease(){if(!this.lease)return true;let e=false;try{e=this.lease.release()}catch{e=false}if(e)this.forgetLease();return e}publicRole(){if(this.stopped)return"stopped";if(this.draining)return"draining";if(!this.enabled)return"disabled";return this.role}skippedTick(e,s,i){return{status:"skipped",skipped:true,reason:e,role:this.publicRole(),now:s.toISOString(),activeTick:i||this.activeTickPromise!==void 0,dispatched:0,workspaces:[]}}clearActiveTick(e){if(this.activeTickPromise===e)this.activeTickPromise=void 0}track(e){let s;s=e.finally(()=>this.operations.delete(s));this.operations.add(s);return s}async waitForDrain(e){const s=Array.from(this.operations);if(s.length===0)return true;const i=Promise.allSettled(s).then(()=>true);if(e<=0)return false;let t;const o=new Promise(a=>{t=setTimeout(()=>a(false),e)});const n=await Promise.race([i,o]);if(t!==void 0)clearTimeout(t);return n}}function S(r={}){return new I(r)}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -141,7 +141,8 @@ export interface ExecuteScheduleOptions {
|
|
|
141
141
|
}
|
|
142
142
|
export interface ExecuteScheduleRunning {
|
|
143
143
|
status: 'running';
|
|
144
|
-
|
|
144
|
+
runId: string;
|
|
145
|
+
taskId?: string;
|
|
145
146
|
done: Promise<ExecuteResult>;
|
|
146
147
|
}
|
|
147
148
|
export interface ExecuteScheduleSkipped {
|
|
@@ -153,6 +154,7 @@ export interface ExecuteScheduleSkipped {
|
|
|
153
154
|
export interface ExecuteScheduleConflict {
|
|
154
155
|
status: 'conflict';
|
|
155
156
|
runningTaskId: string;
|
|
157
|
+
runningRunId?: string;
|
|
156
158
|
reason?: 'execution_lease' | 'occurrence_claim';
|
|
157
159
|
}
|
|
158
160
|
export interface ExecuteScheduleBlocked {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewx/cron",
|
|
3
|
-
"version": "0.1.10-rc.
|
|
3
|
+
"version": "0.1.10-rc.210",
|
|
4
4
|
"description": "Cron Scheduler for CrewX - Schedule and execute crewx commands automatically",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/src/engine.js",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
],
|
|
34
34
|
"license": "MIT",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@crewx/sdk": "0.9.0-rc.
|
|
37
|
-
"@crewx/shared": "0.0.6-rc.
|
|
36
|
+
"@crewx/sdk": "0.9.0-rc.175",
|
|
37
|
+
"@crewx/shared": "0.0.6-rc.90"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^20.0.0",
|