harlay 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app/dist/main.cjs CHANGED
@@ -3195,24 +3195,77 @@ function assessHealth(s, context) {
3195
3195
 
3196
3196
  // ../../packages/core/src/webchat.ts
3197
3197
  var import_node_path19 = require("node:path");
3198
+ var LIMIT_NOTICES = [
3199
+ // claude.ai
3200
+ "Usage limit reached",
3201
+ "You've reached your session limit",
3202
+ "You've reached your weekly limit",
3203
+ "You've reached your weekly Cowork limit",
3204
+ "You've reached your usage limit",
3205
+ "You've reached your plan's usage limit",
3206
+ "You've reached your monthly spend limit",
3207
+ "You've reached your * limit. Get more usage",
3208
+ "Reached your session limit",
3209
+ "Reached your weekly limit",
3210
+ "Reached your weekly Cowork limit",
3211
+ "Reached your usage limit",
3212
+ "Reached your * limit$",
3213
+ "* limit reached$",
3214
+ "Out of free messages",
3215
+ "You hit your message limit",
3216
+ "You hit your 5-hour message limit",
3217
+ "You hit your weekly message limit",
3218
+ "You hit your weekly * limit",
3219
+ "You hit your usage limit",
3220
+ "You hit the Free plan's",
3221
+ "You just hit your free message limit",
3222
+ "You've hit your limit for Claude messages",
3223
+ "You've hit your session limit",
3224
+ "You've hit your weekly limit",
3225
+ "You've hit your usage limit",
3226
+ "You've hit your monthly spend limit",
3227
+ "Your usage limit is still exceeded",
3228
+ "Paused: Your usage limit",
3229
+ "Limit hit. Your week resets",
3230
+ "Limit hit. You can send new messages",
3231
+ "Try again after your * resets",
3232
+ "Send a message after your * resets",
3233
+ "Wait for your * to reset",
3234
+ "Your * resets * Try again then",
3235
+ "Your * resets * Send a message then",
3236
+ // ChatGPT, signed out
3237
+ "You have reached the anonymous message limit"
3238
+ ];
3198
3239
  function isLimitText(s) {
3199
- const t = s.replace(/\s+/g, " ");
3200
- if (t.length > 400) return false;
3201
- if (!/\blimits?\b|out of (?:free )?messages/i.test(t)) return false;
3202
- return /\b(?:hit|reached|exceeded|out of|resets?|reset at|until|try again)\b/i.test(t);
3240
+ const self = isLimitText;
3241
+ if (!self.patterns) {
3242
+ self.patterns = (self.notices ?? LIMIT_NOTICES).map((n) => {
3243
+ const whole2 = n.endsWith("$");
3244
+ const body = (whole2 ? n.slice(0, -1) : n).replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".{1,60}?");
3245
+ return new RegExp(`^${body}${whole2 ? "$" : ""}`, "i");
3246
+ });
3247
+ }
3248
+ const t = s.replace(/[’‘]/g, "'").replace(/\s+/g, " ").trim();
3249
+ if (/\b(?:upload|image|file|length|storage|project|artifact|translation|read aloud)\b/i.test(t)) return false;
3250
+ return t.length > 0 && t.length <= 300 && self.patterns.some((p) => p.test(t));
3203
3251
  }
