onako 0.1.2__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.
onako/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.2"
1
+ __version__ = "0.2.0"
onako/cli.py CHANGED
@@ -27,14 +27,24 @@ def version():
27
27
  @main.command()
28
28
  @click.option("--host", default="0.0.0.0", help="Host to bind to.")
29
29
  @click.option("--port", default=8787, type=int, help="Port to bind to.")
30
- def serve(host, port):
30
+ @click.option("--dir", "working_dir", default=None, type=click.Path(exists=True), help="Working directory for tasks (default: current directory).")
31
+ @click.option("--background", is_flag=True, help="Run as a background service (launchd/systemd).")
32
+ def serve(host, port, working_dir, background):
31
33
  """Start the Onako server."""
34
+ working_dir = str(Path(working_dir).resolve()) if working_dir else os.getcwd()
35
+
36
+ if background:
37
+ _start_background(host, port, working_dir)
38
+ return
39
+
32
40
  _check_prerequisites()
33
41
 
42
+ os.environ["ONAKO_WORKING_DIR"] = working_dir
43
+
34
44
  from onako import __version__
35
45
  click.echo(f"Onako v{__version__}")
36
46
  click.echo(f"Starting server at http://{host}:{port}")
37
- click.echo(f"Dashboard: http://{host}:{port}")
47
+ click.echo(f"Working directory: {working_dir}")
38
48
  click.echo()
39
49
 
40
50
  import uvicorn
@@ -43,10 +53,54 @@ def serve(host, port):
43
53
 
44
54
 
45
55
  @main.command()
46
- @click.option("--host", default="0.0.0.0", help="Host to bind to.")
47
- @click.option("--port", default=8787, type=int, help="Port to bind to.")
48
- def install(host, port):
49
- """Install Onako as a background service (launchd on macOS, systemd on Linux)."""
56
+ def stop():
57
+ """Stop the background Onako service."""
58
+ system = platform.system()
59
+ if system == "Darwin":
60
+ plist_path = Path.home() / "Library" / "LaunchAgents" / "com.onako.server.plist"
61
+ if plist_path.exists():
62
+ uid = os.getuid()
63
+ result = subprocess.run(
64
+ ["launchctl", "bootout", f"gui/{uid}", str(plist_path)],
65
+ capture_output=True,
66
+ )
67
+ if result.returncode != 0:
68
+ subprocess.run(["launchctl", "unload", str(plist_path)], capture_output=True)
69
+ plist_path.unlink()
70
+ click.echo("Onako service stopped and removed.")
71
+ else:
72
+ click.echo("Onako service is not running.")
73
+ elif system == "Linux":
74
+ unit_path = Path.home() / ".config" / "systemd" / "user" / "onako.service"
75
+ if unit_path.exists():
76
+ subprocess.run(["systemctl", "--user", "disable", "--now", "onako"])
77
+ unit_path.unlink()
78
+ subprocess.run(["systemctl", "--user", "daemon-reload"])
79
+ click.echo("Onako service stopped and removed.")
80
+ else:
81
+ click.echo("Onako service is not running.")
82
+ else:
83
+ click.echo(f"Not supported on {system}.")
84
+
85
+
86
+ @main.command()
87
+ def status():
88
+ """Check if Onako is running."""
89
+ import urllib.request
90
+ try:
91
+ r = urllib.request.urlopen("http://127.0.0.1:8787/health", timeout=2)
92
+ data = r.read().decode()
93
+ if '"ok"' in data:
94
+ click.echo("Onako server: running")
95
+ click.echo(" URL: http://127.0.0.1:8787")
96
+ else:
97
+ click.echo("Onako server: not responding correctly")
98
+ except Exception:
99
+ click.echo("Onako server: not running")
100
+
101
+
102
+ def _start_background(host, port, working_dir):
103
+ """Install and start Onako as a background service."""
50
104
  system = platform.system()
51
105
  onako_bin = shutil.which("onako")
52
106
  if not onako_bin:
@@ -65,21 +119,22 @@ def install(host, port):
65
119
  path_value = ":".join(sorted(path_dirs))
66
120
 
67
121
  if system == "Darwin":
68
- _install_launchd(onako_bin, host, port, path_value)
122
+ _install_launchd(onako_bin, host, port, working_dir, path_value)
69
123
  elif system == "Linux":
70
- _install_systemd(onako_bin, host, port, path_value)
124
+ _install_systemd(onako_bin, host, port, working_dir, path_value)
71
125
  else:
72
- click.echo(f"Auto-start is not supported on {system}. Run 'onako serve' manually.", err=True)
126
+ click.echo(f"Background mode is not supported on {system}. Run 'onako serve' manually.", err=True)
73
127
  sys.exit(1)
74
128
 
75
129
 
76
- def _install_launchd(onako_bin, host, port, path_value):
130
+ def _install_launchd(onako_bin, host, port, working_dir, path_value):
77
131
  from importlib.resources import files
