openrune 0.3.3 → 0.3.5

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.
Files changed (2) hide show
  1. package/bin/rune.js +79 -29
  2. package/package.json +1 -1
package/bin/rune.js CHANGED
@@ -439,10 +439,29 @@ function registerFileAssociation(projectRoot) {
439
439
 
440
440
  fs.writeFileSync(path.join(appContents, 'Info.plist'), appPlist)
441
441
 
442
- // Launcher script — uses actual Electron binary, not Node wrapper
442
+ // Launcher script — dynamically finds the rune binary and uses it to resolve Electron
443
+ const runeBin = path.resolve(__dirname, 'rune.js')
444
+ const nodebin = process.execPath
443
445
  const launcherScript = `#!/bin/bash
444
- RUNE_PROJECT="${projectRoot}"
445
- ELECTRON="${electronBinary}"
446
+ # Dynamically resolve Rune's install location via the CLI binary
447
+ RUNE_BIN="${runeBin}"
448
+ RUNE_PROJECT="$(dirname "$(dirname "$RUNE_BIN")")"
449
+
450
+ # Find Electron binary
451
+ ELECTRON="$RUNE_PROJECT/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron"
452
+
453
+ if [ ! -f "$ELECTRON" ]; then
454
+ # Fallback: try the path saved by rune install
455
+ if [ -f "$HOME/.rune/project-path" ]; then
456
+ RUNE_PROJECT="$(cat "$HOME/.rune/project-path")"
457
+ ELECTRON="$RUNE_PROJECT/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron"
458
+ fi
459
+ fi
460
+
461
+ if [ ! -f "$ELECTRON" ]; then
462
+ osascript -e 'display dialog "Electron not found. Run: rune install" buttons {"OK"}'
463
+ exit 1
464
+ fi
446
465
 
447
466
  # CRITICAL: unset this so Electron runs as an app, not plain Node.js
448
467
  unset ELECTRON_RUN_AS_NODE
@@ -609,6 +628,23 @@ function createRune(name, allArgs) {
609
628
 
610
629
  // ── open ─────────────────────────────────────────
611
630
 
631
+ function findProjectRoot() {
632
+ // Always resolve from the actual package location (works for both global and local)
633
+ const fromBin = path.resolve(__dirname, '..')
634
+ const electronCheck = path.join(fromBin, 'node_modules', 'electron', 'dist', 'Electron.app', 'Contents', 'MacOS', 'Electron')
635
+ if (fs.existsSync(electronCheck)) return fromBin
636
+
637
+ // Fallback: check saved path
638
+ const savedPath = path.join(RUNE_HOME, 'project-path')
639
+ if (fs.existsSync(savedPath)) {
640
+ const saved = fs.readFileSync(savedPath, 'utf-8').trim()
641
+ const savedElectron = path.join(saved, 'node_modules', 'electron', 'dist', 'Electron.app', 'Contents', 'MacOS', 'Electron')
642
+ if (fs.existsSync(savedElectron)) return saved
643
+ }
644
+
645
+ return null
646
+ }
647
+
612
648
  function openRune(file) {
613
649
  if (!file) {
614
650
  console.log('Usage: rune open <file.rune>')
@@ -621,21 +657,14 @@ function openRune(file) {
621
657
  process.exit(1)
622
658
  }
623
659
 
624
- // Try to find the project root
625
- let projectRoot
626
- const savedPath = path.join(RUNE_HOME, 'project-path')
627
- if (fs.existsSync(savedPath)) {
628
- projectRoot = fs.readFileSync(savedPath, 'utf-8').trim()
629
- } else {
630
- projectRoot = path.resolve(__dirname, '..')
631
- }
632
-
633
- const electronBinary = path.join(projectRoot, 'node_modules', 'electron', 'dist', 'Electron.app', 'Contents', 'MacOS', 'Electron')
634
- if (!fs.existsSync(electronBinary)) {
660
+ const projectRoot = findProjectRoot()
661
+ if (!projectRoot) {
635
662
  console.error(' ❌ Electron not found. Run `rune install` first.')
636
663
  process.exit(1)
637
664
  }
638
665
 
666
+ const electronBinary = path.join(projectRoot, 'node_modules', 'electron', 'dist', 'Electron.app', 'Contents', 'MacOS', 'Electron')
667
+
639
668
  console.log(`🔮 Opening ${path.basename(filePath)}...`)
640
669
 
641
670
  // CRITICAL: unset ELECTRON_RUN_AS_NODE — Claude Code sets it,
@@ -736,31 +765,52 @@ function runRune(file, restArgs) {
736
765
 
737
766
  let fullOutput = ''
738
767
 
768
+ let buffer = ''
739
769
  child.stdout.on('data', (data) => {
740
- const lines = data.toString().split('\n').filter(Boolean)
770
+ buffer += data.toString()
771
+ const lines = buffer.split('\n')
772
+ buffer = lines.pop() // keep incomplete line in buffer
741
773
  for (const line of lines) {
774
+ if (!line.trim()) continue
742
775
  try {
743
776
  const event = JSON.parse(line)
744
777
 
745
- if (event.type === 'assistant' && event.subtype === 'tool_use') {
746
- const tool = event.tool_name || event.name || 'unknown'
747
- const input = event.input || {}
748
- if (tool === 'Bash') {
749
- console.log(` ▶ Bash: ${(input.command || '').slice(0, 120)}`)
750
- } else if (tool === 'Write') {
751
- console.log(` ▶ Write: ${input.file_path || ''}`)
752
- } else if (tool === 'Edit') {
753
- console.log(` ▶ Edit: ${input.file_path || ''}`)
754
- } else if (tool === 'Read') {
755
- console.log(` ▶ Read: ${input.file_path || ''}`)
756
- } else {
757
- console.log(` ▶ ${tool}`)
778
+ // Tool use events
779
+ if (event.type === 'assistant' && event.message && event.message.content) {
780
+ for (const block of event.message.content) {
781
+ if (block.type === 'tool_use') {
782
+ const tool = block.name || 'unknown'
783
+ const input = block.input || {}
784
+ if (tool === 'Bash') {
785
+ console.log(` ▶ Bash: ${(input.command || '').slice(0, 120)}`)
786
+ } else if (tool === 'Write') {
787
+ console.log(` ▶ Write: ${input.file_path || ''}`)
788
+ } else if (tool === 'Edit') {
789
+ console.log(` ▶ Edit: ${input.file_path || ''}`)
790
+ } else if (tool === 'Read') {
791
+ console.log(` ▶ Read: ${input.file_path || ''}`)
792
+ } else if (tool === 'Grep') {
793
+ console.log(` ▶ Grep: ${input.pattern || ''}`)
794
+ } else if (tool === 'Glob') {
795
+ console.log(` ▶ Glob: ${input.pattern || ''}`)
796
+ } else {
797
+ console.log(` ▶ ${tool}`)
798
+ }
799
+ } else if (block.type === 'text' && block.text && block.text.trim()) {
800
+ console.log(` 💬 ${block.text.trim().slice(0, 200)}`)
801
+ }
758
802
  }
759
803
  }
760
804
 
805
+ // Tool results
806
+ if (event.type === 'user' && event.tool_use_result) {
807
+ // silently track tool results
808
+ }
809
+
810
+ // Final result
761
811
  if (event.type === 'result') {
762
812
  fullOutput = event.result || ''
763
- console.log(`\n${fullOutput}`)
813
+ if (fullOutput) console.log(`\n${fullOutput}`)
764
814
  }
765
815
  } catch {}
766
816
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openrune",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Rune — File-based AI Agent Harness for Claude Code",
5
5
  "keywords": ["ai", "agent", "claude", "desktop", "electron", "mcp", "claude-code", "harness", "automation"],
6
6
  "repository": {