@indigoai-us/hq-cli 5.345.113 → 5.345.115
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/CHANGELOG.md +24 -0
- package/assets/scaffold/core/scripts/hq-delegate-send.sh +5 -1
- package/dist/commands/bot-jobs.d.ts +1 -11
- package/dist/commands/bot-jobs.js +13 -34
- package/dist/commands/capacity.js +2 -0
- package/dist/commands/core-audit-log-native.js +1 -1
- package/dist/commands/core-checkpoint-native.d.ts +27 -0
- package/dist/commands/core-checkpoint-native.js +85 -2
- package/dist/commands/core-dm-bind-native.js +1 -1
- package/dist/commands/core-git-pack-extension-check-native.js +1 -1
- package/dist/commands/core-job-native-utils.d.ts +2 -2
- package/dist/commands/core-job-native-utils.js +3 -11
- package/dist/commands/core-job-notify-native.js +1 -2
- package/dist/commands/core-job-probe-native.d.ts +2 -3
- package/dist/commands/core-job-probe-native.js +14 -22
- package/dist/commands/core-job-remediate-native.js +1 -2
- package/dist/commands/core-job-run-native.js +58 -54
- package/dist/commands/core-jobs-native.d.ts +1 -3
- package/dist/commands/core-jobs-native.js +16 -271
- package/dist/commands/core-jobs-schedule.d.ts +7 -0
- package/dist/commands/core-jobs-schedule.js +243 -0
- package/dist/commands/core-native-utilities.d.ts +2 -3
- package/dist/commands/core-native-utilities.js +2 -19
- package/dist/commands/core-pin-native.js +1 -1
- package/dist/commands/core-refresh-vault-access-native.js +1 -1
- package/dist/commands/core-resolve-company-command.js +2 -17
- package/dist/commands/core-work-mesh-bind-trusted-native.js +1 -1
- package/dist/commands/core.js +1 -17
- package/dist/commands/lanes.js +1 -0
- package/dist/fast-scaffold.d.ts +1 -1
- package/dist/fast-scaffold.js +0 -38
- package/dist/lib/capacity/lane-login.js +73 -6
- package/dist/lib/capacity/route.d.ts +1 -1
- package/dist/lib/capacity/route.js +5 -1
- package/dist/lib/capacity/sign-in.d.ts +12 -0
- package/dist/lib/capacity/sign-in.js +65 -16
- package/dist/lib/daemon/catalog.d.ts +0 -2
- package/dist/lib/daemon/catalog.js +3 -6
- package/dist/lib/daemon/run.js +0 -7
- package/dist/utils/resident-package-preload.js +2 -7
- package/package.json +1 -1
- package/assets/scaffold/core/scripts/audit-log.sh +0 -384
- package/assets/scaffold/core/scripts/git-pack-extension-check.sh +0 -164
- package/assets/scaffold/core/scripts/hq-dm-bind.sh +0 -590
- package/assets/scaffold/core/scripts/hq-job-notify.sh +0 -389
- package/assets/scaffold/core/scripts/hq-job-probe.sh +0 -865
- package/assets/scaffold/core/scripts/hq-job-remediate.sh +0 -359
- package/assets/scaffold/core/scripts/hq-job-run.sh +0 -1025
- package/assets/scaffold/core/scripts/hq-pin.sh +0 -118
- package/assets/scaffold/core/scripts/jobs-schedule-parse.sh +0 -310
- package/assets/scaffold/core/scripts/jobs-validate.sh +0 -482
- package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +0 -836
- package/assets/scaffold/core/scripts/refresh-vault-access.sh +0 -188
- package/assets/scaffold/core/scripts/resolve-company.sh +0 -331
- package/assets/scaffold/core/scripts/work-mesh-live-bind-trusted.sh +0 -184
- package/dist/commands/core-job-post-exit-assets.d.ts +0 -8
- package/dist/commands/core-job-post-exit-assets.js +0 -37
- package/dist/commands/core-native-jobs-flag.d.ts +0 -4
- package/dist/commands/core-native-jobs-flag.js +0 -7
- package/dist/commands/core-native-utilities-flag.d.ts +0 -4
- package/dist/commands/core-native-utilities-flag.js +0 -7
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# hq-pin.sh — anchor the current session to one goal (the "pin").
|
|
3
|
-
#
|
|
4
|
-
# A pin is the message, goal, or target the session keeps working toward
|
|
5
|
-
# across loops, wakeups, compactions, and hand-offs. It is stored per session
|
|
6
|
-
# and re-read at every checkpoint so the session cannot drift.
|
|
7
|
-
#
|
|
8
|
-
# Usage:
|
|
9
|
-
# core/scripts/hq-pin.sh set "<goal>" [--done "<criterion>"]... [--owner <name>] [--channel <dm-channel>]
|
|
10
|
-
# core/scripts/hq-pin.sh show # print the pin (goal, done criteria, owner, channel, set-at)
|
|
11
|
-
# core/scripts/hq-pin.sh check # print a one-line reminder for loop ticks; exit 3 if no pin
|
|
12
|
-
# core/scripts/hq-pin.sh note "<progress>" # append a dated progress line under the pin
|
|
13
|
-
# core/scripts/hq-pin.sh clear # remove the pin (the goal is met or withdrawn)
|
|
14
|
-
#
|
|
15
|
-
# Storage: workspace/sessions/<sid>/pin.md plus `pin: <goal>` in the session's
|
|
16
|
-
# meta.yaml (via hq-session.sh) so other tooling can see it.
|
|
17
|
-
set -euo pipefail
|
|
18
|
-
|
|
19
|
-
HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
|
20
|
-
SESSION_SH="$HQ_ROOT/core/scripts/hq-session.sh"
|
|
21
|
-
|
|
22
|
-
die() { echo "hq-pin: $*" >&2; exit 2; }
|
|
23
|
-
|
|
24
|
-
session_id() { bash "$SESSION_SH" current 2>/dev/null || true; }
|
|
25
|
-
pin_file() {
|
|
26
|
-
local sid; sid="$(session_id)"
|
|
27
|
-
[ -n "$sid" ] || die "no current session (hq-session.sh current is empty)"
|
|
28
|
-
local d="$HQ_ROOT/workspace/sessions/$sid"; mkdir -p "$d"; echo "$d/pin.md"
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
cmd_set() {
|
|
32
|
-
local goal="${1:-}"; [ -n "$goal" ] || die "set needs the goal text"; shift
|
|
33
|
-
local owner="" channel=""; local -a done=()
|
|
34
|
-
while [ $# -gt 0 ]; do
|
|
35
|
-
case "$1" in
|
|
36
|
-
--done) done+=("$2"); shift 2 ;;
|
|
37
|
-
--owner) owner="$2"; shift 2 ;;
|
|
38
|
-
--channel) channel="$2"; shift 2 ;;
|
|
39
|
-
*) die "set: unknown arg $1" ;;
|
|
40
|
-
esac
|
|
41
|
-
done
|
|
42
|
-
local f; f="$(pin_file)"
|
|
43
|
-
{
|
|
44
|
-
echo "# Pin"
|
|
45
|
-
echo
|
|
46
|
-
echo "Goal: $goal"
|
|
47
|
-
echo
|
|
48
|
-
echo "Set: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
49
|
-
[ -n "$owner" ] && echo "Owner: $owner"
|
|
50
|
-
[ -n "$channel" ] && echo "Channel: $channel"
|
|
51
|
-
if [ ${#done[@]} -gt 0 ]; then
|
|
52
|
-
echo
|
|
53
|
-
echo "## Done when"
|
|
54
|
-
for c in "${done[@]}"; do echo "- [ ] $c"; done
|
|
55
|
-
fi
|
|
56
|
-
echo
|
|
57
|
-
echo "## Progress"
|
|
58
|
-
} > "$f"
|
|
59
|
-
bash "$SESSION_SH" set pin "$goal" >/dev/null
|
|
60
|
-
echo "pinned session $(session_id): $goal"
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
cmd_show() {
|
|
64
|
-
local f; f="$(pin_file)"
|
|
65
|
-
[ -f "$f" ] || { echo "no pin for session $(session_id)"; return 3; }
|
|
66
|
-
cat "$f"
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
cmd_check() {
|
|
70
|
-
local f; f="$(pin_file)"
|
|
71
|
-
[ -f "$f" ] || { echo "no pin"; return 3; }
|
|
72
|
-
local goal; goal="$(sed -n 's/^Goal: //p' "$f" | head -1)"
|
|
73
|
-
local open; open="$(grep -c '^- \[ \]' "$f" 2>/dev/null || true)"
|
|
74
|
-
local closed; closed="$(grep -c '^- \[x\]' "$f" 2>/dev/null || true)"
|
|
75
|
-
echo "PIN: $goal (done criteria: ${closed:-0} met, ${open:-0} open)"
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
cmd_note() {
|
|
79
|
-
local text="${1:-}"; [ -n "$text" ] || die "note needs text"
|
|
80
|
-
local f; f="$(pin_file)"
|
|
81
|
-
[ -f "$f" ] || die "no pin to note against"
|
|
82
|
-
printf -- '- %s %s\n' "$(date -u +%H:%MZ)" "$text" >> "$f"
|
|
83
|
-
echo "noted"
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
cmd_done() {
|
|
87
|
-
# Mark a done-criterion met by substring match.
|
|
88
|
-
local needle="${1:-}"; [ -n "$needle" ] || die "done needs a criterion substring"
|
|
89
|
-
local f; f="$(pin_file)"
|
|
90
|
-
[ -f "$f" ] || die "no pin"
|
|
91
|
-
local tmp; tmp="$(mktemp)"
|
|
92
|
-
local hit=0
|
|
93
|
-
while IFS= read -r line; do
|
|
94
|
-
case "$line" in
|
|
95
|
-
"- [ ] "*"$needle"*) echo "- [x] ${line#- [ ] }"; hit=1 ;;
|
|
96
|
-
*) echo "$line" ;;
|
|
97
|
-
esac
|
|
98
|
-
done < "$f" > "$tmp"
|
|
99
|
-
mv "$tmp" "$f"
|
|
100
|
-
[ "$hit" = 1 ] && echo "marked done: $needle" || die "no open criterion matches: $needle"
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
cmd_clear() {
|
|
104
|
-
local f; f="$(pin_file)"
|
|
105
|
-
rm -f "$f"
|
|
106
|
-
bash "$SESSION_SH" set pin "" >/dev/null
|
|
107
|
-
echo "pin cleared"
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
case "${1:-}" in
|
|
111
|
-
set) shift; cmd_set "$@" ;;
|
|
112
|
-
show) cmd_show ;;
|
|
113
|
-
check) cmd_check ;;
|
|
114
|
-
note) shift; cmd_note "$@" ;;
|
|
115
|
-
done) shift; cmd_done "$@" ;;
|
|
116
|
-
clear) cmd_clear ;;
|
|
117
|
-
*) sed -n '2,15p' "$0"; exit 2 ;;
|
|
118
|
-
esac
|
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# hq-core: public
|
|
3
|
-
# jobs-schedule-parse.sh — resolve natural-language (or raw cron) schedules for /schedule.
|
|
4
|
-
#
|
|
5
|
-
# Usage:
|
|
6
|
-
# core/scripts/jobs-schedule-parse.sh [--tz IANA] [--json] "<schedule text>"
|
|
7
|
-
#
|
|
8
|
-
# Prints one JSON object on stdout:
|
|
9
|
-
# {"ok":true,"cron":"0 9 * * 1-5","timezone":"America/Los_Angeles",
|
|
10
|
-
# "human":"Every weekday at 9:00 AM (America/Los_Angeles)","source":"nl"|"cron"}
|
|
11
|
-
# {"ok":false,"error":"..."}
|
|
12
|
-
#
|
|
13
|
-
# Cron is always the canonical 5-field form. NL is never echoed back as storage.
|
|
14
|
-
# Timezone defaults to the host IANA zone (macOS /etc/localtime, $TZ, or UTC).
|
|
15
|
-
#
|
|
16
|
-
# Requires: node. Optional: jq (not required for parse).
|
|
17
|
-
|
|
18
|
-
set -euo pipefail
|
|
19
|
-
|
|
20
|
-
TZ_OVERRIDE=""
|
|
21
|
-
|
|
22
|
-
usage() {
|
|
23
|
-
echo "usage: jobs-schedule-parse.sh [--tz IANA] \"<nl or cron schedule>\"" >&2
|
|
24
|
-
exit 2
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
while [ "$#" -gt 0 ]; do
|
|
28
|
-
case "$1" in
|
|
29
|
-
--tz)
|
|
30
|
-
[ "$#" -ge 2 ] || usage
|
|
31
|
-
TZ_OVERRIDE="$2"
|
|
32
|
-
shift 2
|
|
33
|
-
;;
|
|
34
|
-
--json)
|
|
35
|
-
# JSON is the only output mode; flag kept for callers/docs symmetry
|
|
36
|
-
shift
|
|
37
|
-
;;
|
|
38
|
-
-h|--help)
|
|
39
|
-
usage
|
|
40
|
-
;;
|
|
41
|
-
--)
|
|
42
|
-
shift
|
|
43
|
-
break
|
|
44
|
-
;;
|
|
45
|
-
-*)
|
|
46
|
-
echo "jobs-schedule-parse: unknown flag: $1" >&2
|
|
47
|
-
usage
|
|
48
|
-
;;
|
|
49
|
-
*)
|
|
50
|
-
break
|
|
51
|
-
;;
|
|
52
|
-
esac
|
|
53
|
-
done
|
|
54
|
-
|
|
55
|
-
[ "$#" -ge 1 ] || usage
|
|
56
|
-
SCHEDULE="$*"
|
|
57
|
-
SCHEDULE="$(printf '%s' "$SCHEDULE" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
|
58
|
-
[ -n "$SCHEDULE" ] || {
|
|
59
|
-
printf '%s\n' '{"ok":false,"error":"empty schedule"}'
|
|
60
|
-
exit 1
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export JOBS_SCHEDULE_PARSE_INPUT="$SCHEDULE"
|
|
64
|
-
export JOBS_SCHEDULE_PARSE_TZ="${TZ_OVERRIDE}"
|
|
65
|
-
|
|
66
|
-
node <<'JS'
|
|
67
|
-
const fs = require("fs");
|
|
68
|
-
const path = require("path");
|
|
69
|
-
const { execFileSync } = require("child_process");
|
|
70
|
-
|
|
71
|
-
const inp = (process.env.JOBS_SCHEDULE_PARSE_INPUT || "").trim();
|
|
72
|
-
const tzOverride = (process.env.JOBS_SCHEDULE_PARSE_TZ || "").trim();
|
|
73
|
-
|
|
74
|
-
function fail(msg, code = 1) {
|
|
75
|
-
process.stdout.write(JSON.stringify({ ok: false, error: msg }));
|
|
76
|
-
process.stdout.write("\n");
|
|
77
|
-
process.exit(code);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function detectTz() {
|
|
81
|
-
if (tzOverride) return tzOverride;
|
|
82
|
-
const envTz = (process.env.TZ || "").trim();
|
|
83
|
-
if (envTz && envTz.includes("/")) return envTz;
|
|
84
|
-
try {
|
|
85
|
-
const link = fs.realpathSync("/etc/localtime");
|
|
86
|
-
const parts = link.split(path.sep).filter(Boolean);
|
|
87
|
-
const i = parts.indexOf("zoneinfo");
|
|
88
|
-
if (i >= 0) {
|
|
89
|
-
const cand = parts.slice(i + 1).join("/");
|
|
90
|
-
if (cand) return cand;
|
|
91
|
-
}
|
|
92
|
-
} catch (_) {
|
|
93
|
-
/* ignore */
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const out = execFileSync(
|
|
97
|
-
"timedatectl",
|
|
98
|
-
["show", "-p", "Timezone", "--value"],
|
|
99
|
-
{ encoding: "utf8", timeout: 2000, stdio: ["ignore", "pipe", "ignore"] }
|
|
100
|
-
).trim();
|
|
101
|
-
if (out && out.includes("/")) return out;
|
|
102
|
-
} catch (_) {
|
|
103
|
-
/* ignore */
|
|
104
|
-
}
|
|
105
|
-
return "UTC";
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function validateIana(tz) {
|
|
109
|
-
const wellFormed = /^(UTC|[A-Za-z0-9_+\-]+(\/[A-Za-z0-9_+\-]+)+)$/;
|
|
110
|
-
if (!wellFormed.test(tz)) return false;
|
|
111
|
-
try {
|
|
112
|
-
Intl.DateTimeFormat(undefined, { timeZone: tz });
|
|
113
|
-
return true;
|
|
114
|
-
} catch (_) {
|
|
115
|
-
// Intl may lack tzdata on some hosts — accept well-formed names
|
|
116
|
-
return wellFormed.test(tz);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const CRON_RE = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/;
|
|
121
|
-
|
|
122
|
-
const DOW_NAMES = {
|
|
123
|
-
sun: 0,
|
|
124
|
-
sunday: 0,
|
|
125
|
-
mon: 1,
|
|
126
|
-
monday: 1,
|
|
127
|
-
tue: 2,
|
|
128
|
-
tues: 2,
|
|
129
|
-
tuesday: 2,
|
|
130
|
-
wed: 3,
|
|
131
|
-
wednesday: 3,
|
|
132
|
-
thu: 4,
|
|
133
|
-
thur: 4,
|
|
134
|
-
thurs: 4,
|
|
135
|
-
thursday: 4,
|
|
136
|
-
fri: 5,
|
|
137
|
-
friday: 5,
|
|
138
|
-
sat: 6,
|
|
139
|
-
saturday: 6,
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const DOW_LABEL = {
|
|
143
|
-
"0": "Sunday",
|
|
144
|
-
"1": "Monday",
|
|
145
|
-
"2": "Tuesday",
|
|
146
|
-
"3": "Wednesday",
|
|
147
|
-
"4": "Thursday",
|
|
148
|
-
"5": "Friday",
|
|
149
|
-
"6": "Saturday",
|
|
150
|
-
"1-5": "weekday",
|
|
151
|
-
"*": "day",
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
function parseClock(fragment) {
|
|
155
|
-
const s = fragment.trim().toLowerCase().replace(/ /g, "");
|
|
156
|
-
const m = /^(\d{1,2})(?::(\d{2}))?\s*(am|pm)?$/.exec(s);
|
|
157
|
-
if (!m) return null;
|
|
158
|
-
let hour = parseInt(m[1], 10);
|
|
159
|
-
const minute = parseInt(m[2] || "0", 10);
|
|
160
|
-
const ampm = m[3];
|
|
161
|
-
if (minute > 59) return null;
|
|
162
|
-
if (ampm) {
|
|
163
|
-
if (hour < 1 || hour > 12) return null;
|
|
164
|
-
if (ampm === "am") hour = hour === 12 ? 0 : hour;
|
|
165
|
-
else hour = hour === 12 ? 12 : hour + 12;
|
|
166
|
-
} else if (hour > 23) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
return [hour, minute];
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function fmtClock(hour, minute) {
|
|
173
|
-
const suffix = hour < 12 ? "AM" : "PM";
|
|
174
|
-
let h12 = hour % 12;
|
|
175
|
-
if (h12 === 0) h12 = 12;
|
|
176
|
-
return `${h12}:${String(minute).padStart(2, "0")} ${suffix}`;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function humanizeCron(cron, tz) {
|
|
180
|
-
const parts = cron.split(/\s+/);
|
|
181
|
-
if (parts.length !== 5) return `Cron \`${cron}\` (${tz})`;
|
|
182
|
-
const [minute, hour, dom, month, dow] = parts;
|
|
183
|
-
if (
|
|
184
|
-
/^\d+$/.test(minute) &&
|
|
185
|
-
/^\d+$/.test(hour) &&
|
|
186
|
-
dom === "*" &&
|
|
187
|
-
month === "*" &&
|
|
188
|
-
(dow === "*" || dow === "1-5")
|
|
189
|
-
) {
|
|
190
|
-
const clock = fmtClock(parseInt(hour, 10), parseInt(minute, 10));
|
|
191
|
-
if (dow === "1-5") return `Every weekday at ${clock} (${tz})`;
|
|
192
|
-
return `Every day at ${clock} (${tz})`;
|
|
193
|
-
}
|
|
194
|
-
if (
|
|
195
|
-
/^\d+$/.test(minute) &&
|
|
196
|
-
/^\d+$/.test(hour) &&
|
|
197
|
-
dom === "*" &&
|
|
198
|
-
month === "*" &&
|
|
199
|
-
/^\d+$/.test(dow)
|
|
200
|
-
) {
|
|
201
|
-
const day = DOW_LABEL[dow] || `day ${dow}`;
|
|
202
|
-
return `Every ${day} at ${fmtClock(parseInt(hour, 10), parseInt(minute, 10))} (${tz})`;
|
|
203
|
-
}
|
|
204
|
-
if (minute.startsWith("*/") && hour === "*" && dom === "*" && month === "*" && dow === "*") {
|
|
205
|
-
return `Every ${minute.slice(2)} minutes (${tz})`;
|
|
206
|
-
}
|
|
207
|
-
if (minute === "0" && hour.startsWith("*/") && dom === "*" && month === "*" && dow === "*") {
|
|
208
|
-
return `Every ${hour.slice(2)} hours (${tz})`;
|
|
209
|
-
}
|
|
210
|
-
if (minute === "0" && hour === "*" && dom === "*" && month === "*" && dow === "*") {
|
|
211
|
-
return `Every hour on the hour (${tz})`;
|
|
212
|
-
}
|
|
213
|
-
return `Cron \`${cron}\` (${tz})`;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function parseNl(text) {
|
|
217
|
-
const s = text.trim();
|
|
218
|
-
const low = s.toLowerCase();
|
|
219
|
-
let m = /^every\s+(\d+)\s+minutes?$/.exec(low);
|
|
220
|
-
if (m) {
|
|
221
|
-
const n = parseInt(m[1], 10);
|
|
222
|
-
if (n < 1 || n > 59) return [null, "minute interval must be 1..59"];
|
|
223
|
-
return [`*/${n} * * * *`, `Every ${n} minutes`];
|
|
224
|
-
}
|
|
225
|
-
if (low === "every hour" || low === "hourly") {
|
|
226
|
-
return ["0 * * * *", "Every hour on the hour"];
|
|
227
|
-
}
|
|
228
|
-
m = /^every\s+(\d+)\s+hours?$/.exec(low);
|
|
229
|
-
if (m) {
|
|
230
|
-
const n = parseInt(m[1], 10);
|
|
231
|
-
if (n < 1 || n > 23) return [null, "hour interval must be 1..23"];
|
|
232
|
-
return [`0 */${n} * * *`, `Every ${n} hours`];
|
|
233
|
-
}
|
|
234
|
-
m = /^(?:every\s+)?(weekday|weekdays|day|daily)\s+(?:at\s+)?(.+)$/.exec(low);
|
|
235
|
-
if (m) {
|
|
236
|
-
const kind = m[1];
|
|
237
|
-
const clock = parseClock(m[2]);
|
|
238
|
-
if (!clock) return [null, `could not parse time: ${m[2]}`];
|
|
239
|
-
const [hour, minute] = clock;
|
|
240
|
-
if (kind === "weekday" || kind === "weekdays") {
|
|
241
|
-
return [`${minute} ${hour} * * 1-5`, `Every weekday at ${fmtClock(hour, minute)}`];
|
|
242
|
-
}
|
|
243
|
-
return [`${minute} ${hour} * * *`, `Every day at ${fmtClock(hour, minute)}`];
|
|
244
|
-
}
|
|
245
|
-
m =
|
|
246
|
-
/^(?:every\s+)?(sun(?:day)?|mon(?:day)?|tue(?:s|sday)?|wed(?:nesday)?|thu(?:r|rs|rsday)?|fri(?:day)?|sat(?:urday)?)s?\s+(?:at\s+)?(.+)$/.exec(
|
|
247
|
-
low
|
|
248
|
-
);
|
|
249
|
-
if (m) {
|
|
250
|
-
const dow = DOW_NAMES[m[1]];
|
|
251
|
-
const clock = parseClock(m[2]);
|
|
252
|
-
if (!clock) return [null, `could not parse time: ${m[2]}`];
|
|
253
|
-
const [hour, minute] = clock;
|
|
254
|
-
return [
|
|
255
|
-
`${minute} ${hour} * * ${dow}`,
|
|
256
|
-
`Every ${DOW_LABEL[String(dow)]} at ${fmtClock(hour, minute)}`,
|
|
257
|
-
];
|
|
258
|
-
}
|
|
259
|
-
m = /^at\s+(.+?)\s+every\s+(weekday|weekdays|day|daily)$/.exec(low);
|
|
260
|
-
if (m) {
|
|
261
|
-
const clock = parseClock(m[1]);
|
|
262
|
-
if (!clock) return [null, `could not parse time: ${m[1]}`];
|
|
263
|
-
const [hour, minute] = clock;
|
|
264
|
-
const kind = m[2];
|
|
265
|
-
if (kind === "weekday" || kind === "weekdays") {
|
|
266
|
-
return [`${minute} ${hour} * * 1-5`, `Every weekday at ${fmtClock(hour, minute)}`];
|
|
267
|
-
}
|
|
268
|
-
return [`${minute} ${hour} * * *`, `Every day at ${fmtClock(hour, minute)}`];
|
|
269
|
-
}
|
|
270
|
-
return [
|
|
271
|
-
null,
|
|
272
|
-
"unrecognized schedule — try 'every weekday at 9am', " +
|
|
273
|
-
"'every day at 14:30', 'every monday at 9am', a 5-field cron, " +
|
|
274
|
-
"or 'every 15 minutes'",
|
|
275
|
-
];
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const tz = detectTz();
|
|
279
|
-
if (!validateIana(tz)) fail(`invalid IANA timezone: ${tz}`);
|
|
280
|
-
|
|
281
|
-
if (CRON_RE.test(inp) && !/[A-Za-z]/.test(inp)) {
|
|
282
|
-
const cron = inp;
|
|
283
|
-
const human = humanizeCron(cron, tz);
|
|
284
|
-
process.stdout.write(
|
|
285
|
-
JSON.stringify({ ok: true, cron, timezone: tz, human, source: "cron" })
|
|
286
|
-
);
|
|
287
|
-
process.stdout.write("\n");
|
|
288
|
-
process.exit(0);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const named = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(mon-fri|monday-friday)$/i.exec(inp);
|
|
292
|
-
if (named) {
|
|
293
|
-
const cron = `${named[1]} ${named[2]} ${named[3]} ${named[4]} 1-5`;
|
|
294
|
-
const human = humanizeCron(cron, tz);
|
|
295
|
-
process.stdout.write(
|
|
296
|
-
JSON.stringify({ ok: true, cron, timezone: tz, human, source: "cron" })
|
|
297
|
-
);
|
|
298
|
-
process.stdout.write("\n");
|
|
299
|
-
process.exit(0);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const [cron, humanOrErr] = parseNl(inp);
|
|
303
|
-
if (cron == null) fail(humanOrErr);
|
|
304
|
-
|
|
305
|
-
const human = `${humanOrErr} (${tz})`;
|
|
306
|
-
process.stdout.write(
|
|
307
|
-
JSON.stringify({ ok: true, cron, timezone: tz, human, source: "nl" })
|
|
308
|
-
);
|
|
309
|
-
process.stdout.write("\n");
|
|
310
|
-
JS
|