@jonit-dev/night-watch-cli 1.8.4-beta.8 → 1.8.4-beta.9

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/dist/cli.js CHANGED
@@ -6966,7 +6966,7 @@ async function fetchAmplitudeData(apiKey, secretKey, lookbackDays) {
6966
6966
  const baseUrl = "https://amplitude.com/api/2";
6967
6967
  const allEventsParam = encodeURIComponent('{"event_type":"_all"}');
6968
6968
  const [activeUsers, eventSegmentation, retention, userSessions] = await Promise.allSettled([
6969
- amplitudeFetch(`${baseUrl}/users/active?start=${start}&end=${end}`, authHeader, "active users"),
6969
+ amplitudeFetch(`${baseUrl}/users?m=active&start=${start}&end=${end}`, authHeader, "active users"),
6970
6970
  amplitudeFetch(`${baseUrl}/events/segmentation?start=${start}&end=${end}&e=${allEventsParam}`, authHeader, "event segmentation"),
6971
6971
  amplitudeFetch(`${baseUrl}/retention?se=${allEventsParam}&re=${allEventsParam}&start=${start}&end=${end}`, authHeader, "retention"),
6972
6972
  amplitudeFetch(`${baseUrl}/sessions/average?start=${start}&end=${end}`, authHeader, "user sessions")
@@ -7037,9 +7037,13 @@ ${JSON.stringify(data, null, 2)}`;
7037
7037
  fs19.writeFileSync(promptFile, prompt, "utf-8");
7038
7038
  try {
7039
7039
  const provider = resolveJobProvider(config, "analytics");
7040
- const providerCmd = PROVIDER_COMMANDS[provider];
7040
+ let providerCmd = PROVIDER_COMMANDS[provider];
7041
+ if (!providerCmd) {
7042
+ const preset = resolvePreset(config, provider);
7043
+ providerCmd = preset.command;
7044
+ }
7041
7045
  let scriptContent;
7042
- if (provider === "claude") {
7046
+ if (providerCmd === "claude") {
7043
7047
  const modelId = CLAUDE_MODEL_IDS[config.claudeModel ?? "sonnet"];
7044
7048
  scriptContent = `#!/usr/bin/env bash
7045
7049
  set -euo pipefail
@@ -242,7 +242,7 @@ count_prs_for_branch() {
242
242
  local branch_name="${2:?branch_name required}"
243
243
  local count
244
244
  count=$(
245
- { gh pr list --state "${pr_state}" --json headRefName --jq '.[].headRefName' 2>/dev/null || true; } \
245
+ { gh pr list --state "${pr_state}" --limit 200 --json headRefName --jq '.[].headRefName' 2>/dev/null || true; } \
246
246
  | { grep -xF "${branch_name}" || true; } \
247
247
  | wc -l \
248
248
  | tr -d '[:space:]'
@@ -773,6 +773,20 @@ fi
773
773
  TOTAL_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
774
774
  log "OUTCOME: exit_code=${EXIT_CODE} total_elapsed=${TOTAL_ELAPSED}s prd=${ELIGIBLE_PRD} branch=${BRANCH_NAME}"
775
775
 
776
+ # Detect false-success from budget exhaustion.
777
+ # Claude exits 0 even when it hits the $ budget cap, so scan the log.
778
+ if [ "${EXIT_CODE}" -eq 0 ] && grep -qiF 'Exceeded USD budget' "${LOG_FILE}" 2>/dev/null; then
779
+ log "WARN: provider exited 0 but budget was exceeded — reclassifying as failure"
780
+ if [ -n "${ISSUE_NUMBER}" ]; then
781
+ "${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "Ready" 2>>"${LOG_FILE}" || true
782
+ "${NW_CLI}" board comment "${ISSUE_NUMBER}" \
783
+ --body "Budget limit reached (via ${EFFECTIVE_PROVIDER_LABEL}). Moved back to Ready." 2>>"${LOG_FILE}" || true
784
+ fi
785
+ night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code 1 2>/dev/null || true
786
+ emit_result "failure_budget_exceeded" "prd=${ELIGIBLE_PRD}|branch=${BRANCH_NAME}|reason=budget_exceeded"
787
+ EXIT_CODE=1
788
+ fi
789
+
776
790
  if [ ${EXIT_CODE} -eq 0 ]; then
777
791
  OPEN_PR_COUNT=$(count_prs_for_branch open "${BRANCH_NAME}")
778
792
  if [ "${OPEN_PR_COUNT}" -gt 0 ]; then
@@ -830,13 +830,33 @@ if [ -z "${TARGET_PR}" ] && [ "${WORKER_MODE}" != "1" ] && [ "${PARALLEL_ENABLED
830
830
  worker_pr="${WORKER_PRS[$idx]}"
831
831
  worker_output="${WORKER_OUTPUTS[$idx]}"
832
832
 
833
+ # Guard: abort the wait loop when the global budget is exhausted
834
+ PARENT_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
835
+ PARENT_REMAINING=$(( MAX_RUNTIME - PARENT_ELAPSED ))
836
+ if [ "${PARENT_REMAINING}" -le 0 ]; then
837
+ log "PARALLEL: global timeout exhausted — killing remaining workers"
838
+ for remaining_idx in $(seq "${idx}" $(( ${#WORKER_PIDS[@]} - 1 ))); do
839
+ kill "${WORKER_PIDS[$remaining_idx]}" 2>/dev/null || true
840
+ done
841
+ EXIT_CODE=124
842
+ break
843
+ fi
844
+
845
+ # Watchdog: kill the worker if it outlives the remaining budget
846
+ ( sleep "${PARENT_REMAINING}" 2>/dev/null; kill "${worker_pid}" 2>/dev/null || true ) &
847
+ watchdog_pid=$!
848
+
833
849
  worker_exit_code=0
834
- if wait "${worker_pid}"; then
850
+ if wait "${worker_pid}" 2>/dev/null; then
835
851
  worker_exit_code=0
836
852
  else
837
853
  worker_exit_code=$?
838
854
  fi
839
855
 
856
+ # Cancel the watchdog — the worker finished in time
857
+ kill "${watchdog_pid}" 2>/dev/null || true
858
+ wait "${watchdog_pid}" 2>/dev/null || true
859
+
840
860
  if [ -f "${worker_output}" ] && [ -s "${worker_output}" ]; then
841
861
  cat "${worker_output}" >> "${LOG_FILE}"
842
862
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jonit-dev/night-watch-cli",
3
- "version": "1.8.4-beta.8",
3
+ "version": "1.8.4-beta.9",
4
4
  "description": "AI agent that implements your specs, opens PRs, and reviews code overnight. Queue GitHub issues or PRDs, wake up to pull requests.",
5
5
  "type": "module",
6
6
  "bin": {