pterm 0.0.14 → 0.0.16

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 (4) hide show
  1. package/README.md +85 -2
  2. package/index.js +21 -9
  3. package/package.json +1 -1
  4. package/util.js +71 -1
package/README.md CHANGED
@@ -108,9 +108,11 @@ Run a launcher. Equivalent to the user visiting a launcher page. Will run whiche
108
108
  ### syntax
109
109
 
110
110
  ```
111
- pterm run <launcher_path>
111
+ pterm run <launcher_path_or_uri> [--open]
112
112
  ```
113
113
 
114
+ - `--open`: (optional) open URL results in the browser. Default behavior is to print the URL to stdout without opening a browser.
115
+
114
116
  ### examples
115
117
 
116
118
  Launch the launcher in the current path
@@ -125,6 +127,88 @@ Launch from absolute path
125
127
  pterm run /pinokio/api/test
126
128
  ```
127
129
 
130
+ Run from a launcher URI and auto-open the resulting URL in browser
131
+
132
+ ```
133
+ pterm run https://github.com/example/my-launcher --open
134
+ ```
135
+
136
+ ## search
137
+
138
+ Search installed or available apps.
139
+
140
+ ### syntax
141
+
142
+ ```
143
+ pterm search [query words...]
144
+ pterm search --q="<query>"
145
+ pterm search "<query>" [--mode=balanced|broad|strict] [--min-match=<n>] [--limit=<n>]
146
+ ```
147
+
148
+ - `--mode`: (optional) search strategy. `broad` (default), `balanced`, or `strict`.
149
+ - `--min-match`: (optional) minimum number of query terms an app should match.
150
+ - `--limit`: (optional) max number of app results to return.
151
+
152
+ ### examples
153
+
154
+ ```
155
+ pterm search comfyui
156
+ ```
157
+
158
+ ```
159
+ pterm search --q="text generation"
160
+ ```
161
+
162
+ ```
163
+ pterm search "tts speech synthesis" --mode=balanced --min-match=2 --limit=8
164
+ ```
165
+
166
+ ## status
167
+
168
+ Get app status by app id.
169
+
170
+ ### syntax
171
+
172
+ ```
173
+ pterm status <app_id> [--probe] [--timeout=<ms>]
174
+ ```
175
+
176
+ - `--probe`: (optional) actively probe app health.
177
+ - `--timeout`: (optional) probe timeout in milliseconds.
178
+
179
+ ### examples
180
+
181
+ ```
182
+ pterm status comfyanonymous-comfyui
183
+ ```
184
+
185
+ ```
186
+ pterm status comfyanonymous-comfyui --probe --timeout=5000
187
+ ```
188
+
189
+ ## logs
190
+
191
+ Get app logs by app id.
192
+
193
+ ### syntax
194
+
195
+ ```
196
+ pterm logs <app_id> [--script=<name>] [--tail=<lines>]
197
+ ```
198
+
199
+ - `--script`: (optional) filter to a script.
200
+ - `--tail`: (optional) return only the last N lines.
201
+
202
+ ### examples
203
+
204
+ ```
205
+ pterm logs comfyanonymous-comfyui
206
+ ```
207
+
208
+ ```
209
+ pterm logs comfyanonymous-comfyui --script=start --tail=200
210
+ ```
211
+
128
212
  ## filepicker
129
213
 
130
214
  Display a file picker dialog, which lets the user select one or more file or folder paths, powered by tkinter.
@@ -268,4 +352,3 @@ pterm push 'this is a notification' --sound
268
352
  ```
269
353
  pterm push 'this is an image notification' --image=icon.png
