haltija 1.3.1 → 1.3.2

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haltija-desktop",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "private": true,
5
5
  "description": "Haltija Desktop - God Mode Browser for AI Agents",
6
6
  "homepage": "https://github.com/tonioloewald/haltija",
@@ -46,7 +46,7 @@
46
46
  });
47
47
 
48
48
  // src/version.ts
49
- var VERSION = "1.3.1";
49
+ var VERSION = "1.3.2";
50
50
 
51
51
  // src/text-selector.ts
52
52
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\(/;
@@ -584,7 +584,7 @@ async function launchElectronApp() {
584
584
  return false
585
585
  }
586
586
 
587
- async function ensureBrowserConnected(port) {
587
+ async function ensureBrowserConnected(port, { explicitTarget = false } = {}) {
588
588
  let status
589
589
  try {
590
590
  const resp = await fetch(`http://localhost:${port}/status`, {
@@ -600,6 +600,19 @@ async function ensureBrowserConnected(port) {
600
600
  // produce two app instances side by side — skip the launch.
601
601
  if (status?.desktopApp) return true
602
602
 
603
+ // Private / project-owned server (explicitly targeted via --port / --name /
604
+ // HALTIJA_PORT). Launching the standalone Haltija.app here is wrong — it runs
605
+ // its own server on 8700 and would never connect to this port — so guide the
606
+ // user to attach a browser to *this* server instead of spawning Electron.
607
+ if (explicitTarget) {
608
+ process.stderr.write(
609
+ `\x1b[2mNo browser connected to the haltija server on port ${port}. ` +
610
+ `Open your app/page with the widget injected (script tag or bookmarklet), ` +
611
+ `or run \`hj --no-launch\` to skip this check.\x1b[0m\n`
612
+ )
613
+ return false
614
+ }
615
+
603
616
  // Respect "user explicitly quit" — don't auto-relaunch on every agent
604
617
  // call. Cleared when the user starts Haltija manually.
605
618
  try {
@@ -748,6 +761,7 @@ export async function runSubcommand(subcommand, subArgs, port = '8700', options
748
761
  const baseUrl = `http://localhost:${port}`
749
762
  const jsonOutput = subArgs.includes('--json')
750
763
  const noLaunch = options.noLaunch || false
764
+ const explicitTarget = options.explicitTarget || false
751
765
  // Remove --json and extract --window before processing
752
766
  let filteredArgs = subArgs.filter(a => a !== '--json')
753
767
  let targetWindowId = undefined
@@ -791,7 +805,7 @@ export async function runSubcommand(subcommand, subArgs, port = '8700', options
791
805
 
792
806
  // Auto-launch browser if no windows connected (skip for info commands and --no-launch)
793
807
  if (!noLaunch && !INFO_COMMANDS.has(subcommand)) {
794
- await ensureBrowserConnected(port)
808
+ await ensureBrowserConnected(port, { explicitTarget })
795
809
  }
796
810
 
797
811
  // Special handling for 'send' command - route to appropriate endpoint
package/bin/hj.mjs CHANGED
@@ -196,6 +196,15 @@ if (noLaunchIdx !== -1) {
196
196
  args.splice(noLaunchIdx, 1)
197
197
  }
198
198
 
199
+ // Did the shell explicitly target a private instance (--port / --name /
200
+ // HALTIJA_PORT / HALTIJA_NAME / DEV_CHANNEL_PORT)? If so, this is a
201
+ // project-owned server with a bring-your-own browser — auto-launching the
202
+ // standalone Haltija.app is never right (it runs its own server on 8700 and
203
+ // can't connect to this port), so we suppress the Electron launch and print
204
+ // an actionable hint instead. Only the bare, unconfigured 8700 default keeps
205
+ // the zero-config desktop auto-launch.
206
+ const explicitTarget = portSource !== '8700 (default)'
207
+
199
208
  // --- Space-to-hyphen sub-command resolution ---
200
209
  // "hj test run foo.json" → "hj test-run foo.json"
201
210
  // "hj events watch" → "hj events-watch"
@@ -247,7 +256,7 @@ if (!isSubcommand(subcommand)) {
247
256
 
248
257
  // Auto-execute if there's exactly one fuzzy match
249
258
  if (suggestion) {
250
- runSubcommand(suggestion, subArgs, port, { noLaunch })
259
+ runSubcommand(suggestion, subArgs, port, { noLaunch, explicitTarget })
251
260
  } else {
252
261
  console.error(`Unknown command: '${subcommand}'`)
253
262
  console.error(`\nExamples: hj tree, hj navigate <url>, hj click @42`)
@@ -255,7 +264,7 @@ if (!isSubcommand(subcommand)) {
255
264
  process.exit(1)
256
265
  }
257
266
  } else {
258
- runSubcommand(subcommand, subArgs, port, { noLaunch })
267
+ runSubcommand(subcommand, subArgs, port, { noLaunch, explicitTarget })
259
268
  }
260
269
 
261
270
  function filterHelp(topic) {
@@ -20,7 +20,7 @@
20
20
  * - Option+Tab toggles visibility (but active state always shows briefly)
21
21
  * - Localhost only by default
22
22
  */
23
- export declare const VERSION = "1.3.1";
23
+ export declare const VERSION = "1.3.2";
24
24
  export declare class DevChannel extends HTMLElement {
25
25
  static get tagName(): string;
26
26
  static elementCreator(): () => DevChannel;
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "1.3.1";
2
+ var VERSION = "1.3.2";
3
3
 
4
4
  // src/text-selector.ts
5
5
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\(/;
package/dist/component.js CHANGED
@@ -46,7 +46,7 @@
46
46
  });
47
47
 
48
48
  // src/version.ts
49
- var VERSION = "1.3.1";
49
+ var VERSION = "1.3.2";
50
50
 
51
51
  // src/text-selector.ts
52
52
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\(/;
package/dist/hj.js CHANGED
@@ -1345,7 +1345,7 @@ async function launchElectronApp() {
1345
1345
  }
1346
1346
  return false;
1347
1347
  }
1348
- async function ensureBrowserConnected(port) {
1348
+ async function ensureBrowserConnected(port, { explicitTarget = false } = {}) {
1349
1349
  let status;
1350
1350
  try {
1351
1351
  const resp = await fetch(`http://localhost:${port}/status`, {
@@ -1359,6 +1359,11 @@ async function ensureBrowserConnected(port) {
1359
1359
  }
1360
1360
  if (status?.desktopApp)
1361
1361
  return true;
1362
+ if (explicitTarget) {
1363
+ process.stderr.write(`\x1B[2mNo browser connected to the haltija server on port ${port}. Open your app/page with the widget injected (script tag or bookmarklet), or run \`hj --no-launch\` to skip this check.\x1B[0m
1364
+ `);
1365
+ return false;
1366
+ }
1362
1367
  try {
1363
1368
  const quitMarker = join(homedir(), ".haltija", "last-quit");
1364
1369
  if (existsSync(quitMarker)) {
@@ -1483,6 +1488,7 @@ async function runSubcommand(subcommand, subArgs, port = "8700", options = {}) {
1483
1488
  const baseUrl = `http://localhost:${port}`;
1484
1489
  const jsonOutput = subArgs.includes("--json");
1485
1490
  const noLaunch = options.noLaunch || false;
1491
+ const explicitTarget = options.explicitTarget || false;
1486
1492
  let filteredArgs = subArgs.filter((a) => a !== "--json");
1487
1493
  let targetWindowId = undefined;
1488
1494
  const windowIdx = filteredArgs.indexOf("--window");
@@ -1516,7 +1522,7 @@ async function runSubcommand(subcommand, subArgs, port = "8700", options = {}) {
1516
1522
  }
1517
1523
  }
1518
1524
  if (!noLaunch && !INFO_COMMANDS.has(subcommand)) {
1519
- await ensureBrowserConnected(port);
1525
+ await ensureBrowserConnected(port, { explicitTarget });
1520
1526
  }
1521
1527
  if (subcommand === "send") {
1522
1528
  const firstArg = filteredArgs[0]?.toLocaleLowerCase();
@@ -2018,6 +2024,7 @@ if (noLaunchIdx !== -1) {
2018
2024
  noLaunch = true;
2019
2025
  args.splice(noLaunchIdx, 1);
2020
2026
  }
2027
+ var explicitTarget = portSource !== "8700 (default)";
2021
2028
  if (args.length >= 2 && isSubcommand(`${args[0]}-${args[1]}`)) {
2022
2029
  args.splice(0, 2, `${args[0]}-${args[1]}`);
2023
2030
  }
@@ -2052,7 +2059,7 @@ if (!isSubcommand(subcommand)) {
2052
2059
  process.exit(0);
2053
2060
  }
2054
2061
  if (suggestion) {
2055
- runSubcommand(suggestion, subArgs, port, { noLaunch });
2062
+ runSubcommand(suggestion, subArgs, port, { noLaunch, explicitTarget });
2056
2063
  } else {
2057
2064
  console.error(`Unknown command: '${subcommand}'`);
2058
2065
  console.error(`
@@ -2061,7 +2068,7 @@ Examples: hj tree, hj navigate <url>, hj click @42`);
2061
2068
  process.exit(1);
2062
2069
  }
2063
2070
  } else {
2064
- runSubcommand(subcommand, subArgs, port, { noLaunch });
2071
+ runSubcommand(subcommand, subArgs, port, { noLaunch, explicitTarget });
2065
2072
  }
2066
2073
  function filterHelp(topic) {
2067
2074
  const bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
package/dist/index.js CHANGED
@@ -674,7 +674,7 @@ var injectorCode = `
674
674
  `;
675
675
 
676
676
  // src/version.ts
677
- var VERSION = "1.3.1";
677
+ var VERSION = "1.3.2";
678
678
 
679
679
  // src/embedded-assets.ts
680
680
  var APP_MD = `# Haltija App
@@ -3019,7 +3019,7 @@ var COMPONENT_JS = `(() => {
3019
3019
  });
3020
3020
 
3021
3021
  // src/version.ts
3022
- var VERSION = "1.3.1";
3022
+ var VERSION = "1.3.2";
3023
3023
 
3024
3024
  // src/text-selector.ts
3025
3025
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\\(/;
package/dist/server.js CHANGED
@@ -674,7 +674,7 @@ var injectorCode = `
674
674
  `;
675
675
 
676
676
  // src/version.ts
677
- var VERSION = "1.3.1";
677
+ var VERSION = "1.3.2";
678
678
 
679
679
  // src/embedded-assets.ts
680
680
  var APP_MD = `# Haltija App
@@ -3019,7 +3019,7 @@ var COMPONENT_JS = `(() => {
3019
3019
  });
3020
3020
 
3021
3021
  // src/version.ts
3022
- var VERSION = "1.3.1";
3022
+ var VERSION = "1.3.2";
3023
3023
 
3024
3024
  // src/text-selector.ts
3025
3025
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\\(/;
package/dist/version.d.ts CHANGED
@@ -8,4 +8,4 @@
8
8
  * ⚠️ AUTO-GENERATED FROM package.json - DO NOT EDIT THIS FILE
9
9
  * ⚠️ To change the version, update package.json and run: bun run build
10
10
  */
11
- export declare const VERSION = "1.3.1";
11
+ export declare const VERSION = "1.3.2";
package/docs/README.md CHANGED
@@ -34,7 +34,7 @@
34
34
  ## Planning
35
35
 
36
36
  - **[Executive Summary](EXECUTIVE-SUMMARY.md)** - What Haltija is, who it's for
37
- - **[Roadmap to 10/10](ROADMAP-TO-10.md)** - Where we're going
37
+ - **[Roadmap](ROADMAP.md)** - Where we're going
38
38
  - **[Development Roadmap](../ROADMAP.md)** - Completed and planned phases
39
39
  - **[TODO](../TODO.md)** - Outstanding issues and ideas
40
40
 
@@ -81,7 +81,7 @@ To fill this form:
81
81
  hj tree -d 5 Deeper tree
82
82
  hj tree form Subtree rooted at selector
83
83
  hj console Recent console logs/errors
84
- hj screenshot Capture page as image
84
+ hj screenshot Capture page as image (--format webp for smaller)
85
85
  hj location Current URL and title
86
86
  hj events Recent semantic events
87
87
 
@@ -113,6 +113,10 @@ To fill this form:
113
113
  hj windows List connected tabs
114
114
  hj click 5 --window abc Target specific tab
115
115
 
116
+ ### Server
117
+ hj status Is the server up? which tab is focused?
118
+ hj where Which server this shell targets (add --json)
119
+
116
120
  ## Tips
117
121
 
118
122
  - Start with `hj tree` — look for [interactive] to find actionable elements
package/docs/recipes.md CHANGED
@@ -128,8 +128,8 @@ curl localhost:8700/events
128
128
  # Highlight what might be wrong
129
129
  curl -X POST localhost:8700/highlight -d '{"selector":".error-message","label":"This error"}'
130
130
 
131
- # Screenshot for the ticket
132
- curl -X POST localhost:8700/screenshot -d '{"maxWidth":1200}'
131
+ # Screenshot for the ticket (webp keeps it small)
132
+ curl -X POST localhost:8700/screenshot -d '{"maxWidth":1200,"format":"webp"}'
133
133
  ```
134
134
 
135
135
  **Or just tell the agent**: "Customer says Settings page is broken. Check it out."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haltija",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Browser control for AI agents - query DOM, click, type, run JS, watch mutations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",