@typed-assistant/builder 0.0.62 → 0.0.64

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": "@typed-assistant/builder",
3
- "version": "0.0.62",
3
+ "version": "0.0.64",
4
4
  "exports": {
5
5
  "./appProcess": "./src/appProcess.tsx",
6
6
  "./bunInstall": "./src/bunInstall.tsx",
@@ -25,10 +25,10 @@
25
25
  "home-assistant-js-websocket": "^8.2.0",
26
26
  "ts-toolbelt": "^9.6.0",
27
27
  "typescript": "^5.3.3",
28
- "@typed-assistant/logger": "0.0.17",
29
28
  "@typed-assistant/eslint-config": "0.0.9",
30
- "@typed-assistant/typescript-config": "0.0.9",
31
- "@typed-assistant/utils": "0.0.15"
29
+ "@typed-assistant/logger": "0.0.17",
30
+ "@typed-assistant/utils": "0.0.15",
31
+ "@typed-assistant/typescript-config": "0.0.9"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "home-assistant-js-websocket": "^8.2.0"
@@ -2,21 +2,20 @@ import { logger } from "@typed-assistant/logger"
2
2
  import { generateTypes } from "@typed-assistant/types/generateTypes"
3
3
  import type { Subprocess } from "bun"
4
4
  import { $ } from "bun"
5
+ import debounce from "debounce"
5
6
  import { readFileSync, watch } from "fs"
6
7
  import ignore from "ignore"
7
8
  import { join, relative } from "path"
9
+ import { getAddonInfo as getAddonInfoAPI } from "./getAddonInfo"
8
10
  import {
9
11
  addKillListener,
10
12
  callKillListeners,
11
13
  callSoftKillListeners,
12
14
  killSubprocess,
13
15
  } from "./killProcess"
16
+ import { restartAddon } from "./restartAddon"
14
17
  import { setupGitPoller } from "./setupGitPoller"
15
- import { setupWebhook } from "./setupWebhook"
16
18
  import { startWebappServer } from "./setupWebserver"
17
- import { restartAddon } from "./restartAddon"
18
- import { getAddonInfo as getAddonInfoAPI } from "./getAddonInfo"
19
- import debounce from "debounce"
20
19
 
21
20
  export async function setup({
22
21
  entryFile,
@@ -31,7 +30,6 @@ export async function setup({
31
30
  const slug = addonInfo?.data.slug ?? ""
32
31
  const directoryToWatch = join(process.cwd(), "./src")
33
32
  const addonUrl = `${slug}/ingress`
34
- const webhookUrl = `${process.env.HASS_EXTERNAL_URL}${basePath}/webhook`
35
33
 
36
34
  let subprocesses = await buildAndStartAppProcess(entryFile, {
37
35
  mdiPaths: mdiPaths,
@@ -76,7 +74,7 @@ export async function setup({
76
74
  )
77
75
  },
78
76
  })
79
- await setupGitSync(webhookUrl)
77
+ await setupGitSync()
80
78
 
81
79
  return subprocesses
82
80
  }
@@ -166,7 +164,7 @@ const getAddonInfo = async () => {
166
164
  return data
167
165
  }
168
166
 
169
- const setupGitSync = async (webhookUrl: string) => {
167
+ const setupGitSync = async () => {
170
168
  if (
171
169
  !process.env.GITHUB_TOKEN ||
172
170
  !process.env.GITHUB_USERNAME ||
@@ -178,14 +176,8 @@ const setupGitSync = async (webhookUrl: string) => {
178
176
  )
179
177
  return { error: {} }
180
178
  }
181
- if (process.env.HASS_EXTERNAL_URL) {
182
- await setupWebhook(webhookUrl)
183
- return
184
- }
185
- logger.warn(
186
- { emoji: "⚠️" },
187
- "No HASS_EXTERNAL_URL found. Setting up git poller...",
188
- )
179
+
180
+ logger.warn({ emoji: "⬇️" }, "Setting up git poller...")
189
181
  await setupGitPoller()
190
182
  }
191
183
 
@@ -92,13 +92,13 @@ const getStats = async () => {
92
92
  ? data.data.memory_usage
93
93
  : stats.max_memory_usage,
94
94
  }
95
- logger.info(
95
+ logger.debug(
96
96
  { additionalDetails: JSON.stringify(stats, null, 2), emoji: "📊" },
97
97
  "Stats updated",
98
98
  )
99
99
  }
100
100
 
101
- setTimeout(getStats, 30 * ONE_SECOND)
101
+ setTimeout(getStats, 10 * ONE_SECOND)
102
102
  }
103
103
 
104
104
  export const startWebappServer = async ({
@@ -164,8 +164,22 @@ export const startWebappServer = async ({
164
164
  return { message: "Restarting addon..." }
165
165
  })
166
166
  .get("/force-sync-with-github", async () => {
167
- const { exitCode, stdout, stderr } =
167
+ const { exitCode, stderr } =
168
168
  await $`git reset --hard origin/${process.env.GITHUB_BRANCH}`.quiet()
169
+ if (exitCode) {
170
+ logger.error(
171
+ {
172
+ additionalDetails: stderr.toString().trim(),
173
+ emoji: "🔄🚨",
174
+ },
175
+ "Failed to reset to origin",
176
+ )
177
+ return {
178
+ message: "Failed to reset to origin",
179
+ }
180
+ }
181
+ logger.info({ emoji: "🔄" }, "Reset to origin")
182
+ return { message: "Reset to origin" }
169
183
  })
170
184
  .get(
171
185
  "/webhook",
@@ -1,11 +1,6 @@
1
- import { Terminal } from "./Terminal"
2
1
  import { Logs } from "./Logs"
3
- import { useEffect, useState } from "react"
4
- import { app } from "./api"
5
- import { Await } from "ts-toolbelt/out/Any/Await"
6
- import { AppSection } from "./AppSection"
7
- import { set } from "zod"
8
- import { ONE_SECOND } from "@typed-assistant/utils/durations"
2
+ import { Stats } from "./Stats"
3
+ import { Terminal } from "./Terminal"
9
4
 
10
5
  const basePath = process.env.BASE_PATH ?? ""
11
6
 
@@ -23,75 +18,4 @@ const App = () => {
23
18
  )
24
19
  }
25
20
 
26
- const Stats = () => {
27
- const [counter, setCounter] = useState(0)
28
- const [error, setError] = useState<string | null>(null)
29
- const [lastUpdated, setLastUpdated] = useState<number | null>(null)
30
- const [stats, setStats] =
31
- useState<Awaited<ReturnType<typeof app.stats.get>>["data"]>(null)
32
-
33
- useEffect(() => {
34
- app.stats.get().then((stats) => {
35
- setLastUpdated(Date.now())
36
- if (stats.error) {
37
- setError(stats.error.message)
38
- return
39
- }
40
- setStats(stats.data)
41
-
42
- const timeout = setTimeout(() => {
43
- setCounter((c) => c + 1)
44
- }, 30 * ONE_SECOND)
45
- return () => clearTimeout(timeout)
46
- })
47
- }, [counter])
48
-
49
- return (
50
- <AppSection className="pb-0" fullHeight={false} scrollable={false}>
51
- {error ? (
52
- <>Error: {error}</>
53
- ) : stats ? (
54
- <div
55
- title={`Last updated: ${lastUpdated ? new Date(lastUpdated).toLocaleTimeString() : "Never"}`}
56
- >
57
- <div className="mb-2 text-slate-400">
58
- Last updated:{" "}
59
- {lastUpdated ? new Date(lastUpdated).toLocaleTimeString() : "Never"}
60
- , max memory usage: {bytesToMegaBytes(stats.max_memory_usage)}MB
61
- </div>
62
- <div className="mb-3">
63
- <div className="mb-1">
64
- Memory:{" "}
65
- {stats.memory_usage
66
- ? `${bytesToMegaBytes(stats.memory_usage ?? 0)} / ${bytesToMegaBytes(stats.memory_limit ?? 0)}MB`
67
- : "Loading..."}
68
- </div>
69
- <ProgressBar value={stats.memory_percent ?? 0} />
70
- </div>
71
- <div className="mb-1">
72
- CPU: {stats.cpu_percent ? `${stats.cpu_percent}%` : "Loading..."}
73
- </div>
74
- <ProgressBar value={stats.cpu_percent ?? 0} />
75
- </div>
76
- ) : (
77
- <div>Loading...</div>
78
- )}
79
- </AppSection>
80
- )
81
- }
82
-
83
- const ProgressBar = ({ value }: { value: number }) => {
84
- return (
85
- <div className="relative w-full h-2 bg-slate-800 rounded-md overflow-hidden">
86
- <div
87
- className="absolute h-full bg-slate-600"
88
- style={{ width: `${value}%` }}
89
- ></div>
90
- </div>
91
- )
92
- }
93
-
94
- const bytesToMegaBytes = (bytes: number) =>
95
- Math.round((bytes / 1024 / 1024) * 100) / 100
96
-
97
21
  export default App
@@ -95,9 +95,9 @@ export const Logs = ({ basePath }: { basePath: string }) => {
95
95
  {logs
96
96
  .filter((log) => log.level >= (levels[level] ?? 0))
97
97
  .sort((a, b) => b.time - a.time)
98
- .map((log, index) => {
98
+ .map((log) => {
99
99
  return (
100
- <li key={index + JSON.stringify(log)} className="flex gap-1">
100
+ <li key={JSON.stringify(log)} className="flex gap-1">
101
101
  <span className="text-slate-400 mr-2">
102
102
  {dateTimeVisibility === "hidden"
103
103
  ? null
@@ -0,0 +1,73 @@
1
+ import { useEffect, useState } from "react"
2
+ import { app } from "./api"
3
+ import { AppSection } from "./AppSection"
4
+ import { ONE_SECOND } from "@typed-assistant/utils/durations"
5
+
6
+ export const Stats = () => {
7
+ const [counter, setCounter] = useState(0)
8
+ const [error, setError] = useState<string | null>(null)
9
+ const [lastUpdated, setLastUpdated] = useState<number | null>(null)
10
+ const [stats, setStats] =
11
+ useState<Awaited<ReturnType<typeof app.stats.get>>["data"]>(null)
12
+
13
+ useEffect(() => {
14
+ app.stats.get().then((stats) => {
15
+ setLastUpdated(Date.now())
16
+ if (stats.error) {
17
+ setError(stats.error.message)
18
+ return
19
+ }
20
+ setStats(stats.data)
21
+
22
+ const timeout = setTimeout(() => {
23
+ setCounter((c) => c + 1)
24
+ }, 10 * ONE_SECOND)
25
+ return () => clearTimeout(timeout)
26
+ })
27
+ }, [counter])
28
+
29
+ return (
30
+ <AppSection className="pb-0" fullHeight={false} scrollable={false}>
31
+ {error ? (
32
+ <>Error: {error}</>
33
+ ) : stats ? (
34
+ <>
35
+ <div className="mb-3">
36
+ <div className="mb-1">
37
+ Memory:{" "}
38
+ {stats.memory_usage
39
+ ? `${bytesToMegaBytes(stats.memory_usage ?? 0)} / ${bytesToMegaBytes(stats.memory_limit ?? 0)}MB`
40
+ : "Loading..."}
41
+ </div>
42
+ <ProgressBar value={stats.memory_percent ?? 0} />
43
+ </div>
44
+ <div className="mb-3">
45
+ <div className="mb-1">
46
+ CPU: {stats.cpu_percent ? `${stats.cpu_percent}%` : "Loading..."}
47
+ </div>
48
+ <ProgressBar value={stats.cpu_percent ?? 0} />
49
+ </div>
50
+ <div className=" text-slate-400">
51
+ Max memory usage: {bytesToMegaBytes(stats.max_memory_usage)}MB. Last
52
+ updated:{" "}
53
+ {lastUpdated ? new Date(lastUpdated).toLocaleTimeString() : "Never"}
54
+ </div>
55
+ </>
56
+ ) : (
57
+ <div>Loading...</div>
58
+ )}
59
+ </AppSection>
60
+ )
61
+ }
62
+ const ProgressBar = ({ value }: { value: number }) => {
63
+ return (
64
+ <div className="relative w-full h-2 bg-slate-800 rounded-md overflow-hidden">
65
+ <div
66
+ className="absolute h-full bg-slate-600"
67
+ style={{ width: `${value}%` }}
68
+ ></div>
69
+ </div>
70
+ )
71
+ }
72
+ const bytesToMegaBytes = (bytes: number) =>
73
+ Math.round((bytes / 1024 / 1024) * 100) / 100
@@ -84,6 +84,14 @@ export function Terminal() {
84
84
  TypedAssistant <WSIndicator ws={ws.ws} />
85
85
  </h1>
86
86
  <div className="flex flex-wrap gap-2">
87
+ <ButtonAsync
88
+ onClick={() => app["force-sync-with-github"].get()}
89
+ stateLabels={{
90
+ idle: "Force sync with remote",
91
+ loading: "Syncing...",
92
+ success: "Successfully synced with remote",
93
+ }}
94
+ />
87
95
  <ButtonAsync
88
96
  onClick={() => app["restart-app"].get()}
89
97
  stateLabels={{