78
132
  tpl = files("onako").joinpath("templates", "com.onako.server.plist.tpl").read_text()
79
133
  plist = tpl.format(
80
134
  onako_bin=onako_bin,
81
135
  host=host,
82
136
  port=port,
137
+ working_dir=working_dir,
83
138
  log_dir=LOG_DIR,
84
139
  path_value=path_value,
85
140
  )
@@ -109,21 +164,22 @@ def _install_launchd(onako_bin, host, port, path_value):
109
164
  capture_output=True,
110
165
  )
111
166
 
112
- click.echo(f"Installed launchd service: {plist_path}")
113
- click.echo(f"Logs: {LOG_DIR}")
114
- click.echo(f"Onako is running at http://{host}:{port}")
167
+ click.echo(f"Onako running in background at http://{host}:{port}")
168
+ click.echo(f" Working directory: {working_dir}")
169
+ click.echo(f" Logs: {LOG_DIR}")
115
170
  click.echo()
116
171
  click.echo("If macOS blocks this service, allow it in:")
117
172
  click.echo(" System Settings > General > Login Items & Extensions")
118
173
 
119
174
 
120
- def _install_systemd(onako_bin, host, port, path_value):
175
+ def _install_systemd(onako_bin, host, port, working_dir, path_value):
121
176
  from importlib.resources import files
122
177
  tpl = files("onako").joinpath("templates", "onako.service.tpl").read_text()
123
178
  unit = tpl.format(
124
179
  onako_bin=onako_bin,
125
180
  host=host,
126
181
  port=port,
182
+ working_dir=working_dir,
127
183
  path_value=path_value,
128
184
  )
129
185
  unit_path = Path.home() / ".config" / "systemd" / "user" / "onako.service"
@@ -131,55 +187,8 @@ def _install_systemd(onako_bin, host, port, path_value):
131
187
  unit_path.write_text(unit)
132
188
  subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
133
189
  subprocess.run(["systemctl", "--user", "enable", "--now", "onako"], check=True)
134
- click.echo(f"Installed systemd service: {unit_path}")
135
- click.echo(f"Onako is running at http://{host}:{port}")
136
-
137
-
138
- @main.command()
139
- def uninstall():
140
- """Remove the Onako background service."""
141
- system = platform.system()
142
- if system == "Darwin":
143
- plist_path = Path.home() / "Library" / "LaunchAgents" / "com.onako.server.plist"
144
- if plist_path.exists():
145
- uid = os.getuid()
146
- result = subprocess.run(
147
- ["launchctl", "bootout", f"gui/{uid}", str(plist_path)],
148
- capture_output=True,
149
- )
150
- if result.returncode != 0:
151
- subprocess.run(["launchctl", "unload", str(plist_path)], capture_output=True)
152
- plist_path.unlink()
153
- click.echo("Onako service removed.")
154
- else:
155
- click.echo("Onako service is not installed.")
156
- elif system == "Linux":
157
- unit_path = Path.home() / ".config" / "systemd" / "user" / "onako.service"
158
- if unit_path.exists():
159
- subprocess.run(["systemctl", "--user", "disable", "--now", "onako"])
160
- unit_path.unlink()
161
- subprocess.run(["systemctl", "--user", "daemon-reload"])
162
- click.echo("Onako service removed.")
163
- else:
164
- click.echo("Onako service is not installed.")
165
- else:
166
- click.echo(f"Not supported on {system}.")
167
-
168
-
169
- @main.command()
170
- def status():
171
- """Check if Onako is running."""
172
- import urllib.request
173
- try:
174
- r = urllib.request.urlopen("http://127.0.0.1:8787/health", timeout=2)
175
- data = r.read().decode()
176
- if '"ok"' in data:
177
- click.echo("Onako server: running")
178
- click.echo(" URL: http://127.0.0.1:8787")
179
- else:
180
- click.echo("Onako server: not responding correctly")
181
- except Exception:
182
- click.echo("Onako server: not running")
190
+ click.echo(f"Onako running in background at http://{host}:{port}")
191
+ click.echo(f" Working directory: {working_dir}")
183
192
 
184
193
 
185
194
  def _check_prerequisites():
@@ -12,7 +12,11 @@
12
12
  <string>{host}</string>
13
13
  <string>--port</string>
14
14
  <string>{port}</string>
15
+ <string>--dir</string>
16
+ <string>{working_dir}</string>
15
17
  </array>
18
+ <key>WorkingDirectory</key>
19
+ <string>{working_dir}</string>
16
20
  <key>RunAtLoad</key>
17
21
  <true/>
18
22
  <key>KeepAlive</key>
@@ -3,7 +3,8 @@ Description=Onako - Claude Code Task Orchestrator
3
3
  After=network.target
4
4
 
5
5
  [Service]
