@tishlang/tish-desktop 1.1.0 → 1.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tishlang/tish-desktop",
3
- "version": "1.1.0",
3
+ "version": "1.1.4",
4
4
  "description": "Tish Desktop CLI — init, dev, build, info, icon, distribute",
5
5
  "license": "PIF",
6
6
  "type": "module",
@@ -1,12 +1,5 @@
1
1
  import { exit, cwd, exec } from "tish:process"
2
- import {
3
- firstPositional,
4
- joinPath,
5
- pathExists,
6
- q,
7
- repoRoot,
8
- resolveTish,
9
- } from "../paths.tish"
2
+ import { firstPositional, joinPath, pathExists, q, repoRoot, resolveTish } from "../paths.tish"
10
3
 
11
4
  fn sh(cmd) {
12
5
  console.log("-> " + cmd)
@@ -24,10 +17,16 @@ export fn runBuild(args) {
24
17
 
25
18
  if (name !== null && pathExists(joinPath(root, "examples/" + name))) {
26
19
  projectDir = joinPath(root, "examples/" + name)
27
- } else if (name !== null) {
28
- let candidate = name
29
- if (!String(name).startsWith("/")) candidate = joinPath(cwd(), name)
30
- if (pathExists(candidate)) projectDir = candidate
20
+ } else {
21
+ if (name !== null) {
22
+ let candidate = name
23
+ if (!String(name).startsWith("/")) {
24
+ candidate = joinPath(cwd(), name)
25
+ }
26
+ if (pathExists(candidate)) {
27
+ projectDir = candidate
28
+ }
29
+ }
31
30
  }
32
31
 
33
32
  if (!pathExists(joinPath(projectDir, "package.json"))) {
@@ -46,8 +45,9 @@ export fn runBuild(args) {
46
45
  let out = "dist/app-shell"
47
46
  console.log("[build] npm run build:shell missing/failed — compiling " + out)
48
47
  sh(
49
- "cd " + q(projectDir) + " && " + q(tishBin) +
50
- " build --target native --native-backend rust src/main.tish -o " + q(out)
48
+ "cd " + q(projectDir) + " && " + q(tishBin) + " build --target native --native-backend rust src/main.tish -o " + q(
49
+ out
50
+ )
51
51
  )
52
52
  }
53
53
 
@@ -3,31 +3,40 @@
3
3
  // backgrounded with `sh -c '… &'`. Pass --legacy-node to call the Node script.
4
4
  import { exit, cwd, exec, env } from "tish:process"
5
5
  import { readFile } from "tish:fs"
6
- import {
7
- flagValue,
8
- firstPositional,
9
- hasFlag,
10
- joinPath,
11
- pathExists,
12
- q,
13
- repoRoot,
14
- resolveTish,
15
- } from "../paths.tish"
6
+ import { flagValue, firstPositional, hasFlag, joinPath, pathExists, q, repoRoot, resolveTish } from "../paths.tish"
16
7
 
17
8
  fn examplePort(name) {
18
- if (name === "file-browser") return 5174
19
- if (name === "native-chrome") return 5175
20
- if (name === "byo-ui") return 5176
21
- if (name === "hybrid") return 5177
9
+ if (name === "file-browser") {
10
+ return 5174
11
+ }
12
+ if (name === "native-chrome") {
13
+ return 5175
14
+ }
15
+ if (name === "byo-ui") {
16
+ return 5176
17
+ }
18
+ if (name === "hybrid") {
19
+ return 5177
20
+ }
22
21
  return 5173
23
22
  }
24
23
 
25
24
  fn exampleShellOut(name) {
26
- if (name === "basic") return "dist/basic-shell"
27
- if (name === "file-browser") return "dist/file-browser-shell"
28
- if (name === "native-chrome") return "dist/native-chrome-shell"
29
- if (name === "byo-ui") return "dist/byo-ui-shell"
30
- if (name === "hybrid") return "dist/hybrid-shell"
25
+ if (name === "basic") {
26
+ return "dist/basic-shell"
27
+ }
28
+ if (name === "file-browser") {
29
+ return "dist/file-browser-shell"
30
+ }
31
+ if (name === "native-chrome") {
32
+ return "dist/native-chrome-shell"
33
+ }
34
+ if (name === "byo-ui") {
35
+ return "dist/byo-ui-shell"
36
+ }
37
+ if (name === "hybrid") {
38
+ return "dist/hybrid-shell"
39
+ }
31
40
  return "dist/" + name + "-shell"
32
41
  }
33
42
 
@@ -37,19 +46,29 @@ fn sleepMs(ms) {
37
46
 
38
47
  fn httpCode(url) {
39
48
  let out = "/tmp/tish-desktop-http-code.txt"
40
- exec("curl -s -o /dev/null -w '%{http_code}' " + q(url) + " > " + q(out) + " 2>/dev/null || echo 000 > " + q(out))
41
- if (!pathExists(out)) return "000"
49
+ exec(
50
+ "curl -s -o /dev/null -w '%{http_code}' " + q(url) + " > " + q(out) + " 2>/dev/null || echo 000 > " + q(
51
+ out
52
+ )
53
+ )
54
+ if (!pathExists(out)) {
55
+ return "000"
56
+ }
42
57
  return String(readFile(out)).trim()
43
58
  }
44
59
 
45
60
  fn waitForHttp(url, timeoutMs) {
46
61
  let maxTries = Math.floor(timeoutMs / 250)
47
- if (maxTries < 1) maxTries = 1
62
+ if (maxTries < 1) {
63
+ maxTries = 1
64
+ }
48
65
  let n = 0
49
66
  while (n < maxTries) {
50
67
  let code = httpCode(url)
51
68
  let num = Number(code)
52
- if (num >= 200 && num < 500) return true
69
+ if (num >= 200 && num < 500) {
70
+ return true
71
+ }
53
72
  sleepMs(250)
54
73
  n = n + 1
55
74
  }
@@ -61,7 +80,7 @@ fn warmupVite(baseUrl) {
61
80
  baseUrl + "/",
62
81
  baseUrl + "/assets/app.css",
63
82
  baseUrl + "/bridge-boot.js",
64
- baseUrl + "/ui/main.tish",
83
+ baseUrl + "/ui/main.tish"
65
84
  ]
66
85
  let i = 0
67
86
  while (i < urls.length) {
@@ -70,28 +89,28 @@ fn warmupVite(baseUrl) {
70
89
  }
71
90
  let bodyFile = "/tmp/tish-desktop-vite-main.txt"
72
91
  exec(
73
- "curl -s -H 'Accept: text/javascript' " + q(baseUrl + "/ui/main.tish") +
74
- " > " + q(bodyFile) + " 2>/dev/null || true"
92
+ "curl -s -H 'Accept: text/javascript' " + q(baseUrl + "/ui/main.tish") + " > " + q(bodyFile) + " 2>/dev/null || true"
75
93
  )
76
94
  if (pathExists(bodyFile)) {
77
95
  let text = String(readFile(bodyFile))
78
- let parts = text.split('from "')
96
+ let parts = text.split("from \"")
79
97
  let p = 1
80
98
  while (p < parts.length) {
81
99
  let rest = parts[p]
82
- let end = rest.indexOf('"')
100
+ let end = rest.indexOf("\"")
83
101
  if (end > 0) {
84
102
  let spec = rest.slice(0, end)
85
103
  let next = null
86
104
  if (spec.startsWith("./")) {
87
105
  next = baseUrl + "/ui/" + spec.slice(2)
88
- } else if (spec.startsWith("/")) {
89
- next = baseUrl + spec
106
+ } else {
107
+ if (spec.startsWith("/")) {
108
+ next = baseUrl + spec
109
+ }
90
110
  }
91
111
  if (next !== null) {
92
112
  exec(
93
- "curl -s -o /dev/null -H 'Accept: text/javascript' " + q(next) +
94
- " >/dev/null 2>&1 || true"
113
+ "curl -s -o /dev/null -H 'Accept: text/javascript' " + q(next) + " >/dev/null 2>&1 || true"
95
114
  )
96
115
  }
97
116
  }
@@ -104,8 +123,9 @@ fn warmupVite(baseUrl) {
104
123
  fn buildShell(tishBin, exampleDir, shellOut, shellPath) {
105
124
  console.log("[dev] building shell with " + tishBin + " → " + shellOut)
106
125
  let code = exec(
107
- "cd " + q(exampleDir) + " && " + q(tishBin) +
108
- " build --target native --native-backend rust src/main.tish -o " + q(shellOut)
126
+ "cd " + q(exampleDir) + " && " + q(tishBin) + " build --target native --native-backend rust src/main.tish -o " + q(
127
+ shellOut
128
+ )
109
129
  )
110
130
  if (code !== 0) {
111
131
  console.error("[dev] shell build failed (exit " + String(code) + ")")
@@ -118,18 +138,22 @@ fn buildShell(tishBin, exampleDir, shellOut, shellPath) {
118
138
  }
119
139
 
120
140
  fn shellNeedsRebuild(root, exampleDir, shellPath) {
121
- if (!pathExists(shellPath)) return true
141
+ if (!pathExists(shellPath)) {
142
+ return true
143
+ }
122
144
  // Recursive: any file under host/shell sources newer than the binary.
123
145
  let marker = "/tmp/tish-desktop-shell-stale.txt"
124
146
  let hostSrc = joinPath(root, "crates/tish_desktop/src")
125
147
  let hostToml = joinPath(root, "crates/tish_desktop/Cargo.toml")
126
148
  let shellSrc = joinPath(exampleDir, "src")
127
149
  exec(
128
- "if [ -n \"$(find " + q(hostSrc) + " " + q(shellSrc) + " " + q(hostToml) +
129
- " -type f -newer " + q(shellPath) + " 2>/dev/null | head -1)\" ]; then echo yes; else echo no; fi > " +
130
- q(marker)
150
+ "if [ -n \"$(find " + q(hostSrc) + " " + q(shellSrc) + " " + q(hostToml) + " -type f -newer " + q(
151
+ shellPath
152
+ ) + " 2>/dev/null | head -1)\" ]; then echo yes; else echo no; fi > " + q(marker)
131
153
  )
132
- if (!pathExists(marker)) return true
154
+ if (!pathExists(marker)) {
155
+ return true
156
+ }
133
157
  return String(readFile(marker)).trim() === "yes"
134
158
  }
135
159
 
@@ -146,8 +170,12 @@ export fn runDev(args) {
146
170
  }
147
171
 
148
172
  let name = flagValue(args, "--example")
149
- if (name === null) name = firstPositional(args)
150
- if (name === null) name = "basic"
173
+ if (name === null) {
174
+ name = firstPositional(args)
175
+ }
176
+ if (name === null) {
177
+ name = "basic"
178
+ }
151
179
 
152
180
  if (legacyNode) {
153
181
  let script = joinPath(root, "scripts/dev-example.mjs")
@@ -165,34 +193,39 @@ export fn runDev(args) {
165
193
  name = "app"
166
194
  } else {
167
195
  console.error("[dev] example not found: " + exampleDir)
168
- console.error(" pass --example basic|file-browser|native-chrome|byo-ui|hybrid, or run inside an app dir")
196
+ console.error(
197
+ " pass --example basic|file-browser|native-chrome|byo-ui|hybrid, or run inside an app dir"
198
+ )
169
199
  exit(1)
170
200
  }
171
201
  }
172
202
 
173
203
  let port = examplePort(name)
174
- if (name === "app") port = 5173
204
+ if (name === "app") {
205
+ port = 5173
206
+ }
175
207
  let shellOut = exampleShellOut(name)
176
- if (name === "app") shellOut = "dist/app-shell"
208
+ if (name === "app") {
209
+ shellOut = "dist/app-shell"
210
+ }
177
211
  let shellPath = joinPath(exampleDir, shellOut)
178
212
 
179
- console.log("[dev] " + name + " — starting Vite :" + String(port) + ", then native desktop shell")
213
+ console.log(
214
+ "[dev] " + name + " — starting Vite :" + String(port) + ", then native desktop shell"
215
+ )
180
216
 
181
217
  let cssScript = joinPath(exampleDir, "scripts/build-css.tish")
182
218
  if (pathExists(cssScript)) {
183
- let cssCode = exec(
184
- "cd " + q(exampleDir) + " && tish run --feature fs scripts/build-css.tish"
185
- )
219
+ let cssCode = exec("cd " + q(exampleDir) + " && tish run --feature fs scripts/build-css.tish")
186
220
  if (cssCode !== 0) {
187
221
  console.log("[dev] build-css failed (continuing; styles may be stale)")
188
222
  }
189
223
  }
190
224
 
191
225
  killVite(port)
192
- let viteCmd =
193
- "cd " + q(exampleDir) +
194
- " && npx vite --port " + String(port) + " --strictPort >/tmp/tish-desktop-vite-" +
195
- String(port) + ".log 2>&1 &"
226
+ let viteCmd = "cd " + q(exampleDir) + " && npx vite --port " + String(port) + " --strictPort >/tmp/tish-desktop-vite-" + String(
227
+ port
228
+ ) + ".log 2>&1 &"
196
229
  exec(viteCmd)
197
230
 
198
231
  let baseUrl = "http://localhost:" + String(port)
@@ -31,22 +31,32 @@ export fn runDistribute(args) {
31
31
  let cmd = null
32
32
  if (step === "build") {
33
33
  cmd = "node " + q(joinPath(distDir, "build-release.mjs"))
34
- } else if (step === "sign") {
35
- cmd = "bash " + q(joinPath(distDir, "sign-macos.sh"))
36
- } else if (step === "notarize") {
37
- cmd = "bash " + q(joinPath(distDir, "notarize-macos.sh"))
38
- } else if (step === "updater") {
39
- cmd = "node " + q(joinPath(distDir, "publish-updater.mjs"))
40
- } else if (step === "github") {
41
- cmd = "node " + q(joinPath(distDir, "publish-github-release.mjs"))
42
- } else if (step === "release") {
43
- cmd =
44
- "node " + q(joinPath(distDir, "build-release.mjs")) +
45
- " && node " + q(joinPath(distDir, "publish-github-release.mjs"))
46
34
  } else {
47
- console.error("unknown distribute step: " + step)
48
- usage()
49
- exit(1)
35
+ if (step === "sign") {
36
+ cmd = "bash " + q(joinPath(distDir, "sign-macos.sh"))
37
+ } else {
38
+ if (step === "notarize") {
39
+ cmd = "bash " + q(joinPath(distDir, "notarize-macos.sh"))
40
+ } else {
41
+ if (step === "updater") {
42
+ cmd = "node " + q(joinPath(distDir, "publish-updater.mjs"))
43
+ } else {
44
+ if (step === "github") {
45
+ cmd = "node " + q(joinPath(distDir, "publish-github-release.mjs"))
46
+ } else {
47
+ if (step === "release") {
48
+ cmd = "node " + q(joinPath(distDir, "build-release.mjs")) + " && node " + q(
49
+ joinPath(distDir, "publish-github-release.mjs")
50
+ )
51
+ } else {
52
+ console.error("unknown distribute step: " + step)
53
+ usage()
54
+ exit(1)
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
50
60
  }
51
61
 
52
62
  console.log("[distribute] " + step)
@@ -1,24 +1,24 @@
1
1
  import { exit, env, cwd, exec } from "tish:process"
2
2
  import { readFile } from "tish:fs"
3
- import {
4
- flagValue,
5
- joinPath,
6
- pathExists,
7
- q,
8
- resolveTish,
9
- } from "../paths.tish"
3
+ import { flagValue, joinPath, pathExists, q, resolveTish } from "../paths.tish"
10
4
 
11
5
  fn capLevel(name, surface, platform) {
12
6
  if (name === "notification") {
13
- if (surface === "web") return "Partial"
7
+ if (surface === "web") {
8
+ return "Partial"
9
+ }
14
10
  return "Full"
15
11
  }
16
12
  if (name === "store") {
17
- if (surface === "web" || platform === "ios") return "Unsupported"
13
+ if (surface === "web" || platform === "ios") {
14
+ return "Unsupported"
15
+ }
18
16
  return "Full"
19
17
  }
20
18
  if (name === "tray") {
21
- if (surface === "web" || platform === "ios" || surface === "native") return "Unsupported"
19
+ if (surface === "web" || platform === "ios" || surface === "native") {
20
+ return "Unsupported"
21
+ }
22
22
  return "Full"
23
23
  }
24
24
  return "Unsupported"
@@ -38,12 +38,20 @@ export fn runDoctor(args) {
38
38
  // `--desk-platform` / `--desk-surface` are rewritten from `--platform` /
39
39
  // `--surface` by cli/bin/mode.js so `tish run` is not disrupted.
40
40
  let platform = flagValue(args, "--desk-platform")
41
- if (platform === null) platform = flagValue(args, "--platform")
42
- if (platform === null) platform = "macos"
41
+ if (platform === null) {
42
+ platform = flagValue(args, "--platform")
43
+ }
44
+ if (platform === null) {
45
+ platform = "macos"
46
+ }
43
47
 
44
48
  let surface = flagValue(args, "--desk-surface")
45
- if (surface === null) surface = flagValue(args, "--surface")
46
- if (surface === null) surface = "webview"
49
+ if (surface === null) {
50
+ surface = flagValue(args, "--surface")
51
+ }
52
+ if (surface === null) {
53
+ surface = "webview"
54
+ }
47
55
 
48
56
  let tish = resolveTish()
49
57
  console.log("mode doctor")
@@ -53,13 +61,19 @@ export fn runDoctor(args) {
53
61
  console.log(" tish: " + tish)
54
62
 
55
63
  let probe = flagValue(args, "--resolve")
56
- if (probe === null) probe = "./Button"
64
+ if (probe === null) {
65
+ probe = "./Button"
66
+ }
57
67
  let importer = flagValue(args, "--importer")
58
68
  if (importer === null) {
59
69
  let here = cwd()
60
70
  importer = joinPath(here, "src/main.tish")
61
- if (!pathExists(importer)) importer = joinPath(here, "ui/main.tish")
62
- if (!pathExists(importer)) importer = joinPath(here, "app/App.tish")
71
+ if (!pathExists(importer)) {
72
+ importer = joinPath(here, "ui/main.tish")
73
+ }
74
+ if (!pathExists(importer)) {
75
+ importer = joinPath(here, "app/App.tish")
76
+ }
63
77
  }
64
78
 
65
79
  console.log(" resolve: " + probe + " (importer " + importer + ")")
@@ -86,6 +100,8 @@ export fn runDoctor(args) {
86
100
  console.log("Upgrade path (Web -> Webview -> Hybrid):")
87
101
  console.log(" npm run build:web | build:shell | build:shell:apple / dev:hybrid")
88
102
  console.log(" See docs/HYBRID.md · docs/UNIFIED_APP.md")
89
- console.log("HMR: platform file edits reload; switching TISH_PLATFORM/SURFACE needs Vite restart.")
103
+ console.log(
104
+ "HMR: platform file edits reload; switching TISH_PLATFORM/SURFACE needs Vite restart."
105
+ )
90
106
  exit(0)
91
107
  }
@@ -6,8 +6,11 @@ export fn runIcon(args) {
6
6
  let dir = firstPositional(args)
7
7
  let projectDir = cwd()
8
8
  if (dir !== null) {
9
- if (String(dir).startsWith("/")) projectDir = dir
10
- else projectDir = joinPath(cwd(), dir)
9
+ if (String(dir).startsWith("/")) {
10
+ projectDir = dir
11
+ } else {
12
+ projectDir = joinPath(cwd(), dir)
13
+ }
11
14
  }
12
15
 
13
16
  let iconsDir = joinPath(projectDir, "icons")
@@ -15,12 +18,7 @@ export fn runIcon(args) {
15
18
 
16
19
  // Minimal placeholder SVG icon set. Real raster generation can land later
17
20
  // (sips / ImageMagick) once distribute scripts ship.
18
- let svg =
19
- '<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">' +
20
- '<rect width="1024" height="1024" rx="192" fill="#18181b"/>' +
21
- '<circle cx="512" cy="512" r="280" fill="#10b981"/>' +
22
- '<text x="512" y="580" text-anchor="middle" font-family="DM Sans, sans-serif" font-size="320" font-weight="700" fill="#ffffff">T</text>' +
23
- "</svg>"
21
+ let svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\">" + "<rect width=\"1024\" height=\"1024\" rx=\"192\" fill=\"#18181b\"/>" + "<circle cx=\"512\" cy=\"512\" r=\"280\" fill=\"#10b981\"/>" + "<text x=\"512\" y=\"580\" text-anchor=\"middle\" font-family=\"DM Sans, sans-serif\" font-size=\"320\" font-weight=\"700\" fill=\"#ffffff\">T</text>" + "</svg>"
24
22
 
25
23
  let svgPath = joinPath(iconsDir, "icon.svg")
26
24
  writeFile(svgPath, svg)
@@ -29,8 +27,7 @@ export fn runIcon(args) {
29
27
  // Best-effort PNG via `sips` on macOS when available.
30
28
  let pngPath = joinPath(iconsDir, "icon.png")
31
29
  let code = exec(
32
- "command -v sips >/dev/null 2>&1 && sips -s format png " +
33
- q(svgPath) + " --out " + q(pngPath) + " >/dev/null 2>&1"
30
+ "command -v sips >/dev/null 2>&1 && sips -s format png " + q(svgPath) + " --out " + q(pngPath) + " >/dev/null 2>&1"
34
31
  )
35
32
  if (code === 0 && pathExists(pngPath)) {
36
33
  console.log("[icon] wrote " + pngPath)
@@ -38,5 +35,7 @@ export fn runIcon(args) {
38
35
  console.log("[icon] PNG skipped (install sips/ImageMagick or convert icon.svg manually)")
39
36
  }
40
37
 
41
- console.log("[icon] place platform icons under " + iconsDir + " and point tauri.conf / bundler at them")
38
+ console.log(
39
+ "[icon] place platform icons under " + iconsDir + " and point tauri.conf / bundler at them"
40
+ )
42
41
  }
@@ -59,7 +59,9 @@ export fn runInfo(_args) {
59
59
  platform = String(env["OSTYPE"])
60
60
  } else {
61
61
  let u = capture("uname -s")
62
- if (u.text !== "") platform = u.text.split("\n")[0]
62
+ if (u.text !== "") {
63
+ platform = u.text.split("\n")[0]
64
+ }
63
65
  }
64
66
  console.log("platform: " + platform)
65
67
  console.log("")
@@ -10,19 +10,25 @@ import {
10
10
  joinPath,
11
11
  pathExists,
12
12
  q,
13
- repoRoot,
13
+ repoRoot
14
14
  } from "../paths.tish"
15
15
 
16
16
  fn relPath(fromDir, toDir) {
17
- if (fromDir === toDir) return "."
17
+ if (fromDir === toDir) {
18
+ return "."
19
+ }
18
20
  let prefix = fromDir
19
- if (!prefix.endsWith("/")) prefix = prefix + "/"
21
+ if (!prefix.endsWith("/")) {
22
+ prefix = prefix + "/"
23
+ }
20
24
  if (String(toDir).startsWith(prefix)) {
21
25
  return String(toDir).slice(prefix.length)
22
26
  }
23
27
  // Prefer absolute when the scaffold is outside the repo tree.
24
28
  let rootPrefix = toDir
25
- if (!rootPrefix.endsWith("/")) rootPrefix = rootPrefix + "/"
29
+ if (!rootPrefix.endsWith("/")) {
30
+ rootPrefix = rootPrefix + "/"
31
+ }
26
32
  if (!String(fromDir).startsWith(rootPrefix) && !String(fromDir).startsWith(String(toDir))) {
27
33
  return toDir
28
34
  }
@@ -43,13 +49,19 @@ fn relPath(fromDir, toDir) {
43
49
  u = u + 1
44
50
  }
45
51
  // Too many hops → absolute (avoids ../../Users/... from /tmp).
46
- if (ups > 3) return toDir
52
+ if (ups > 3) {
53
+ return toDir
54
+ }
47
55
  let d = i
48
56
  while (d < toParts.length) {
49
- if (toParts[d] !== "") parts.push(toParts[d])
57
+ if (toParts[d] !== "") {
58
+ parts.push(toParts[d])
59
+ }
50
60
  d = d + 1
51
61
  }
52
- if (parts.length === 0) return "."
62
+ if (parts.length === 0) {
63
+ return "."
64
+ }
53
65
  return parts.join("/")
54
66
  }
55
67
 
@@ -126,13 +138,31 @@ fn applyRegistryOverlay(templates, target, appName, shellOut, port, pkgVersion)
126
138
  console.error("init: registry templates missing under " + templates)
127
139
  exit(1)
128
140
  }
129
- copyTemplateFile(pkgSrc, joinPath(target, "package.json"), appName, ".", shellOut, port, pkgVersion)
130
- copyTemplateFile(viteSrc, joinPath(target, "vite.config.mjs"), appName, ".", shellOut, port, pkgVersion)
141
+ copyTemplateFile(
142
+ pkgSrc,
143
+ joinPath(target, "package.json"),
144
+ appName,
145
+ ".",
146
+ shellOut,
147
+ port,
148
+ pkgVersion
149
+ )
150
+ copyTemplateFile(
151
+ viteSrc,
152
+ joinPath(target, "vite.config.mjs"),
153
+ appName,
154
+ ".",
155
+ shellOut,
156
+ port,
157
+ pkgVersion
158
+ )
131
159
  }
132
160
 
133
161
  export fn runInit(args) {
134
162
  let dirArg = firstPositional(args)
135
- if (dirArg === null) dirArg = "my-desktop-app"
163
+ if (dirArg === null) {
164
+ dirArg = "my-desktop-app"
165
+ }
136
166
  let here = cwd()
137
167
  let target = dirArg
138
168
  if (!String(dirArg).startsWith("/")) {
@@ -159,19 +189,25 @@ export fn runInit(args) {
159
189
  }
160
190
  templateName = uiName
161
191
  }
162
- if (templateName === null) templateName = "lattish"
192
+ if (templateName === null) {
193
+ templateName = "lattish"
194
+ }
163
195
  let templateDir = "templates/app"
164
196
  if (templateName === "bare" || templateName === "none" || templateName === "byo") {
165
197
  templateDir = "templates/bare"
166
- } else if (templateName === "lattish" || templateName === "app" || templateName === "default") {
167
- templateDir = "templates/app"
168
198
  } else {
169
- console.error("init: unknown --template/--ui " + templateName + " (use lattish|bare|none)")
170
- exit(1)
199
+ if (templateName === "lattish" || templateName === "app" || templateName === "default") {
200
+ templateDir = "templates/app"
201
+ } else {
202
+ console.error("init: unknown --template/--ui " + templateName + " (use lattish|bare|none)")
203
+ exit(1)
204
+ }
171
205
  }
172
206
  let templates = joinPath(cliRoot(), templateDir)
173
207
  let appName = basename(target)
174
- if (appName === "" || appName === "." || appName === "/") appName = "my-desktop-app"
208
+ if (appName === "" || appName === "." || appName === "/") {
209
+ appName = "my-desktop-app"
210
+ }
175
211
 
176
212
  let relRoot = monorepo ? relPath(target, root) : "."
177
213
  let shellOut = "dist/" + appName + "-shell"
@@ -181,7 +217,9 @@ export fn runInit(args) {
181
217
  if (monorepo) {
182
218
  console.log("[init] monorepo mode — path deps → " + relRoot)
183
219
  } else {
184
- console.log("[init] registry mode — @tishlang/tish-desktop*@" + pkgVersion + " (outside tish-mode checkout)")
220
+ console.log(
221
+ "[init] registry mode — @tishlang/tish-desktop*@" + pkgVersion + " (outside tish-mode checkout)"
222
+ )
185
223
  }
186
224
  mkdir(target, true)
187
225
  walkCopy(templates, target, appName, relRoot, shellOut, port, pkgVersion, true)
@@ -5,15 +5,7 @@
5
5
  // mode ios --example hello-ios --launch-only
6
6
  // mode ios --example hello-ios --device "iPhone 16"
7
7
  import { exit, cwd, exec, env } from "tish:process"
8
- import {
9
- flagValue,
10
- firstPositional,
11
- hasFlag,
12
- joinPath,
13
- pathExists,
14
- q,
15
- repoRoot,
16
- } from "../paths.tish"
8
+ import { flagValue, firstPositional, hasFlag, joinPath, pathExists, q, repoRoot } from "../paths.tish"
17
9
 
18
10
  fn usage() {
19
11
  console.log("mode ios — build + launch an iOS example on the Simulator")
@@ -34,16 +26,24 @@ fn usage() {
34
26
  fn dirnameOf(p) {
35
27
  let s = String(p)
36
28
  let i = s.lastIndexOf("/")
37
- if (i < 0) return "."
38
- if (i === 0) return "/"
29
+ if (i < 0) {
30
+ return "."
31
+ }
32
+ if (i === 0) {
33
+ return "/"
34
+ }
39
35
  return s.slice(0, i)
40
36
  }
41
37
 
42
38
  fn resolveAppleRoot(args) {
43
39
  let fromFlag = flagValue(args, "--apple")
44
- if (fromFlag !== null) return fromFlag
40
+ if (fromFlag !== null) {
41
+ return fromFlag
42
+ }
45
43
  let fromEnv = env !== null ? env["TISH_APPLE"] : null
46
- if (fromEnv !== null && fromEnv !== undefined && fromEnv !== "") return fromEnv
44
+ if (fromEnv !== null && fromEnv !== undefined && fromEnv !== "") {
45
+ return fromEnv
46
+ }
47
47
  let root = repoRoot()
48
48
  let sibling = joinPath(dirnameOf(root), "tish-apple")
49
49
  if (pathExists(joinPath(sibling, "crates/tish-ios/Cargo.toml"))) {
package/src/main.tish CHANGED
@@ -21,13 +21,19 @@ fn usage() {
21
21
  console.log("")
22
22
  console.log("Commands:")
23
23
  console.log(" init [dir] Scaffold a desktop app")
24
- console.log(" dev [--example name] Vite UI + native shell (parity with scripts/dev-example.mjs)")
24
+ console.log(
25
+ " dev [--example name] Vite UI + native shell (parity with scripts/dev-example.mjs)"
26
+ )
25
27
  console.log(" build [dir] Production UI + native shell → dist/")
26
28
  console.log(" ios [--example name] Build + launch iOS example on Simulator (no Xcode UI)")
27
- console.log(" doctor Platform/surface, resolve probe, cap matrix (≡ tish app doctor)")
29
+ console.log(
30
+ " doctor Platform/surface, resolve probe, cap matrix (≡ tish app doctor)"
31
+ )
28
32
  console.log(" info Print tish / rustc / platform summary")
29
33
  console.log(" icon [dir] Generate icon set into project icons/")
30
- console.log(" distribute <step> Run scripts/distribute/* (build|sign|notarize|updater|release)")
34
+ console.log(
35
+ " distribute <step> Run scripts/distribute/* (build|sign|notarize|updater|release)"
36
+ )
31
37
  console.log(" help Show this message")
32
38
  console.log("")
33
39
  console.log("Init options:")
package/src/paths.tish CHANGED
@@ -7,25 +7,43 @@ export fn pathExists(p) {
7
7
  }
8
8
 
9
9
  export fn joinPath(a, b) {
10
- if (a === null || a === "") return b
11
- if (b === null || b === "") return a
12
- if (a === ".") return b
13
- if (a.endsWith("/")) return a + b
10
+ if (a === null || a === "") {
11
+ return b
12
+ }
13
+ if (b === null || b === "") {
14
+ return a
15
+ }
16
+ if (a === ".") {
17
+ return b
18
+ }
19
+ if (a.endsWith("/")) {
20
+ return a + b
21
+ }
14
22
  return a + "/" + b
15
23
  }
16
24
 
17
25
  export fn dirname(p) {
18
- if (p === null || p === "") return "."
26
+ if (p === null || p === "") {
27
+ return "."
28
+ }
19
29
  let i = p.lastIndexOf("/")
20
- if (i < 0) return "."
21
- if (i === 0) return "/"
30
+ if (i < 0) {
31
+ return "."
32
+ }
33
+ if (i === 0) {
34
+ return "/"
35
+ }
22
36
  return p.slice(0, i)
23
37
  }
24
38
 
25
39
  export fn basename(p) {
26
- if (p === null || p === "") return ""
40
+ if (p === null || p === "") {
41
+ return ""
42
+ }
27
43
  let i = p.lastIndexOf("/")
28
- if (i < 0) return p
44
+ if (i < 0) {
45
+ return p
46
+ }
29
47
  return p.slice(i + 1)
30
48
  }
31
49
 
@@ -50,7 +68,9 @@ export fn userArgs() {
50
68
  export fn hasFlag(args, flag) {
51
69
  let i = 0
52
70
  while (i < args.length) {
53
- if (args[i] === flag) return true
71
+ if (args[i] === flag) {
72
+ return true
73
+ }
54
74
  i = i + 1
55
75
  }
56
76
  return false
@@ -59,7 +79,9 @@ export fn hasFlag(args, flag) {
59
79
  export fn flagValue(args, flag) {
60
80
  let i = 0
61
81
  while (i < args.length) {
62
- if (args[i] === flag && i + 1 < args.length) return args[i + 1]
82
+ if (args[i] === flag && i + 1 < args.length) {
83
+ return args[i + 1]
84
+ }
63
85
  if (String(args[i]).startsWith(flag + "=")) {
64
86
  return String(args[i]).slice(flag.length + 1)
65
87
  }
@@ -72,7 +94,9 @@ export fn firstPositional(args) {
72
94
  let i = 0
73
95
  while (i < args.length) {
74
96
  let a = args[i]
75
- if (!String(a).startsWith("-")) return a
97
+ if (!String(a).startsWith("-")) {
98
+ return a
99
+ }
76
100
  if ((a === "--example" || a === "--dir" || a === "--out" || a === "--template" || a === "--ui" || a === "--platform" || a === "--surface" || a === "--desk-platform" || a === "--desk-surface" || a === "--resolve" || a === "--importer" || a === "--device" || a === "--apple") && i + 1 < args.length) {
77
101
  i = i + 2
78
102
  continue
@@ -84,9 +108,13 @@ export fn firstPositional(args) {
84
108
 
85
109
  fn looksLikeCliRoot(dir) {
86
110
  let pkg = joinPath(dir, "package.json")
87
- if (!pathExists(pkg)) return false
111
+ if (!pathExists(pkg)) {
112
+ return false
113
+ }
88
114
  let text = readFile(pkg)
89
- if (text === null || String(text).startsWith("Error:")) return false
115
+ if (text === null || String(text).startsWith("Error:")) {
116
+ return false
117
+ }
90
118
  return String(text).indexOf("@tishlang/tish-desktop") >= 0
91
119
  }
92
120
 
@@ -103,19 +131,31 @@ export fn inMonorepoCheckout() {
103
131
  export fn cliPackageVersion() {
104
132
  let pkg = joinPath(cliRoot(), "package.json")
105
133
  let text = readFile(pkg)
106
- if (text === null || String(text).startsWith("Error:")) return "0.1.0"
134
+ if (text === null || String(text).startsWith("Error:")) {
135
+ return "0.1.0"
136
+ }
107
137
  let s = String(text)
108
138
  let key = "\"version\""
109
139
  let i = s.indexOf(key)
110
- if (i < 0) return "0.1.0"
140
+ if (i < 0) {
141
+ return "0.1.0"
142
+ }
111
143
  let colon = s.indexOf(":", i + key.length)
112
- if (colon < 0) return "0.1.0"
144
+ if (colon < 0) {
145
+ return "0.1.0"
146
+ }
113
147
  let q1 = s.indexOf("\"", colon + 1)
114
- if (q1 < 0) return "0.1.0"
148
+ if (q1 < 0) {
149
+ return "0.1.0"
150
+ }
115
151
  let q2 = s.indexOf("\"", q1 + 1)
116
- if (q2 < 0) return "0.1.0"
152
+ if (q2 < 0) {
153
+ return "0.1.0"
154
+ }
117
155
  let ver = s.slice(q1 + 1, q2)
118
- if (ver === "") return "0.1.0"
156
+ if (ver === "") {
157
+ return "0.1.0"
158
+ }
119
159
  return ver
120
160
  }
121
161
 
@@ -125,22 +165,33 @@ export fn cliRoot() {
125
165
  let candidate = null
126
166
  if (argv.length >= 2 && argv[1] !== null && String(argv[1]).endsWith(".tish")) {
127
167
  let script = String(argv[1])
128
- if (!script.startsWith("/")) script = joinPath(here, script)
168
+ if (!script.startsWith("/")) {
169
+ script = joinPath(here, script)
170
+ }
129
171
  let srcDir = dirname(script)
130
172
  let root = dirname(srcDir)
131
- if (looksLikeCliRoot(root)) candidate = root
173
+ if (looksLikeCliRoot(root)) {
174
+ candidate = root
175
+ }
132
176
  }
133
177
  if (candidate === null && argv.length >= 1 && argv[0] !== null) {
134
178
  let exe = String(argv[0])
135
179
  if (exe.indexOf("mode") >= 0 || exe.indexOf("tish-desktop") >= 0) {
136
180
  let dist = dirname(exe)
137
181
  let root = dirname(dist)
138
- if (looksLikeCliRoot(root)) candidate = root
182
+ if (looksLikeCliRoot(root)) {
183
+ candidate = root
184
+ }
139
185
  }
140
186
  }
141
187
  if (candidate === null) {
142
- if (looksLikeCliRoot(here)) candidate = here
143
- else if (looksLikeCliRoot(joinPath(here, "cli"))) candidate = joinPath(here, "cli")
188
+ if (looksLikeCliRoot(here)) {
189
+ candidate = here
190
+ } else {
191
+ if (looksLikeCliRoot(joinPath(here, "cli"))) {
192
+ candidate = joinPath(here, "cli")
193
+ }
194
+ }
144
195
  }
145
196
  if (candidate === null) {
146
197
  let walk = here
@@ -155,14 +206,20 @@ export fn cliRoot() {
155
206
  break
156
207
  }
157
208
  let parent = dirname(walk)
158
- if (parent === walk) break
209
+ if (parent === walk) {
210
+ break
211
+ }
159
212
  walk = parent
160
213
  n = n + 1
161
214
  }
162
215
  }
163
- if (candidate === null) candidate = here
216
+ if (candidate === null) {
217
+ candidate = here
218
+ }
164
219
  if (candidate === "." || !String(candidate).startsWith("/")) {
165
- if (candidate === "." || candidate === "") return here
220
+ if (candidate === "." || candidate === "") {
221
+ return here
222
+ }
166
223
  return joinPath(here, candidate)
167
224
  }
168
225
  return candidate
@@ -172,15 +229,23 @@ export fn cliRoot() {
172
229
  export fn repoRoot() {
173
230
  let cli = cliRoot()
174
231
  let parent = dirname(cli)
175
- if (looksLikeRepoRoot(parent)) return parent
232
+ if (looksLikeRepoRoot(parent)) {
233
+ return parent
234
+ }
176
235
  let here = cwd()
177
- if (looksLikeRepoRoot(here)) return here
236
+ if (looksLikeRepoRoot(here)) {
237
+ return here
238
+ }
178
239
  let walk = here
179
240
  let n = 0
180
241
  while (n < 8) {
181
- if (looksLikeRepoRoot(walk)) return walk
242
+ if (looksLikeRepoRoot(walk)) {
243
+ return walk
244
+ }
182
245
  let parent2 = dirname(walk)
183
- if (parent2 === walk) break
246
+ if (parent2 === walk) {
247
+ break
248
+ }
184
249
  walk = parent2
185
250
  n = n + 1
186
251
  }
@@ -191,21 +256,31 @@ export fn resolveTish() {
191
256
  // Prefer explicit override, then sibling monorepo debug build (has --platform / resolve-id).
192
257
  if (env !== null) {
193
258
  let custom = env["TISH_PATH"]
194
- if (custom !== null && custom !== "" && fileExists(String(custom))) return String(custom)
259
+ if (custom !== null && custom !== "" && fileExists(String(custom))) {
260
+ return String(custom)
261
+ }
195
262
  }
196
263
  let root = repoRoot()
197
264
  let localDebug = joinPath(root, "../tish/target/debug/tish")
198
- if (fileExists(localDebug)) return localDebug
265
+ if (fileExists(localDebug)) {
266
+ return localDebug
267
+ }
199
268
  let localRelease = joinPath(root, "../tish/target/release/tish")
200
- if (fileExists(localRelease)) return localRelease
269
+ if (fileExists(localRelease)) {
270
+ return localRelease
271
+ }
201
272
  let home = ""
202
273
  if (env !== null) {
203
274
  let h = env["HOME"]
204
- if (h !== null && h !== "") home = String(h)
275
+ if (h !== null && h !== "") {
276
+ home = String(h)
277
+ }
205
278
  }
206
279
  if (home !== "") {
207
280
  let cargoTish = home + "/.cargo/bin/tish"
208
- if (fileExists(cargoTish)) return cargoTish
281
+ if (fileExists(cargoTish)) {
282
+ return cargoTish
283
+ }
209
284
  }
210
285
  return "tish"
211
286
  }
@@ -11,9 +11,9 @@ await emitStylesheet({
11
11
  "__ROOT__/packages/ui-theme/src/ui/Badge.tish",
12
12
  "__ROOT__/packages/ui-theme/src/ui/Separator.tish",
13
13
  "__ROOT__/packages/ui-theme/src/ui/ScrollArea.tish",
14
- "__ROOT__/packages/ui-theme/src/ui/Toolbar.tish",
14
+ "__ROOT__/packages/ui-theme/src/ui/Toolbar.tish"
15
15
  ],
16
- outputPath: "public/assets/app.tw.css",
16
+ outputPath: "public/assets/app.tw.css"
17
17
  })
18
18
 
19
19
  mkdir("public/assets", { recursive: true })
@@ -31,12 +31,8 @@ fn App() {
31
31
 
32
32
  {hello !== null ? <Card class="mt-4">
33
33
  <CardHeader>
34
- <h2 class="font-semibold">Response</h2>
35
- </CardHeader>
36
- <CardBody>
37
- <pre class="text-sm whitespace-pre-wrap">{JSON.stringify(hello, null, 2)}</pre>
38
- </CardBody>
39
- </Card> : null}
34
+ <h2 class="font-semibold">Response</h2></CardHeader><CardBody>
35
+ <pre class="text-sm whitespace-pre-wrap">{JSON.stringify(hello, null, 2)}</pre></CardBody></Card> : null}
40
36
  </div>
41
37
  }
42
38
 
@@ -13,15 +13,15 @@ export fn mountApp(rootEl) {
13
13
  rootEl.appendChild(p)
14
14
  let out = document.createElement("pre")
15
15
  let btn = Button({
16
- title: "Hello",
17
- onPress: () => {
18
- invoke("app.hello", { from: "ui" }).then((r) => {
19
- out.textContent = JSON.stringify(r, null, 2)
20
- }, (e) => {
21
- out.textContent = String(e)
22
- })
23
- },
24
- })
16
+ title: "Hello",
17
+ onPress: () => {
18
+ invoke("app.hello", { from: "ui" }).then((r) => {
19
+ out.textContent = JSON.stringify(r, null, 2)
20
+ }, (e) => {
21
+ out.textContent = String(e)
22
+ })
23
+ }
24
+ })
25
25
  rootEl.appendChild(btn)
26
26
  rootEl.appendChild(out)
27
27
  }
@@ -24,11 +24,4 @@ createSurface({
24
24
  titleBarStyle: "transparent"
25
25
  })
26
26
 
27
- run({
28
- plugins: {
29
- dialog: true,
30
- menu: true,
31
- notification: true,
32
- singleInstance: false
33
- }
34
- })
27
+ run({ plugins: { dialog: true, menu: true, notification: true, singleInstance: false } })