270
354
  ```
271
-
package/index.js CHANGED
@@ -2,11 +2,12 @@
2
2
  const path = require('path')
3
3
  const yargs = require('yargs/yargs')
4
4
  const { hideBin } = require('yargs/helpers')
5
+ const argv = yargs(hideBin(process.argv)).parse();
5
6
  const Script = require('./script')
6
7
  const Util = require('./util')
7
- const argv = yargs(hideBin(process.argv)).parse();
8
8
  const script = new Script();
9
9
  const util = new Util();
10
+ const isHttpUri = (value) => typeof value === "string" && /^https?:\/\//i.test(value);
10
11
  (async () => {
11
12
  if (argv._.length > 0) {
12
13
  let cmd = argv._[0].toLowerCase()
@@ -53,6 +54,12 @@ const util = new Util();
53
54
  await util.filepicker(argv)
54
55
  } else if (cmd === "download") {
55
56
  await util.download(argv)
57
+ } else if (cmd === "search") {
58
+ await util.search(argv)
59
+ } else if (cmd === "status") {
60
+ await util.status(argv)
61
+ } else if (cmd === "logs") {
62
+ await util.logs(argv)
56
63
  } else if (cmd === "stop") {
57
64
  await script.stop(argv)
58
65
  } else if (cmd === "start") {
@@ -65,12 +72,13 @@ const util = new Util();
65
72
  } else if (cmd === "run") {
66
73
  if (argv._.length > 1) {
67
74
  let _uri = argv._[1]
68
- const uri = path.resolve(process.cwd(), _uri)
75
+ const uri = isHttpUri(_uri) ? _uri : path.resolve(process.cwd(), _uri)
69
76
  // try downloading first
70
- if (path.isAbsolute(uri)) {
71
- } else {
72
- // url
73
- await util.download(argv)
77
+ if (isHttpUri(uri)) {
78
+ await util.download({
79
+ ...argv,
80
+ no_exit: true
81
+ })
74
82
  }
75
83
  while(true) {
76
84
  let default_uri = await script.default_script(uri)
@@ -87,9 +95,13 @@ const util = new Util();
87
95
  break
88
96
  }
89
97
  } else {
90
- // open in browser
91
- let response = await util.open_url(default_uri)
92
- console.log({ response })
98
+ // default behavior is no browser side effect.
99
+ if (argv.open) {
100
+ let response = await util.open_url(default_uri)
101
+ console.log({ response })
102
+ } else {
103
+ console.log(default_uri)
104
+ }
93
105
  break
94
106
  }
95
107
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pterm",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
package/util.js CHANGED
@@ -3,6 +3,74 @@ const axios = require('axios')
3
3
  const path = require('path')
4
4
  const RPC = require('./rpc')
5
5
  class Util {
6
+ printJson(payload) {
7
+ process.stdout.write(JSON.stringify(payload, null, 2))
8
+ process.stdout.write("\n")
9
+ }
10
+ async search(argv) {
11
+ const query = (argv._.slice(1).join(" ") || argv.q || "").trim()
12
+ const params = { q: query }
13
+ const mode = typeof argv.mode === "string" ? argv.mode.trim().toLowerCase() : ""
14
+ const minMatchRaw = argv.minMatch ?? argv["min-match"] ?? argv.min_match
15
+ const limitRaw = argv.limit
16
+ if (mode === "broad" || mode === "balanced" || mode === "strict") {
17
+ params.mode = mode
18
+ }
19
+ if (minMatchRaw !== undefined && minMatchRaw !== null && minMatchRaw !== "") {
20
+ const minMatch = Number.parseInt(String(minMatchRaw), 10)
21
+ if (Number.isFinite(minMatch) && minMatch > 0) {
22
+ params.min_match = String(minMatch)
23
+ }
24
+ }
25
+ if (limitRaw !== undefined && limitRaw !== null && limitRaw !== "") {
26
+ const limit = Number.parseInt(String(limitRaw), 10)
27
+ if (Number.isFinite(limit) && limit > 0) {
28
+ params.limit = String(limit)
29
+ }
30
+ }
31
+ const response = await axios.get("http://localhost:42000/apps/search", {
32
+ params
33
+ })
34
+ this.printJson(response.data)
35
+ }
36
+ async status(argv) {
37
+ if (argv._.length <= 1) {
38
+ console.error("required argument: <app_id>")
39
+ return
40
+ }
41
+ const appId = argv._[1]
42
+ const probe = argv.probe ? "1" : "0"
43
+ const timeout = argv.timeout ? Number.parseInt(String(argv.timeout), 10) : null
44
+ const params = new URLSearchParams()
45
+ params.set("probe", probe)
46
+ if (Number.isFinite(timeout) && timeout > 0) {
47
+ params.set("timeout", String(timeout))
48
+ }
49
+ const url = `http://localhost:42000/apps/status/${encodeURIComponent(appId)}?${params.toString()}`
50
+ const response = await axios.get(url)
51
+ this.printJson(response.data)
52
+ }
53
+ async logs(argv) {
54
+ if (argv._.length <= 1) {
55
+ console.error("required argument: <app_id>")
56
+ return
57
+ }
58
+ const appId = argv._[1]
59
+ const params = new URLSearchParams()
60
+ if (argv.script) {
61
+ params.set("script", String(argv.script))
62
+ }
63
+ if (argv.tail) {
64
+ const tail = Number.parseInt(String(argv.tail), 10)
65
+ if (Number.isFinite(tail) && tail > 0) {
66
+ params.set("tail", String(tail))
67
+ }
68
+ }
69
+ const suffix = params.toString() ? `?${params.toString()}` : ""
70
+ const url = `http://localhost:42000/apps/logs/${encodeURIComponent(appId)}${suffix}`
71
+ const response = await axios.get(url)
72
+ this.printJson(response.data)
73
+ }
6
74
  async filepicker(argv) {
7
75
  const rpc = new RPC("ws://localhost:42000")
8
76
  if (argv.path) {
@@ -104,7 +172,9 @@ class Util {
104
172
  }
105
173
  })
106
174
  }
107
- process.exit()
175
+ if (!argv.no_exit) {
176
+ process.exit()
177
+ }
108
178
  } else {
109
179
  console.error("required argument: <uri>")
110
180
  }