6
- ExecStart={onako_bin} serve --host {host} --port {port}
6
+ ExecStart={onako_bin} serve --host {host} --port {port} --dir {working_dir}
7
+ WorkingDirectory={working_dir}
7
8
  Restart=on-failure
8
9
  Environment=PATH={path_value}
9
10
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onako
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Dispatch and monitor Claude Code tasks from your phone
5
5
  Author: Amir
6
6
  License-Expression: MIT
@@ -32,23 +32,25 @@ Requires [tmux](https://github.com/tmux/tmux) and [Claude Code](https://docs.ant
32
32
  ## Usage
33
33
 
34
34
  ```bash
35
+ cd ~/projects
35
36
  onako serve
36
37
  ```
37
38
 
38
39
  Open http://localhost:8787 on your phone (same network) or set up [Tailscale](https://tailscale.com) for access from anywhere.
39
40
 
40
- ### Auto-start on boot
41
+ ### Run in the background
41
42
 
42
43
  ```bash
43
- onako install
44
+ onako serve --background
44
45
  ```
45
46
 
46
- ### Other commands
47
+ This installs a system service (launchd on macOS, systemd on Linux) that starts on boot. Tasks run in the directory where you ran the command.
47
48
 
48
49
  ```bash
49
- onako status # Check if server is running
50
- onako uninstall # Remove auto-start service
51
- onako version # Print version
50
+ onako serve --background --dir ~/projects # override working directory
51
+ onako status # check if running
52
+ onako stop # stop the background service
53
+ onako version # print version
52
54
  ```
53
55
 
54
56
  ## How it works
@@ -0,0 +1,12 @@
1
+ onako/__init__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
2
+ onako/cli.py,sha256=scmBfnyRAaT_yJziVQyumV6SyureGx6FXumV_r6KGxE,7217
3
+ onako/server.py,sha256=lBNaT8Xq5Jw8EpN1CZNWzKQ2TudAMpSE4L0PY4ucW10,2065
4
+ onako/tmux_orchestrator.py,sha256=rLNVrCcam2iF412WKX_5hAiMCBHmi8sNhDPD4KvEiU8,6080
5
+ onako/static/index.html,sha256=7TjxfF38Spnuerd6u0vbwGpJApstsxzVS3F-YUGCp7I,14403
6
+ onako/templates/com.onako.server.plist.tpl,sha256=XvjvRz_AnjcREVjDPFu2qGMVCxojp6hhTwMfvrFcEbY,994
7
+ onako/templates/onako.service.tpl,sha256=EOVOaLtxC1FrcLdy7DtEbtf9ImgN6PmnMb57ZT81nTM,280
8
+ onako-0.2.0.dist-info/METADATA,sha256=q4U1SxLom_kJjvbZ4SMAqE5zRrVvTBGiZBBa1pI8kf4,1891
9
+ onako-0.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
10
+ onako-0.2.0.dist-info/entry_points.txt,sha256=51KRJzuVpr69iT_k4JO0Lj3DQv_HbgtGjTBTev13JAQ,41
11
+ onako-0.2.0.dist-info/top_level.txt,sha256=EZsc5qq2paM9GTbaFE9Xar4B5wFdfIqK9l_bDQVcmZ4,6
12
+ onako-0.2.0.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- onako/__init__.py,sha256=YvuYzWnKtqBb-IqG8HAu-nhIYAsgj9Vmc_b9o7vO-js,22
2
- onako/cli.py,sha256=_vDVf7R7FdsNvQiQT7i5ZK5jtPeJtx7T2aLVSJki87g,6733
3
- onako/server.py,sha256=lBNaT8Xq5Jw8EpN1CZNWzKQ2TudAMpSE4L0PY4ucW10,2065
4
- onako/tmux_orchestrator.py,sha256=rLNVrCcam2iF412WKX_5hAiMCBHmi8sNhDPD4KvEiU8,6080
5
- onako/static/index.html,sha256=7TjxfF38Spnuerd6u0vbwGpJApstsxzVS3F-YUGCp7I,14403
6
- onako/templates/com.onako.server.plist.tpl,sha256=kOFbOXVLP8ULAyV66fEloI4y1iFPmUSrudyjSCB-pwc,857
7
- onako/templates/onako.service.tpl,sha256=TKGFoDraWyA4VEQYXZodtJF2m5ZjIVSezaDAAB83Vl4,229
8
- onako-0.1.2.dist-info/METADATA,sha256=nEPWBgu2iofpVXXNpZ9u9EChYyPIfzWZS6eOXZvpi-g,1593
9
- onako-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
10
- onako-0.1.2.dist-info/entry_points.txt,sha256=51KRJzuVpr69iT_k4JO0Lj3DQv_HbgtGjTBTev13JAQ,41
11
- onako-0.1.2.dist-info/top_level.txt,sha256=EZsc5qq2paM9GTbaFE9Xar4B5wFdfIqK9l_bDQVcmZ4,6
12
- onako-0.1.2.dist-info/RECORD,,
File without changes