3252
+ var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
3204
3253
  function limitResetsAt(s, now) {
3205
3254
  const inHours = /\bin (\d+) hours?\b/i.exec(s);
3206
3255
  if (inHours) return new Date(now.getTime() + Number(inHours[1]) * 36e5);
3207
3256
  const inMinutes = /\bin (\d+) min(?:ute)?s?\b/i.exec(s);
3208
3257
  if (inMinutes) return new Date(now.getTime() + Number(inMinutes[1]) * 6e4);
3209
- const m = /\b(\d{1,2})(?::(\d{2}))?\s*(am|pm)\b/i.exec(s);
3258
+ const m = /\b(\d{1,2})(?::(\d{2}))?\s*(am|pm)\b/i.exec(s) ?? /\b(\d{1,2}):(\d{2})\b()/.exec(s);
3210
3259
  if (!m) return null;
3211
- let h = Number(m[1]) % 12;
3212
- if (m[3].toLowerCase() === "pm") h += 12;
3260
+ let h = Number(m[1]);
3261
+ if (m[3]) h = h % 12 + (m[3].toLowerCase() === "pm" ? 12 : 0);
3213
3262
  const at = new Date(now);
3214
3263
  at.setHours(h, m[2] ? Number(m[2]) : 0, 0, 0);
3215
- if (at.getTime() <= now.getTime()) at.setDate(at.getDate() + 1);
3264
+ const day = /\b(sun|mon|tue|wed|thu|fri|sat)[a-z]*\b/i.exec(s);
3265
+ if (day) {
3266
+ at.setDate(at.getDate() + (WEEKDAYS.indexOf(day[1].toLowerCase()) - at.getDay() + 7) % 7);
3267
+ if (at.getTime() <= now.getTime()) at.setDate(at.getDate() + 7);
3268
+ } else if (at.getTime() <= now.getTime()) at.setDate(at.getDate() + 1);
3216
3269
  return at;
3217
3270
  }
3218
3271
  function webChatTitle(c) {
@@ -3732,9 +3785,8 @@ function scanPage(root, ax, watch3, isLimit) {
3732
3785
  for (const k of ax.kids(n)) walk(k, depth + 1);
3733
3786
  };
3734
3787
  walk(root, 0);
3735
- const NOTICE = /^(?:you['’]?ve|you have|you['’]re|you are|usage limit|message limit|rate limit|limit reached)\b/i;
3736
3788
  const tail2 = watch3 ? last ? message(last.n, last.h) : void 0 : turns.at(-1);
3737
- if (tail2 && tail2.who === "agent" && tail2.text.length < 250 && NOTICE.test(tail2.text) && isLimit(tail2.text)) {
3789
+ if (tail2 && tail2.who === "agent" && isLimit(tail2.text)) {
3738
3790
  if (!limit) limit = tail2.text;
3739
3791
  if (!watch3) turns.pop();
3740
3792
  }
@@ -3775,6 +3827,7 @@ ObjC.bindFunction('AXUIElementCopyAttributeValue', ['int', ['id', 'id', 'id*']])
3775
3827
  ObjC.bindFunction('AXUIElementSetAttributeValue', ['int', ['id', 'id', 'id']]);
3776
3828
  ObjC.bindFunction('getppid', ['int', []]);
3777
3829
  const isLimitText = ${isLimitText.toString()};
3830
+ isLimitText.notices = ${JSON.stringify(LIMIT_NOTICES)};
3778
3831
  const scanPage = ${scanPage.toString()};
3779
3832
  function get(el, name) { const r = Ref(); return $.AXUIElementCopyAttributeValue(el, name, r) === 0 ? r[0] : null; }
3780
3833
  function str(v) { if (!v) return null; try { const s = ObjC.unwrap(v); return typeof s === 'string' ? s : null; } catch (e) { return null; } }
package/dist/harlay.mjs CHANGED
@@ -2553,7 +2553,7 @@ async function installApp(opts) {
2553
2553
  }
2554
2554
 
2555
2555
  // src/main.ts
2556
- var VERSION = "0.4.0";
2556
+ var VERSION = "0.4.1";
2557
2557
  var HELP = `harlay ${VERSION} \u2014 hand off a stalled AI coding session to another agent
2558
2558
 
2559
2559
  Usage:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harlay",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Move a coding task between AI agents (Claude Code, Codex, Cursor) when one stops. macOS desktop app and CLI.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -19,7 +19,8 @@
19
19
  },
20
20
  "scripts": {
21
21
  "build": "esbuild src/bin.ts --bundle --platform=node --format=esm --target=node22 --external:@electron/packager --outfile=dist/harlay.mjs --banner:js='#!/usr/bin/env node'",
22
- "prepack": "npm run build && node scripts/bundle-app.mjs"
22
+ "prepack": "npm run build && node scripts/bundle-app.mjs",
23
+ "postpack": "node -e \"require('node:fs').rmSync('app',{recursive:true,force:true})\""
23
24
  },
24
25
  "dependencies": {
25
26
  "@electron/packager": "^20.3.0"