diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 00000000..0a7bb422 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,123 @@ +# Ultracite Code Standards + +This project uses **Ultracite**, a zero-config preset that enforces strict code quality standards through automated formatting and linting. + +## Quick Reference + +- **Format code**: `bun x ultracite fix` +- **Check for issues**: `bun x ultracite check` +- **Diagnose setup**: `bun x ultracite doctor` + +Biome (the underlying engine) provides robust linting and formatting. Most issues are automatically fixable. + +--- + +## Core Principles + +Write code that is **accessible, performant, type-safe, and maintainable**. Focus on clarity and explicit intent over brevity. + +### Type Safety & Explicitness + +- Use explicit types for function parameters and return values when they enhance clarity +- Prefer `unknown` over `any` when the type is genuinely unknown +- Use const assertions (`as const`) for immutable values and literal types +- Leverage TypeScript's type narrowing instead of type assertions +- Use meaningful variable names instead of magic numbers - extract constants with descriptive names + +### Modern JavaScript/TypeScript + +- Use arrow functions for callbacks and short functions +- Prefer `for...of` loops over `.forEach()` and indexed `for` loops +- Use optional chaining (`?.`) and nullish coalescing (`??`) for safer property access +- Prefer template literals over string concatenation +- Use destructuring for object and array assignments +- Use `const` by default, `let` only when reassignment is needed, never `var` + +### Async & Promises + +- Always `await` promises in async functions - don't forget to use the return value +- Use `async/await` syntax instead of promise chains for better readability +- Handle errors appropriately in async code with try-catch blocks +- Don't use async functions as Promise executors + +### React & JSX + +- Use function components over class components +- Call hooks at the top level only, never conditionally +- Specify all dependencies in hook dependency arrays correctly +- Use the `key` prop for elements in iterables (prefer unique IDs over array indices) +- Nest children between opening and closing tags instead of passing as props +- Don't define components inside other components +- Use semantic HTML and ARIA attributes for accessibility: + - Provide meaningful alt text for images + - Use proper heading hierarchy + - Add labels for form inputs + - Include keyboard event handlers alongside mouse events + - Use semantic elements (` - - @@ -294,14 +328,18 @@ export default function GatewayPage() { {selectedProject ? (
- Project: {selectedProject.project_name} + Project:{" "} + + {selectedProject.project_name} +
) : null} {error ?
{error}
: null}

- Browser WebSocket clients cannot set headers, so the token is sent in the WS query - string. Treat URLs as sensitive and avoid sharing screenshots. + Browser WebSocket clients cannot set headers, so the token is sent + in the WS query string. Treat URLs as sensitive and avoid sharing + screenshots.

@@ -311,28 +349,28 @@ export default function GatewayPage() { - ) + ); } function buildWebSocketUrl(opts: { - baseUrl: string - projectId: string - shellId: string - token: string + baseUrl: string; + projectId: string; + shellId: string; + token: string; }): string { - const base = new URL(opts.baseUrl) - base.protocol = base.protocol === "https:" ? "wss:" : "ws:" - base.pathname = `/control-plane/projects/${opts.projectId}/shells/${opts.shellId}/stream` - base.searchParams.set("token", opts.token) - return base.toString() + const base = new URL(opts.baseUrl); + base.protocol = base.protocol === "https:" ? "wss:" : "ws:"; + base.pathname = `/control-plane/projects/${opts.projectId}/shells/${opts.shellId}/stream`; + base.searchParams.set("token", opts.token); + return base.toString(); } async function callGateway(opts: { - baseUrl: string - token: string - path: string - method: string - body?: unknown + baseUrl: string; + token: string; + path: string; + method: string; + body?: unknown; }): Promise> { try { const response = await fetch("/api/gateway", { @@ -343,62 +381,67 @@ async function callGateway(opts: { token: opts.token, path: opts.path, method: opts.method, - ...(opts.body !== undefined ? { body: opts.body } : {}) - }) - }) - const text = await response.text() - const data = parseJson({ value: text }) + ...(opts.body !== undefined ? { body: opts.body } : {}), + }), + }); + const text = await response.text(); + const data = parseJson({ value: text }); if (!response.ok) { const error = (isRecord(data) && typeof data.error === "string" && data.error) || - `HTTP ${response.status}` - return { ok: false, error } + `HTTP ${response.status}`; + return { ok: false, error }; } - return { ok: true, data: data as T } + return { ok: true, data: data as T }; } catch (err) { - return { ok: false, error: err instanceof Error ? err.message : "request_failed" } + return { + ok: false, + error: err instanceof Error ? err.message : "request_failed", + }; } } type ParsedMessage = | { type: "output"; data: string } | { type: "exit"; exitCode: number | null } - | { type: "text"; data: string } + | { type: "text"; data: string }; function parseMessage(opts: { data: string }): ParsedMessage { - const raw = parseJson({ value: opts.data }) - if (!isRecord(raw)) return { type: "text", data: opts.data } + const raw = parseJson({ value: opts.data }); + if (!isRecord(raw)) { + return { type: "text", data: opts.data }; + } if (raw.type === "output" && typeof raw.data === "string") { - return { type: "output", data: raw.data } + return { type: "output", data: raw.data }; } if (raw.type === "exit") { - const exitCode = typeof raw.exitCode === "number" ? raw.exitCode : null - return { type: "exit", exitCode } + const exitCode = typeof raw.exitCode === "number" ? raw.exitCode : null; + return { type: "exit", exitCode }; } - return { type: "text", data: opts.data } + return { type: "text", data: opts.data }; } function parseJson(opts: { value: string }): unknown { try { - return opts.value ? JSON.parse(opts.value) : null + return opts.value ? JSON.parse(opts.value) : null; } catch { - return null + return null; } } function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null + return typeof value === "object" && value !== null; } function formatGatewayError(opts: { error: string }): string { if (opts.error === "writes_disabled") { - return "writes_disabled: enable allowWrites and restart hackd." + return "writes_disabled: enable allowWrites and restart hackd."; } if (opts.error === "write_scope_required") { - return "write_scope_required: create a write-scoped token." + return "write_scope_required: create a write-scoped token."; } if (opts.error === "missing_token") { - return "missing_token: paste a gateway token." + return "missing_token: paste a gateway token."; } - return opts.error + return opts.error; } diff --git a/examples/next-app/app/page.tsx b/examples/next-app/app/page.tsx index 295f8fdf..7c97587a 100644 --- a/examples/next-app/app/page.tsx +++ b/examples/next-app/app/page.tsx @@ -3,58 +3,58 @@ import Image from "next/image"; export default function Home() { return (
-
+
Next.js logo
-

+

To get started, edit the page.tsx file.

-

+

Looking for a starting point or more instructions? Head over to{" "} Templates {" "} or the{" "} Learning {" "} center.

-
+
Vercel logomark Deploy Now Documentation diff --git a/examples/next-app/next.config.ts b/examples/next-app/next.config.ts index 73173013..b49c82ce 100644 --- a/examples/next-app/next.config.ts +++ b/examples/next-app/next.config.ts @@ -1,14 +1,14 @@ -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from "node:path"; +import { fileURLToPath } from "node:url"; -import type { NextConfig } from "next" +import type { NextConfig } from "next"; -const rootDir = dirname(fileURLToPath(import.meta.url)) +const rootDir = dirname(fileURLToPath(import.meta.url)); const nextConfig: NextConfig = { turbopack: { - root: rootDir - } -} + root: rootDir, + }, +}; -export default nextConfig +export default nextConfig; diff --git a/examples/next-app/scripts/ops.ts b/examples/next-app/scripts/ops.ts index 1cc4cb96..29221fac 100644 --- a/examples/next-app/scripts/ops.ts +++ b/examples/next-app/scripts/ops.ts @@ -1,50 +1,52 @@ -import { spawn } from "node:child_process" +import { spawn } from "node:child_process"; /** - * + * * Ops script for running commands in the ops container. - * + * * Usage: * bun run ops --command * bun run ops -- * Examples: * bun run ops --command bun run db:push * bun run ops -- bun scripts/generate-something.ts - * + * */ -const args = process.argv.slice(2) +const args = process.argv.slice(2); const extractCommand = (input: string[]) => { if (input.includes("--help") || input.includes("-h")) { - return { command: null } + return { command: null }; } - const flagIndex = input.findIndex(item => item === "--command" || item === "-c") + const flagIndex = input.findIndex( + (item) => item === "--command" || item === "-c" + ); if (flagIndex >= 0) { - return { command: input.slice(flagIndex + 1) } + return { command: input.slice(flagIndex + 1) }; } - const flagValue = input.find(item => item.startsWith("--command=")) + const flagValue = input.find((item) => item.startsWith("--command=")); if (flagValue) { - const value = flagValue.slice("--command=".length) - return { command: value ? [value] : [] } + const value = flagValue.slice("--command=".length); + return { command: value ? [value] : [] }; } - const doubleDashIndex = input.indexOf("--") + const doubleDashIndex = input.indexOf("--"); if (doubleDashIndex >= 0) { - return { command: input.slice(doubleDashIndex + 1) } + return { command: input.slice(doubleDashIndex + 1) }; } - return { command: input.length > 0 ? input : null } -} + return { command: input.length > 0 ? input : null }; +}; -const { command } = extractCommand(args) +const { command } = extractCommand(args); if (!command || command.length === 0) { - process.exit(1) + process.exit(1); } -const commandString = command.join(" ") +const commandString = command.join(" "); const dockerArgs = [ "compose", "-f", @@ -56,17 +58,16 @@ const dockerArgs = [ "db-ops", "sh", "-lc", - `cd /app && ${commandString}` -] - + `cd /app && ${commandString}`, +]; -const child = spawn("docker", dockerArgs, { stdio: "inherit" }) +const child = spawn("docker", dockerArgs, { stdio: "inherit" }); -child.once("exit", code => { - process.exit(code ?? 0) -}) +child.once("exit", (code) => { + process.exit(code ?? 0); +}); -child.once("error", err => { - console.error(err) - process.exit(1) -}) +child.once("error", (err) => { + console.error(err); + process.exit(1); +}); diff --git a/index.ts b/index.ts index 884726c3..b8c87368 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { runCli } from "./src/cli/run.ts" +import { runCli } from "./src/cli/run.ts"; -const exitCode = await runCli(Bun.argv.slice(2)) -process.exitCode = exitCode +const exitCode = await runCli(Bun.argv.slice(2)); +process.exitCode = exitCode; diff --git a/orbstack-crash.txt b/orbstack-crash.txt deleted file mode 100644 index 856390cf..00000000 --- a/orbstack-crash.txt +++ /dev/null @@ -1,1982 +0,0 @@ -🌲 vmgr | time="01-13 19:18:32" level=info msg="using proxy: none" -🌲 vmgr | time="01-13 19:18:32" level=info msg="forwarding SSH agent" sock="/Users/hack/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" -🌲 vmgr | time="01-13 19:18:32" level=info msg="starting VM" -🌲 vmgr | time="01-13 19:18:32" level=info msg="starting host services" -🌲 vmgr | time="01-13 19:18:32" level=info msg="reading user environment variables" -🐧 system | [*] Booting OrbStack (+0ms) -🐧 system | - Kernel version: 6.17.8-orbstack-00308-g8f9c941121b1 -🐧 system | [*] Network (+4ms) -🐧 system | [*] Apply system settings (+2ms) -🐧 system | [*] Late tasks (+0ms) -🐧 system | [*] Emulation -🐧 system | [*] Memory -🐧 system | [*] Data -👾 kernel | [ 0.372648] BTRFS: device label user-data-fs devid 1 transid 287770 /dev/vdb1 (254:17) scanned by vinit (246) -🐧 system | - Using Rosetta -👾 kernel | [ 0.373075] BTRFS info (device vdb1): first mount of filesystem ed0232ec-8756-4100-9df1-6a6f9da3947a -👾 kernel | [ 0.373112] BTRFS info (device vdb1): using crc32c (crc32c-lib) checksum algorithm -👾 kernel | [ 0.375472] BTRFS info (device vdb1): start tree-log replay -👾 kernel | [ 0.388384] zram0: detected capacity change from 0 to 32829312 -👾 kernel | [ 0.433860] Adding 16414652k swap on /dev/zram0. Priority:32767 extents:1 across:16414652k SSDsc -👾 kernel | [ 0.435040] Adding 1048572k swap on /dev/vdc. Priority:1 extents:1 across:1048572k Dsc -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 8000 }" error="connect tcp 0.250.250.2:8000: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 8000 }" error="connect tcp 0.250.250.2:8000: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 8000 }" error="connect tcp 0.250.250.2:8000: connection was refused" -👾 kernel | [ 0.996537] BTRFS info (device vdb1): checking UUID tree -👾 kernel | [ 0.996705] BTRFS info (device vdb1): setting nodatasum -👾 kernel | [ 0.996727] BTRFS info (device vdb1): setting nodatacow -👾 kernel | [ 0.996737] BTRFS info (device vdb1): enabling ssd optimizations -👾 kernel | [ 0.996749] BTRFS info (device vdb1): turning on sync discard -👾 kernel | [ 0.996780] BTRFS info (device vdb1): enabling free space tree -🐧 system | [*] Initialize data (+625ms) -🐧 system | [*] Start services (+0ms) -🐧 system | [*] Done! (+1ms) -🐧 system | - Total boot time: 633ms -👾 kernel | [ 1.007715] udevd[269]: starting version 3.2.14 -👾 kernel | [ 1.010233] udevd[269]: starting eudev-3.2.14 -📦 scon | time="01-14 00:18:33" level=info msg=starting -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 2375 }" error="connect tcp 0.250.250.2:2375: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 2375 }" error="connect tcp 0.250.250.2:2375: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 2375 }" error="connect tcp 0.250.250.2:2375: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 2375 }" error="connect tcp 0.250.250.2:2375: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 2375 }" error="connect tcp 0.250.250.2:2375: connection was refused" -🌲 vmgr | time="01-13 19:18:33" level=error msg="host-unix forward: dial failed" addr="{1 0.250.250.2 2375 }" error="connect tcp 0.250.250.2:2375: connection was refused" -👾 kernel | [ 1.501623] conbr0: port 1(eth1) entered blocking state -👾 kernel | [ 1.501662] conbr0: port 1(eth1) entered disabled state -👾 kernel | [ 1.501684] virtio_net virtio9 eth1: entered allmulticast mode -👾 kernel | [ 1.501739] virtio_net virtio9 eth1: entered promiscuous mode -👾 kernel | [ 1.501827] conbr0: port 1(eth1) entered blocking state -👾 kernel | [ 1.501844] conbr0: port 1(eth1) entered forwarding state -📦 scon | time="01-14 00:18:34" level=info msg=started -🌲 vmgr | time="01-13 19:18:34" level=info msg="service is ready" service=sconrpc -🌲 vmgr | time="01-13 19:18:34" level=info msg="service is ready" service=krpc -🌲 vmgr | time="01-13 19:18:34" level=info msg="service is ready" service=sconrpc-internal -📦 scon | time="01-14 00:18:34" level=info msg="starting container" container=docker -👾 kernel | [ 1.794505] conbr0: port 2(vethsDm5Bg) entered blocking state -👾 kernel | [ 1.794536] conbr0: port 2(vethsDm5Bg) entered disabled state -👾 kernel | [ 1.794559] vethsDm5Bg: entered allmulticast mode -👾 kernel | [ 1.794601] vethsDm5Bg: entered promiscuous mode -👾 kernel | [ 1.794680] conbr0: port 2(vethsDm5Bg) entered blocking state -👾 kernel | [ 1.794701] conbr0: port 2(vethsDm5Bg) entered forwarding state -👾 kernel | [ 1.802701] conbr0: port 2(vethsDm5Bg) entered disabled state -👾 kernel | [ 1.803281] eth0: renamed from vethP0NPwy -👾 kernel | [ 1.803494] conbr0: port 2(vethsDm5Bg) entered blocking state -👾 kernel | [ 1.803514] conbr0: port 2(vethsDm5Bg) entered forwarding state -📦 scon | time="01-14 00:18:34" level=info msg="container started" container=docker -🌲 vmgr | time="01-13 19:18:34" level=info msg="setup done" -👾 kernel | [ 2.549406] NFSD: Using /var/lib/nfs/v4recovery as the NFSv4 state recovery directory -👾 kernel | [ 2.549447] NFSD: Using legacy client tracking operations. -👾 kernel | [ 2.549457] NFSD: starting 1-second grace period (net effffff9) -🌲 vmgr | time="01-13 19:18:35" level=info msg="service is ready" service=nfs -🌲 vmgr | time="01-13 19:18:35" level=info msg="Mounting NFS..." -🌲 vmgr | time="01-13 19:18:35" level=info msg="NFS mounted" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:6379" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:127.0.0.1:3100" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:80" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:443" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:[::]:6379" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:[::]:80" -📦 scon | time="01-14 00:18:37" level=info msg="add forward" container=docker spec="tcp:[::]:443" -📦 scon | time="01-14 00:18:37" level=info msg="remove forward" key="tcp:0.0.0.0:80" -📦 scon | time="01-14 00:18:37" level=info msg="remove forward" key="tcp:0.0.0.0:443" -📦 scon | time="01-14 00:18:37" level=info msg="remove forward" key="tcp:[::]:80" -📦 scon | time="01-14 00:18:37" level=info msg="remove forward" key="tcp:[::]:443" -📦 scon | time="01-14 00:18:37" level=info msg="remove forward" key="tcp:127.0.0.1:3100" -📦 scon | time="01-14 00:18:39" level=info msg="remove forward" key="tcp:0.0.0.0:6379" -📦 scon | time="01-14 00:18:39" level=info msg="remove forward" key="tcp:[::]:6379" -👾 kernel | [ 8.422629] br-dd826a8a89a2: port 1(veth8044859) entered blocking state -👾 kernel | [ 8.422669] br-dd826a8a89a2: port 1(veth8044859) entered disabled state -👾 kernel | [ 8.422692] veth8044859: entered allmulticast mode -👾 kernel | [ 8.422736] veth8044859: entered promiscuous mode -👾 kernel | [ 8.855478] eth0: renamed from vethe6aa877 -👾 kernel | [ 8.856166] br-dd826a8a89a2: port 1(veth8044859) entered blocking state -👾 kernel | [ 8.856192] br-dd826a8a89a2: port 1(veth8044859) entered forwarding state -📦 scon | time="01-14 00:18:41" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:6379" -📦 scon | time="01-14 00:18:41" level=info msg="add forward" container=docker spec="tcp:[::]:6379" -🌸 agent:docker | time="01-13 19:18:42" level=info msg="adding network" config="{192.168.117.0/24 192.168.117.1 invalid Prefix invalid IP br-dd826a8a89a2}" name=mhof_default -📦 scon | time="01-14 00:18:45" level=info msg="remove forward" key="tcp:0.0.0.0:6379" -📦 scon | time="01-14 00:18:45" level=info msg="remove forward" key="tcp:[::]:6379" -👾 kernel | [ 12.653205] br-dd826a8a89a2: port 1(veth8044859) entered disabled state -👾 kernel | [ 12.653310] vethe6aa877: renamed from eth0 -👾 kernel | [ 12.849555] br-dd826a8a89a2: port 1(veth8044859) entered disabled state -👾 kernel | [ 12.850046] veth8044859 (unregistering): left allmulticast mode -👾 kernel | [ 12.850087] veth8044859 (unregistering): left promiscuous mode -👾 kernel | [ 12.850109] br-dd826a8a89a2: port 1(veth8044859) entered disabled state -🌸 agent:docker | time="01-13 19:18:45" level=info msg="removing network" config="{192.168.117.0/24 192.168.117.1 invalid Prefix invalid IP br-dd826a8a89a2}" name=mhof_default -👾 kernel | [ 720.512745] br-d1f3e4394e37: port 1(vethbf00bbc) entered blocking state -👾 kernel | [ 720.512810] br-d1f3e4394e37: port 1(vethbf00bbc) entered disabled state -👾 kernel | [ 720.512836] vethbf00bbc: entered allmulticast mode -👾 kernel | [ 720.512891] vethbf00bbc: entered promiscuous mode -👾 kernel | [ 720.679561] br-d1f3e4394e37: port 2(vetha5437e0) entered blocking state -👾 kernel | [ 720.679625] br-d1f3e4394e37: port 2(vetha5437e0) entered disabled state -👾 kernel | [ 720.679648] vetha5437e0: entered allmulticast mode -👾 kernel | [ 720.679739] vetha5437e0: entered promiscuous mode -👾 kernel | [ 720.690042] eth0: renamed from veth25a009b -👾 kernel | [ 720.693550] br-d1f3e4394e37: port 1(vethbf00bbc) entered blocking state -👾 kernel | [ 720.693605] br-d1f3e4394e37: port 1(vethbf00bbc) entered forwarding state -📦 scon | time="01-14 00:30:33" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:80" -📦 scon | time="01-14 00:30:33" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:443" -📦 scon | time="01-14 00:30:33" level=info msg="add forward" container=docker spec="tcp:[::]:80" -📦 scon | time="01-14 00:30:33" level=info msg="add forward" container=docker spec="tcp:[::]:443" -👾 kernel | [ 720.840069] eth0: renamed from vethfbbe920 -👾 kernel | [ 720.840437] br-d1f3e4394e37: port 2(vetha5437e0) entered blocking state -👾 kernel | [ 720.840469] br-d1f3e4394e37: port 2(vetha5437e0) entered forwarding state -🌸 agent:docker | time="01-13 19:30:33" level=info msg="adding network" config="{172.30.0.0/16 172.30.0.1 invalid Prefix invalid IP br-d1f3e4394e37}" name=hack-dev -👾 kernel | [ 721.909146] br-d1f3e4394e37: port 3(vethc584c67) entered blocking state -👾 kernel | [ 721.909202] br-d1f3e4394e37: port 3(vethc584c67) entered disabled state -👾 kernel | [ 721.909245] vethc584c67: entered allmulticast mode -👾 kernel | [ 721.909301] vethc584c67: entered promiscuous mode -👾 kernel | [ 722.138685] br-19a9aee95308: port 1(vethaf05506) entered blocking state -👾 kernel | [ 722.138725] br-19a9aee95308: port 1(vethaf05506) entered disabled state -👾 kernel | [ 722.138750] vethaf05506: entered allmulticast mode -👾 kernel | [ 722.138806] vethaf05506: entered promiscuous mode -👾 kernel | [ 722.139008] br-d1f3e4394e37: port 4(vetha66c566) entered blocking state -👾 kernel | [ 722.139029] br-d1f3e4394e37: port 4(vetha66c566) entered disabled state -👾 kernel | [ 722.139049] vetha66c566: entered allmulticast mode -👾 kernel | [ 722.139089] vetha66c566: entered promiscuous mode -👾 kernel | [ 722.152152] eth0: renamed from veth28fab53 -👾 kernel | [ 722.152732] br-d1f3e4394e37: port 3(vethc584c67) entered blocking state -👾 kernel | [ 722.152769] br-d1f3e4394e37: port 3(vethc584c67) entered forwarding state -👾 kernel | [ 722.354075] eth0: renamed from veth1a5cd12 -👾 kernel | [ 722.354902] br-d1f3e4394e37: port 4(vetha66c566) entered blocking state -👾 kernel | [ 722.354930] br-d1f3e4394e37: port 4(vetha66c566) entered forwarding state -📦 scon | time="01-14 00:30:34" level=info msg="add forward" container=docker spec="tcp:127.0.0.1:3100" -👾 kernel | [ 722.403849] eth0: renamed from veth8bde839 -👾 kernel | [ 722.404723] br-19a9aee95308: port 1(vethaf05506) entered blocking state -👾 kernel | [ 722.404767] br-19a9aee95308: port 1(vethaf05506) entered forwarding state -🌸 agent:docker | time="01-13 19:30:35" level=info msg="adding network" config="{192.168.164.0/24 192.168.164.1 invalid Prefix invalid IP br-19a9aee95308}" name=hack-logging -👾 kernel | [ 722.513969] br-19a9aee95308: port 2(veth5066e75) entered blocking state -👾 kernel | [ 722.514077] br-19a9aee95308: port 2(veth5066e75) entered disabled state -👾 kernel | [ 722.514113] veth5066e75: entered allmulticast mode -👾 kernel | [ 722.514386] veth5066e75: entered promiscuous mode -👾 kernel | [ 722.832602] eth1: renamed from veth3e6a9f8 -👾 kernel | [ 722.833241] br-19a9aee95308: port 2(veth5066e75) entered blocking state -👾 kernel | [ 722.833261] br-19a9aee95308: port 2(veth5066e75) entered forwarding state -👾 kernel | [ 722.842651] br-19a9aee95308: port 3(veth44a937b) entered blocking state -👾 kernel | [ 722.842683] br-19a9aee95308: port 3(veth44a937b) entered disabled state -👾 kernel | [ 722.842729] veth44a937b: entered allmulticast mode -👾 kernel | [ 722.842775] veth44a937b: entered promiscuous mode -👾 kernel | [ 722.927308] eth1: renamed from vethf48efc7 -👾 kernel | [ 722.928100] br-19a9aee95308: port 3(veth44a937b) entered blocking state -👾 kernel | [ 722.928138] br-19a9aee95308: port 3(veth44a937b) entered forwarding state -👾 kernel | [ 729.072933] br-2ea4b26a6c58: port 1(veth787da21) entered blocking state -👾 kernel | [ 729.073018] br-2ea4b26a6c58: port 1(veth787da21) entered disabled state -👾 kernel | [ 729.073045] veth787da21: entered allmulticast mode -👾 kernel | [ 729.073099] veth787da21: entered promiscuous mode -👾 kernel | [ 729.225722] br-2ea4b26a6c58: port 2(vethaea591a) entered blocking state -👾 kernel | [ 729.225753] br-2ea4b26a6c58: port 2(vethaea591a) entered disabled state -👾 kernel | [ 729.225781] vethaea591a: entered allmulticast mode -👾 kernel | [ 729.225835] vethaea591a: entered promiscuous mode -👾 kernel | [ 729.251289] eth0: renamed from veth8b96f21 -👾 kernel | [ 729.252254] br-2ea4b26a6c58: port 1(veth787da21) entered blocking state -👾 kernel | [ 729.252316] br-2ea4b26a6c58: port 1(veth787da21) entered forwarding state -👾 kernel | [ 729.357647] eth0: renamed from veth67f88ae -👾 kernel | [ 729.358443] br-2ea4b26a6c58: port 2(vethaea591a) entered blocking state -👾 kernel | [ 729.358498] br-2ea4b26a6c58: port 2(vethaea591a) entered forwarding state -👾 kernel | [ 729.503417] br-d1f3e4394e37: port 5(veth3302acc) entered blocking state -👾 kernel | [ 729.503448] br-d1f3e4394e37: port 5(veth3302acc) entered disabled state -👾 kernel | [ 729.503469] veth3302acc: entered allmulticast mode -🌸 agent:docker | time="01-13 19:30:42" level=info msg="adding network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-2ea4b26a6c58}" name=event-agent_default -👾 kernel | [ 729.504002] veth3302acc: entered promiscuous mode -👾 kernel | [ 729.544219] eth1: renamed from veth696cbd0 -👾 kernel | [ 729.546531] br-d1f3e4394e37: port 5(veth3302acc) entered blocking state -👾 kernel | [ 729.546564] br-d1f3e4394e37: port 5(veth3302acc) entered forwarding state -👾 kernel | [ 730.614040] br-2ea4b26a6c58: port 3(veth4f5ab28) entered blocking state -👾 kernel | [ 730.614079] br-2ea4b26a6c58: port 3(veth4f5ab28) entered disabled state -👾 kernel | [ 730.614102] veth4f5ab28: entered allmulticast mode -👾 kernel | [ 730.614149] veth4f5ab28: entered promiscuous mode -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -👾 kernel | [ 730.832869] eth0: renamed from veth8161b16 -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -👾 kernel | [ 730.833702] br-2ea4b26a6c58: port 3(veth4f5ab28) entered blocking state -👾 kernel | [ 730.833739] br-2ea4b26a6c58: port 3(veth4f5ab28) entered forwarding state -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.5.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.8.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.2.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 19:30:43" level=error msg="TCP forward [104.16.4.34:443] create endpoint failed: connection was refused" -👾 kernel | [ 731.143477] br-d1f3e4394e37: port 6(veth69d87b7) entered blocking state -👾 kernel | [ 731.143554] br-d1f3e4394e37: port 6(veth69d87b7) entered disabled state -👾 kernel | [ 731.143593] veth69d87b7: entered allmulticast mode -👾 kernel | [ 731.143672] veth69d87b7: entered promiscuous mode -👾 kernel | [ 731.153948] eth1: renamed from vethb7082e2 -👾 kernel | [ 731.155850] br-d1f3e4394e37: port 6(veth69d87b7) entered blocking state -👾 kernel | [ 731.155883] br-d1f3e4394e37: port 6(veth69d87b7) entered forwarding state -👾 kernel | [ 746.177168] veth8161b16: renamed from eth0 -👾 kernel | [ 746.177692] br-2ea4b26a6c58: port 3(veth4f5ab28) entered disabled state -👾 kernel | [ 746.295445] br-2ea4b26a6c58: port 2(vethaea591a) entered disabled state -👾 kernel | [ 746.295730] veth67f88ae: renamed from eth0 -👾 kernel | [ 746.319720] br-2ea4b26a6c58: port 3(veth4f5ab28) entered disabled state -👾 kernel | [ 746.320504] veth4f5ab28 (unregistering): left allmulticast mode -👾 kernel | [ 746.320534] veth4f5ab28 (unregistering): left promiscuous mode -👾 kernel | [ 746.320552] br-2ea4b26a6c58: port 3(veth4f5ab28) entered disabled state -👾 kernel | [ 746.353015] br-2ea4b26a6c58: port 2(vethaea591a) entered disabled state -👾 kernel | [ 746.353314] vethaea591a (unregistering): left allmulticast mode -👾 kernel | [ 746.353341] vethaea591a (unregistering): left promiscuous mode -👾 kernel | [ 746.353388] br-2ea4b26a6c58: port 2(vethaea591a) entered disabled state -👾 kernel | [ 746.408774] br-d1f3e4394e37: port 6(veth69d87b7) entered disabled state -👾 kernel | [ 746.408901] vethb7082e2: renamed from eth1 -👾 kernel | [ 746.442704] br-d1f3e4394e37: port 5(veth3302acc) entered disabled state -👾 kernel | [ 746.443094] veth696cbd0: renamed from eth1 -👾 kernel | [ 746.466878] br-d1f3e4394e37: port 6(veth69d87b7) entered disabled state -👾 kernel | [ 746.469407] veth69d87b7 (unregistering): left allmulticast mode -👾 kernel | [ 746.469434] veth69d87b7 (unregistering): left promiscuous mode -👾 kernel | [ 746.469451] br-d1f3e4394e37: port 6(veth69d87b7) entered disabled state -👾 kernel | [ 746.525862] br-d1f3e4394e37: port 5(veth3302acc) entered disabled state -👾 kernel | [ 746.526786] veth3302acc (unregistering): left allmulticast mode -👾 kernel | [ 746.526810] veth3302acc (unregistering): left promiscuous mode -👾 kernel | [ 746.526825] br-d1f3e4394e37: port 5(veth3302acc) entered disabled state -👾 kernel | [ 747.441427] br-2ea4b26a6c58: port 2(veth332709a) entered blocking state -👾 kernel | [ 747.441470] br-2ea4b26a6c58: port 2(veth332709a) entered disabled state -👾 kernel | [ 747.441514] veth332709a: entered allmulticast mode -👾 kernel | [ 747.441577] veth332709a: entered promiscuous mode -👾 kernel | [ 747.634366] eth0: renamed from vethbb9b49e -👾 kernel | [ 747.635120] br-2ea4b26a6c58: port 2(veth332709a) entered blocking state -👾 kernel | [ 747.635146] br-2ea4b26a6c58: port 2(veth332709a) entered forwarding state -👾 kernel | [ 747.831212] br-d1f3e4394e37: port 5(veth2dc1ce7) entered blocking state -👾 kernel | [ 747.831252] br-d1f3e4394e37: port 5(veth2dc1ce7) entered disabled state -👾 kernel | [ 747.831277] veth2dc1ce7: entered allmulticast mode -👾 kernel | [ 747.831329] veth2dc1ce7: entered promiscuous mode -👾 kernel | [ 747.896241] br-d1f3e4394e37: port 6(veth24ab076) entered blocking state -👾 kernel | [ 747.896287] br-d1f3e4394e37: port 6(veth24ab076) entered disabled state -👾 kernel | [ 747.896353] veth24ab076: entered allmulticast mode -👾 kernel | [ 747.896435] veth24ab076: entered promiscuous mode -👾 kernel | [ 747.910337] eth1: renamed from veth4c79ddb -👾 kernel | [ 747.911115] br-d1f3e4394e37: port 6(veth24ab076) entered blocking state -👾 kernel | [ 747.911140] br-d1f3e4394e37: port 6(veth24ab076) entered forwarding state -👾 kernel | [ 747.911491] eth0: renamed from veth4bf36a0 -👾 kernel | [ 747.912624] br-d1f3e4394e37: port 5(veth2dc1ce7) entered blocking state -👾 kernel | [ 747.912651] br-d1f3e4394e37: port 5(veth2dc1ce7) entered forwarding state -👾 kernel | [ 748.431912] br-2ea4b26a6c58: port 3(veth144a80f) entered blocking state -👾 kernel | [ 748.432017] br-2ea4b26a6c58: port 3(veth144a80f) entered disabled state -👾 kernel | [ 748.432063] veth144a80f: entered allmulticast mode -👾 kernel | [ 748.432130] veth144a80f: entered promiscuous mode -👾 kernel | [ 749.562349] br-2ea4b26a6c58: port 4(vethb3335ac) entered blocking state -👾 kernel | [ 749.562408] br-2ea4b26a6c58: port 4(vethb3335ac) entered disabled state -👾 kernel | [ 749.562469] vethb3335ac: entered allmulticast mode -👾 kernel | [ 749.562529] vethb3335ac: entered promiscuous mode -👾 kernel | [ 749.576464] eth0: renamed from vethb7b15eb -👾 kernel | [ 749.577403] br-2ea4b26a6c58: port 3(veth144a80f) entered blocking state -👾 kernel | [ 749.577433] br-2ea4b26a6c58: port 3(veth144a80f) entered forwarding state -👾 kernel | [ 749.709030] br-2ea4b26a6c58: port 5(vethb1a1722) entered blocking state -👾 kernel | [ 749.709063] br-2ea4b26a6c58: port 5(vethb1a1722) entered disabled state -👾 kernel | [ 749.709083] vethb1a1722: entered allmulticast mode -👾 kernel | [ 749.709135] vethb1a1722: entered promiscuous mode -👾 kernel | [ 749.722402] eth0: renamed from veth8e858fd -👾 kernel | [ 749.723441] br-2ea4b26a6c58: port 4(vethb3335ac) entered blocking state -👾 kernel | [ 749.723482] br-2ea4b26a6c58: port 4(vethb3335ac) entered forwarding state -👾 kernel | [ 749.899672] br-2ea4b26a6c58: port 6(veth3ffccc3) entered blocking state -👾 kernel | [ 749.899703] br-2ea4b26a6c58: port 6(veth3ffccc3) entered disabled state -👾 kernel | [ 749.899721] veth3ffccc3: entered allmulticast mode -👾 kernel | [ 749.899766] veth3ffccc3: entered promiscuous mode -👾 kernel | [ 749.906443] br-d1f3e4394e37: port 7(veth5c821ba) entered blocking state -👾 kernel | [ 749.906479] br-d1f3e4394e37: port 7(veth5c821ba) entered disabled state -👾 kernel | [ 749.906504] veth5c821ba: entered allmulticast mode -👾 kernel | [ 749.906550] veth5c821ba: entered promiscuous mode -👾 kernel | [ 750.188638] eth0: renamed from veth5ff3904 -👾 kernel | [ 750.189709] br-2ea4b26a6c58: port 5(vethb1a1722) entered blocking state -👾 kernel | [ 750.189729] br-2ea4b26a6c58: port 5(vethb1a1722) entered forwarding state -👾 kernel | [ 751.156229] eth1: renamed from vethe7ad240 -👾 kernel | [ 751.160119] br-d1f3e4394e37: port 7(veth5c821ba) entered blocking state -👾 kernel | [ 751.160146] br-d1f3e4394e37: port 7(veth5c821ba) entered forwarding state -👾 kernel | [ 751.161297] br-2ea4b26a6c58: port 7(veth7c49e51) entered blocking state -👾 kernel | [ 751.161321] br-2ea4b26a6c58: port 7(veth7c49e51) entered disabled state -👾 kernel | [ 751.161346] veth7c49e51: entered allmulticast mode -👾 kernel | [ 751.161422] veth7c49e51: entered promiscuous mode -👾 kernel | [ 751.163912] br-d1f3e4394e37: port 8(vetha789816) entered blocking state -👾 kernel | [ 751.163947] br-d1f3e4394e37: port 8(vetha789816) entered disabled state -👾 kernel | [ 751.163965] vetha789816: entered allmulticast mode -👾 kernel | [ 751.164020] vetha789816: entered promiscuous mode -👾 kernel | [ 751.178694] eth0: renamed from veth556c566 -👾 kernel | [ 751.179784] br-2ea4b26a6c58: port 6(veth3ffccc3) entered blocking state -👾 kernel | [ 751.179815] br-2ea4b26a6c58: port 6(veth3ffccc3) entered forwarding state -👾 kernel | [ 752.113299] br-2ea4b26a6c58: port 8(vethf6498c9) entered blocking state -👾 kernel | [ 752.113329] br-2ea4b26a6c58: port 8(vethf6498c9) entered disabled state -👾 kernel | [ 752.113523] vethf6498c9: entered allmulticast mode -👾 kernel | [ 752.113689] vethf6498c9: entered promiscuous mode -👾 kernel | [ 752.113903] eth1: renamed from veth9bf89ce -👾 kernel | [ 752.145154] br-d1f3e4394e37: port 9(veth3d23ff9) entered blocking state -👾 kernel | [ 752.145197] br-d1f3e4394e37: port 9(veth3d23ff9) entered disabled state -👾 kernel | [ 752.145224] veth3d23ff9: entered allmulticast mode -👾 kernel | [ 752.145273] veth3d23ff9: entered promiscuous mode -👾 kernel | [ 752.145532] eth0: renamed from veth9038a6b -👾 kernel | [ 752.155404] br-2ea4b26a6c58: port 7(veth7c49e51) entered blocking state -👾 kernel | [ 752.155438] br-2ea4b26a6c58: port 7(veth7c49e51) entered forwarding state -👾 kernel | [ 752.157465] br-d1f3e4394e37: port 8(vetha789816) entered blocking state -👾 kernel | [ 752.157494] br-d1f3e4394e37: port 8(vetha789816) entered forwarding state -👾 kernel | [ 752.472473] eth1: renamed from vethb868284 -👾 kernel | [ 752.476743] eth1: renamed from vetha9eee09 -👾 kernel | [ 752.478060] br-2ea4b26a6c58: port 8(vethf6498c9) entered blocking state -👾 kernel | [ 752.478090] br-2ea4b26a6c58: port 8(vethf6498c9) entered forwarding state -👾 kernel | [ 752.478339] br-d1f3e4394e37: port 9(veth3d23ff9) entered blocking state -👾 kernel | [ 752.478379] br-d1f3e4394e37: port 9(veth3d23ff9) entered forwarding state -🌸 agent:docker | time="01-13 19:31:05" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 752.478985] br-d1f3e4394e37: port 10(vethb34ecde) entered blocking state -👾 kernel | [ 752.479008] br-d1f3e4394e37: port 10(vethb34ecde) entered disabled state -👾 kernel | [ 752.479028] vethb34ecde: entered allmulticast mode -👾 kernel | [ 752.479078] vethb34ecde: entered promiscuous mode -👾 kernel | [ 753.677156] eth1: renamed from veth5953be3 -👾 kernel | [ 753.682578] br-d1f3e4394e37: port 11(vetha102874) entered blocking state -👾 kernel | [ 753.682614] br-d1f3e4394e37: port 11(vetha102874) entered disabled state -👾 kernel | [ 753.682644] vetha102874: entered allmulticast mode -👾 kernel | [ 753.682693] vetha102874: entered promiscuous mode -👾 kernel | [ 753.682881] br-d1f3e4394e37: port 10(vethb34ecde) entered blocking state -👾 kernel | [ 753.682900] br-d1f3e4394e37: port 10(vethb34ecde) entered forwarding state -👾 kernel | [ 754.392071] eth1: renamed from veth35dabb4 -👾 kernel | [ 754.394766] br-d1f3e4394e37: port 11(vetha102874) entered blocking state -👾 kernel | [ 754.394809] br-d1f3e4394e37: port 11(vetha102874) entered forwarding state -🌲 vmgr | time="01-13 20:23:11" level=error msg="TCP forward [100.50.83.26:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 20:23:11" level=error msg="TCP forward [34.225.196.179:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 20:23:11" level=error msg="TCP forward [35.171.115.154:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 20:23:11" level=error msg="TCP forward [34.236.95.57:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 20:23:16" level=error msg="TCP forward [162.159.140.245:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 20:23:21" level=error msg="TCP forward [172.66.0.243:443] create endpoint failed: connection was refused" -👾 kernel | [ 5135.301055] br-2ea4b26a6c58: port 7(veth7c49e51) entered disabled state -👾 kernel | [ 5135.301271] veth9038a6b: renamed from eth0 -👾 kernel | [ 5135.345433] vethbb9b49e: renamed from eth0 -👾 kernel | [ 5135.347550] br-2ea4b26a6c58: port 2(veth332709a) entered disabled state -👾 kernel | [ 5135.534212] br-2ea4b26a6c58: port 3(veth144a80f) entered disabled state -👾 kernel | [ 5135.534542] vethb7b15eb: renamed from eth0 -👾 kernel | [ 5135.760129] veth8b96f21: renamed from eth0 -👾 kernel | [ 5135.762323] br-2ea4b26a6c58: port 1(veth787da21) entered disabled state -👾 kernel | [ 5135.780907] br-2ea4b26a6c58: port 4(vethb3335ac) entered disabled state -👾 kernel | [ 5135.781064] veth8e858fd: renamed from eth0 -👾 kernel | [ 5135.807084] br-2ea4b26a6c58: port 7(veth7c49e51) entered disabled state -👾 kernel | [ 5135.807557] veth7c49e51 (unregistering): left allmulticast mode -👾 kernel | [ 5135.807575] veth7c49e51 (unregistering): left promiscuous mode -👾 kernel | [ 5135.807593] br-2ea4b26a6c58: port 7(veth7c49e51) entered disabled state -👾 kernel | [ 5135.844149] br-2ea4b26a6c58: port 6(veth3ffccc3) entered disabled state -👾 kernel | [ 5135.844247] veth556c566: renamed from eth0 -👾 kernel | [ 5135.862839] br-2ea4b26a6c58: port 2(veth332709a) entered disabled state -👾 kernel | [ 5135.863568] veth332709a (unregistering): left allmulticast mode -👾 kernel | [ 5135.863593] veth332709a (unregistering): left promiscuous mode -👾 kernel | [ 5135.863607] br-2ea4b26a6c58: port 2(veth332709a) entered disabled state -👾 kernel | [ 5135.875108] br-2ea4b26a6c58: port 8(vethf6498c9) entered disabled state -👾 kernel | [ 5135.875242] vethb868284: renamed from eth1 -👾 kernel | [ 5135.906056] br-2ea4b26a6c58: port 1(veth787da21) entered disabled state -👾 kernel | [ 5135.906671] veth787da21 (unregistering): left allmulticast mode -👾 kernel | [ 5135.906696] veth787da21 (unregistering): left promiscuous mode -👾 kernel | [ 5135.906708] br-2ea4b26a6c58: port 1(veth787da21) entered disabled state -👾 kernel | [ 5135.931083] br-2ea4b26a6c58: port 5(vethb1a1722) entered disabled state -👾 kernel | [ 5135.931236] veth5ff3904: renamed from eth0 -👾 kernel | [ 5135.955010] br-2ea4b26a6c58: port 3(veth144a80f) entered disabled state -👾 kernel | [ 5135.955547] veth144a80f (unregistering): left allmulticast mode -👾 kernel | [ 5135.955566] veth144a80f (unregistering): left promiscuous mode -👾 kernel | [ 5135.955583] br-2ea4b26a6c58: port 3(veth144a80f) entered disabled state -👾 kernel | [ 5135.967522] br-d1f3e4394e37: port 11(vetha102874) entered disabled state -👾 kernel | [ 5135.967760] veth35dabb4: renamed from eth1 -👾 kernel | [ 5135.988349] br-2ea4b26a6c58: port 8(vethf6498c9) entered disabled state -👾 kernel | [ 5135.988894] vethf6498c9 (unregistering): left allmulticast mode -👾 kernel | [ 5135.988910] vethf6498c9 (unregistering): left promiscuous mode -👾 kernel | [ 5135.988924] br-2ea4b26a6c58: port 8(vethf6498c9) entered disabled state -👾 kernel | [ 5136.032937] br-2ea4b26a6c58: port 4(vethb3335ac) entered disabled state -👾 kernel | [ 5136.033460] vethb3335ac (unregistering): left allmulticast mode -👾 kernel | [ 5136.033479] vethb3335ac (unregistering): left promiscuous mode -👾 kernel | [ 5136.033501] br-2ea4b26a6c58: port 4(vethb3335ac) entered disabled state -👾 kernel | [ 5136.310880] br-2ea4b26a6c58: port 6(veth3ffccc3) entered disabled state -👾 kernel | [ 5136.311494] veth3ffccc3 (unregistering): left allmulticast mode -👾 kernel | [ 5136.311551] veth3ffccc3 (unregistering): left promiscuous mode -👾 kernel | [ 5136.311574] br-2ea4b26a6c58: port 6(veth3ffccc3) entered disabled state -👾 kernel | [ 5136.493531] br-d1f3e4394e37: port 11(vetha102874) entered disabled state -👾 kernel | [ 5136.494349] vetha102874 (unregistering): left allmulticast mode -👾 kernel | [ 5136.494377] vetha102874 (unregistering): left promiscuous mode -👾 kernel | [ 5136.494389] br-d1f3e4394e37: port 11(vetha102874) entered disabled state -👾 kernel | [ 5136.519946] br-d1f3e4394e37: port 6(veth24ab076) entered disabled state -👾 kernel | [ 5136.520128] veth4c79ddb: renamed from eth1 -👾 kernel | [ 5136.561250] vethe7ad240: renamed from eth1 -👾 kernel | [ 5136.563192] br-d1f3e4394e37: port 7(veth5c821ba) entered disabled state -👾 kernel | [ 5136.589676] veth5953be3: renamed from eth1 -👾 kernel | [ 5136.590211] br-d1f3e4394e37: port 8(vetha789816) entered disabled state -👾 kernel | [ 5136.590270] br-d1f3e4394e37: port 5(veth2dc1ce7) entered disabled state -👾 kernel | [ 5136.590310] br-d1f3e4394e37: port 10(vethb34ecde) entered disabled state -👾 kernel | [ 5136.590445] veth9bf89ce: renamed from eth1 -👾 kernel | [ 5136.618836] veth4bf36a0: renamed from eth0 -👾 kernel | [ 5136.619510] br-d1f3e4394e37: port 6(veth24ab076) entered disabled state -👾 kernel | [ 5136.620187] veth24ab076 (unregistering): left allmulticast mode -👾 kernel | [ 5136.620207] veth24ab076 (unregistering): left promiscuous mode -👾 kernel | [ 5136.620222] br-d1f3e4394e37: port 6(veth24ab076) entered disabled state -👾 kernel | [ 5136.660401] br-2ea4b26a6c58: port 5(vethb1a1722) entered disabled state -👾 kernel | [ 5136.661000] vethb1a1722 (unregistering): left allmulticast mode -👾 kernel | [ 5136.661029] vethb1a1722 (unregistering): left promiscuous mode -👾 kernel | [ 5136.661053] br-2ea4b26a6c58: port 5(vethb1a1722) entered disabled state -🌸 agent:docker | time="01-13 20:44:09" level=info msg="removing network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-2ea4b26a6c58}" name=event-agent_default -👾 kernel | [ 5136.780553] br-d1f3e4394e37: port 7(veth5c821ba) entered disabled state -👾 kernel | [ 5136.781345] veth5c821ba (unregistering): left allmulticast mode -👾 kernel | [ 5136.781440] veth5c821ba (unregistering): left promiscuous mode -👾 kernel | [ 5136.781462] br-d1f3e4394e37: port 7(veth5c821ba) entered disabled state -👾 kernel | [ 5136.789099] br-d1f3e4394e37: port 9(veth3d23ff9) entered disabled state -👾 kernel | [ 5136.789371] vetha9eee09: renamed from eth1 -👾 kernel | [ 5136.832070] br-d1f3e4394e37: port 5(veth2dc1ce7) entered disabled state -👾 kernel | [ 5136.832953] veth2dc1ce7 (unregistering): left allmulticast mode -👾 kernel | [ 5136.832983] veth2dc1ce7 (unregistering): left promiscuous mode -👾 kernel | [ 5136.833005] br-d1f3e4394e37: port 5(veth2dc1ce7) entered disabled state -👾 kernel | [ 5136.862635] br-d1f3e4394e37: port 10(vethb34ecde) entered disabled state -👾 kernel | [ 5136.863262] vethb34ecde (unregistering): left allmulticast mode -👾 kernel | [ 5136.863290] vethb34ecde (unregistering): left promiscuous mode -👾 kernel | [ 5136.863310] br-d1f3e4394e37: port 10(vethb34ecde) entered disabled state -👾 kernel | [ 5136.890276] br-d1f3e4394e37: port 8(vetha789816) entered disabled state -👾 kernel | [ 5136.890776] vetha789816 (unregistering): left allmulticast mode -👾 kernel | [ 5136.890824] vetha789816 (unregistering): left promiscuous mode -👾 kernel | [ 5136.890846] br-d1f3e4394e37: port 8(vetha789816) entered disabled state -👾 kernel | [ 5137.402348] br-d1f3e4394e37: port 9(veth3d23ff9) entered disabled state -👾 kernel | [ 5137.403097] veth3d23ff9 (unregistering): left allmulticast mode -👾 kernel | [ 5137.403122] veth3d23ff9 (unregistering): left promiscuous mode -👾 kernel | [ 5137.403135] br-d1f3e4394e37: port 9(veth3d23ff9) entered disabled state -👾 kernel | [ 7428.701489] br-3a2bb40bbcdb: port 1(vethc2182b3) entered blocking state -👾 kernel | [ 7428.701548] br-3a2bb40bbcdb: port 1(vethc2182b3) entered disabled state -👾 kernel | [ 7428.701571] vethc2182b3: entered allmulticast mode -👾 kernel | [ 7428.701611] vethc2182b3: entered promiscuous mode -👾 kernel | [ 7428.841403] eth0: renamed from veth1a8172b -👾 kernel | [ 7428.841958] br-3a2bb40bbcdb: port 1(vethc2182b3) entered blocking state -👾 kernel | [ 7428.842001] br-3a2bb40bbcdb: port 1(vethc2182b3) entered forwarding state -👾 kernel | [ 7429.057682] br-d1f3e4394e37: port 5(veth2d5497b) entered blocking state -👾 kernel | [ 7429.057724] br-d1f3e4394e37: port 5(veth2d5497b) entered disabled state -👾 kernel | [ 7429.057741] veth2d5497b: entered allmulticast mode -👾 kernel | [ 7429.057779] veth2d5497b: entered promiscuous mode -👾 kernel | [ 7429.200272] br-d1f3e4394e37: port 6(vethe4ef3f3) entered blocking state -👾 kernel | [ 7429.200354] br-d1f3e4394e37: port 6(vethe4ef3f3) entered disabled state -👾 kernel | [ 7429.200379] vethe4ef3f3: entered allmulticast mode -👾 kernel | [ 7429.200436] vethe4ef3f3: entered promiscuous mode -👾 kernel | [ 7429.200773] br-3a2bb40bbcdb: port 2(veth45aca23) entered blocking state -👾 kernel | [ 7429.200807] br-3a2bb40bbcdb: port 2(veth45aca23) entered disabled state -👾 kernel | [ 7429.200829] veth45aca23: entered allmulticast mode -👾 kernel | [ 7429.200865] veth45aca23: entered promiscuous mode -🌸 agent:docker | time="01-13 21:22:21" level=info msg="adding network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-3a2bb40bbcdb}" name=omega_default -👾 kernel | [ 7429.314357] eth0: renamed from vethc63a6b0 -👾 kernel | [ 7429.314855] br-d1f3e4394e37: port 5(veth2d5497b) entered blocking state -👾 kernel | [ 7429.314882] br-d1f3e4394e37: port 5(veth2d5497b) entered forwarding state -👾 kernel | [ 7429.728733] eth1: renamed from veth062c431 -👾 kernel | [ 7429.733529] br-d1f3e4394e37: port 6(vethe4ef3f3) entered blocking state -👾 kernel | [ 7429.733572] br-d1f3e4394e37: port 6(vethe4ef3f3) entered forwarding state -👾 kernel | [ 7429.733617] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered blocking state -👾 kernel | [ 7429.733667] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered disabled state -👾 kernel | [ 7429.733697] vethb05b0ee: entered allmulticast mode -👾 kernel | [ 7429.733765] vethb05b0ee: entered promiscuous mode -👾 kernel | [ 7429.734036] br-d1f3e4394e37: port 7(veth06b7a22) entered blocking state -👾 kernel | [ 7429.734066] br-d1f3e4394e37: port 7(veth06b7a22) entered disabled state -👾 kernel | [ 7429.734084] veth06b7a22: entered allmulticast mode -👾 kernel | [ 7429.734130] veth06b7a22: entered promiscuous mode -👾 kernel | [ 7429.858190] eth0: renamed from veth7874483 -👾 kernel | [ 7429.858827] br-3a2bb40bbcdb: port 2(veth45aca23) entered blocking state -👾 kernel | [ 7429.858860] br-3a2bb40bbcdb: port 2(veth45aca23) entered forwarding state -👾 kernel | [ 7429.992208] br-3a2bb40bbcdb: port 4(vethaf4387f) entered blocking state -👾 kernel | [ 7429.992250] br-3a2bb40bbcdb: port 4(vethaf4387f) entered disabled state -👾 kernel | [ 7429.992276] vethaf4387f: entered allmulticast mode -👾 kernel | [ 7429.992363] vethaf4387f: entered promiscuous mode -👾 kernel | [ 7430.015068] eth0: renamed from vethd9981cc -👾 kernel | [ 7430.015514] br-d1f3e4394e37: port 7(veth06b7a22) entered blocking state -👾 kernel | [ 7430.015533] br-d1f3e4394e37: port 7(veth06b7a22) entered forwarding state -👾 kernel | [ 7430.015857] eth0: renamed from vethe0de746 -👾 kernel | [ 7430.016220] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered blocking state -👾 kernel | [ 7430.016238] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered forwarding state -👾 kernel | [ 7430.084260] br-3a2bb40bbcdb: port 5(veth800f8ba) entered blocking state -👾 kernel | [ 7430.086345] br-3a2bb40bbcdb: port 5(veth800f8ba) entered disabled state -👾 kernel | [ 7430.086404] veth800f8ba: entered allmulticast mode -👾 kernel | [ 7430.086477] veth800f8ba: entered promiscuous mode -👾 kernel | [ 7430.130589] eth0: renamed from veth4cf8545 -👾 kernel | [ 7430.130986] br-3a2bb40bbcdb: port 4(vethaf4387f) entered blocking state -👾 kernel | [ 7430.131016] br-3a2bb40bbcdb: port 4(vethaf4387f) entered forwarding state -👾 kernel | [ 7430.284885] br-d1f3e4394e37: port 8(veth11dfb4b) entered blocking state -👾 kernel | [ 7430.284917] br-d1f3e4394e37: port 8(veth11dfb4b) entered disabled state -👾 kernel | [ 7430.284941] veth11dfb4b: entered allmulticast mode -🌸 agent:docker | time="01-13 21:22:22" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 7430.284993] veth11dfb4b: entered promiscuous mode -👾 kernel | [ 7431.507476] br-3a2bb40bbcdb: port 6(vethde25cfb) entered blocking state -👾 kernel | [ 7431.507509] br-3a2bb40bbcdb: port 6(vethde25cfb) entered disabled state -👾 kernel | [ 7431.507526] vethde25cfb: entered allmulticast mode -👾 kernel | [ 7431.507577] vethde25cfb: entered promiscuous mode -👾 kernel | [ 7432.716482] eth1: renamed from veth3bc5b20 -👾 kernel | [ 7432.717384] eth1: renamed from vethfab1b55 -👾 kernel | [ 7432.719451] br-d1f3e4394e37: port 8(veth11dfb4b) entered blocking state -👾 kernel | [ 7432.719490] br-d1f3e4394e37: port 8(veth11dfb4b) entered forwarding state -👾 kernel | [ 7432.719638] br-3a2bb40bbcdb: port 7(veth193b2bc) entered blocking state -👾 kernel | [ 7432.719667] br-3a2bb40bbcdb: port 7(veth193b2bc) entered disabled state -👾 kernel | [ 7432.719693] veth193b2bc: entered allmulticast mode -👾 kernel | [ 7432.719741] veth193b2bc: entered promiscuous mode -👾 kernel | [ 7432.719967] br-3a2bb40bbcdb: port 6(vethde25cfb) entered blocking state -👾 kernel | [ 7432.720007] br-3a2bb40bbcdb: port 6(vethde25cfb) entered forwarding state -👾 kernel | [ 7433.020027] eth0: renamed from vethd811f6a -👾 kernel | [ 7433.020519] br-3a2bb40bbcdb: port 5(veth800f8ba) entered blocking state -👾 kernel | [ 7433.020548] br-3a2bb40bbcdb: port 5(veth800f8ba) entered forwarding state -👾 kernel | [ 7433.233542] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered disabled state -👾 kernel | [ 7433.233646] vethe0de746: renamed from eth0 -📦 scon | time="01-14 02:22:25" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:6333" -📦 scon | time="01-14 02:22:25" level=info msg="add forward" container=docker spec="tcp:[::]:6333" -👾 kernel | [ 7433.372111] br-3a2bb40bbcdb: port 8(vethefb740c) entered blocking state -👾 kernel | [ 7433.372158] br-3a2bb40bbcdb: port 8(vethefb740c) entered disabled state -👾 kernel | [ 7433.372183] vethefb740c: entered allmulticast mode -👾 kernel | [ 7433.372227] vethefb740c: entered promiscuous mode -👾 kernel | [ 7433.419789] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered disabled state -👾 kernel | [ 7433.420214] vethb05b0ee (unregistering): left allmulticast mode -👾 kernel | [ 7433.420274] vethb05b0ee (unregistering): left promiscuous mode -👾 kernel | [ 7433.420307] br-3a2bb40bbcdb: port 3(vethb05b0ee) entered disabled state -👾 kernel | [ 7433.621775] eth0: renamed from vethcd4b5bd -👾 kernel | [ 7433.622237] br-3a2bb40bbcdb: port 7(veth193b2bc) entered blocking state -👾 kernel | [ 7433.622267] br-3a2bb40bbcdb: port 7(veth193b2bc) entered forwarding state -👾 kernel | [ 7434.014684] eth1: renamed from vethcd8ca19 -👾 kernel | [ 7434.016440] br-3a2bb40bbcdb: port 8(vethefb740c) entered blocking state -👾 kernel | [ 7434.016470] br-3a2bb40bbcdb: port 8(vethefb740c) entered forwarding state -👾 kernel | [ 7434.016506] br-3a2bb40bbcdb: port 3(veth857bb06) entered blocking state -👾 kernel | [ 7434.016539] br-3a2bb40bbcdb: port 3(veth857bb06) entered disabled state -👾 kernel | [ 7434.016565] veth857bb06: entered allmulticast mode -👾 kernel | [ 7434.016620] veth857bb06: entered promiscuous mode -👾 kernel | [ 7435.222757] br-d1f3e4394e37: port 9(veth95da60c) entered blocking state -👾 kernel | [ 7435.222804] br-d1f3e4394e37: port 9(veth95da60c) entered disabled state -👾 kernel | [ 7435.222843] veth95da60c: entered allmulticast mode -👾 kernel | [ 7435.222895] veth95da60c: entered promiscuous mode -👾 kernel | [ 7435.239860] eth0: renamed from vethc85f645 -👾 kernel | [ 7435.240887] br-3a2bb40bbcdb: port 3(veth857bb06) entered blocking state -👾 kernel | [ 7435.240936] br-3a2bb40bbcdb: port 3(veth857bb06) entered forwarding state -👾 kernel | [ 7435.483964] eth1: renamed from veth5e9a10b -👾 kernel | [ 7435.485456] br-d1f3e4394e37: port 9(veth95da60c) entered blocking state -👾 kernel | [ 7435.485487] br-d1f3e4394e37: port 9(veth95da60c) entered forwarding state -👾 kernel | [ 7436.617615] br-d1f3e4394e37: port 10(veth8705a00) entered blocking state -👾 kernel | [ 7436.617650] br-d1f3e4394e37: port 10(veth8705a00) entered disabled state -👾 kernel | [ 7436.617669] veth8705a00: entered allmulticast mode -👾 kernel | [ 7436.617712] veth8705a00: entered promiscuous mode -🌸 agent:docker | time="01-13 21:22:29" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 7436.969389] br-d1f3e4394e37: port 11(veth02f35a7) entered blocking state -👾 kernel | [ 7436.969418] br-d1f3e4394e37: port 11(veth02f35a7) entered disabled state -👾 kernel | [ 7436.969440] veth02f35a7: entered allmulticast mode -👾 kernel | [ 7436.969482] veth02f35a7: entered promiscuous mode -👾 kernel | [ 7436.993716] eth0: renamed from vethbc9eb11 -👾 kernel | [ 7436.994910] br-d1f3e4394e37: port 10(veth8705a00) entered blocking state -👾 kernel | [ 7436.994935] br-d1f3e4394e37: port 10(veth8705a00) entered forwarding state -👾 kernel | [ 7437.700513] br-3a2bb40bbcdb: port 9(veth35f3732) entered blocking state -👾 kernel | [ 7437.700553] br-3a2bb40bbcdb: port 9(veth35f3732) entered disabled state -👾 kernel | [ 7437.700579] veth35f3732: entered allmulticast mode -👾 kernel | [ 7437.700633] veth35f3732: entered promiscuous mode -👾 kernel | [ 7437.700739] eth1: renamed from veth2219b73 -👾 kernel | [ 7437.714086] br-d1f3e4394e37: port 11(veth02f35a7) entered blocking state -👾 kernel | [ 7437.714122] br-d1f3e4394e37: port 11(veth02f35a7) entered forwarding state -👾 kernel | [ 7438.469453] eth1: renamed from vethb33942d -👾 kernel | [ 7438.470126] br-3a2bb40bbcdb: port 9(veth35f3732) entered blocking state -👾 kernel | [ 7438.470152] br-3a2bb40bbcdb: port 9(veth35f3732) entered forwarding state -👾 kernel | [ 7441.048873] br-d1f3e4394e37: port 12(vethd1957d6) entered blocking state -👾 kernel | [ 7441.048908] br-d1f3e4394e37: port 12(vethd1957d6) entered disabled state -👾 kernel | [ 7441.048932] vethd1957d6: entered allmulticast mode -👾 kernel | [ 7441.048974] vethd1957d6: entered promiscuous mode -👾 kernel | [ 7441.564841] br-d1f3e4394e37: port 13(vethd123fc6) entered blocking state -👾 kernel | [ 7441.564890] br-d1f3e4394e37: port 13(vethd123fc6) entered disabled state -👾 kernel | [ 7441.564918] vethd123fc6: entered allmulticast mode -👾 kernel | [ 7441.564972] vethd123fc6: entered promiscuous mode -👾 kernel | [ 7441.693910] eth0: renamed from vethb06ead6 -👾 kernel | [ 7441.697397] br-d1f3e4394e37: port 12(vethd1957d6) entered blocking state -👾 kernel | [ 7441.697425] br-d1f3e4394e37: port 12(vethd1957d6) entered forwarding state -👾 kernel | [ 7442.131107] br-3a2bb40bbcdb: port 10(veth4a472b7) entered blocking state -👾 kernel | [ 7442.131147] br-3a2bb40bbcdb: port 10(veth4a472b7) entered disabled state -👾 kernel | [ 7442.131167] veth4a472b7: entered allmulticast mode -👾 kernel | [ 7442.131458] veth4a472b7: entered promiscuous mode -👾 kernel | [ 7442.135915] eth0: renamed from veth8980cac -👾 kernel | [ 7442.136546] br-d1f3e4394e37: port 13(vethd123fc6) entered blocking state -👾 kernel | [ 7442.136569] br-d1f3e4394e37: port 13(vethd123fc6) entered forwarding state -👾 kernel | [ 7442.140921] eth1: renamed from veth1c8b5f2 -👾 kernel | [ 7442.141874] br-3a2bb40bbcdb: port 10(veth4a472b7) entered blocking state -👾 kernel | [ 7442.141893] br-3a2bb40bbcdb: port 10(veth4a472b7) entered forwarding state -👾 kernel | [ 7442.272642] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered blocking state -👾 kernel | [ 7442.272678] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered disabled state -👾 kernel | [ 7442.272695] vethec9cc6d: entered allmulticast mode -👾 kernel | [ 7442.272750] vethec9cc6d: entered promiscuous mode -👾 kernel | [ 7442.308670] eth1: renamed from vethdec9453 -👾 kernel | [ 7442.312656] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered blocking state -👾 kernel | [ 7442.312690] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered forwarding state -👾 kernel | [ 7541.032175] hrtimer: interrupt took 6572423 ns -📦 scon | time="01-14 02:29:25" level=info msg="remove forward" key="tcp:0.0.0.0:6333" -📦 scon | time="01-14 02:29:25" level=info msg="remove forward" key="tcp:[::]:6333" -👾 kernel | [ 7852.984592] br-3a2bb40bbcdb: port 5(veth800f8ba) entered disabled state -👾 kernel | [ 7852.984805] vethd811f6a: renamed from eth0 -👾 kernel | [ 7853.537162] br-3a2bb40bbcdb: port 5(veth800f8ba) entered disabled state -👾 kernel | [ 7853.538160] veth800f8ba (unregistering): left allmulticast mode -👾 kernel | [ 7853.538189] veth800f8ba (unregistering): left promiscuous mode -👾 kernel | [ 7853.538220] br-3a2bb40bbcdb: port 5(veth800f8ba) entered disabled state -👾 kernel | [ 7853.922467] br-d1f3e4394e37: port 11(veth02f35a7) entered disabled state -👾 kernel | [ 7853.922603] veth2219b73: renamed from eth1 -👾 kernel | [ 7854.859132] br-d1f3e4394e37: port 8(veth11dfb4b) entered disabled state -👾 kernel | [ 7854.859406] veth3bc5b20: renamed from eth1 -👾 kernel | [ 7855.451148] br-d1f3e4394e37: port 12(vethd1957d6) entered disabled state -👾 kernel | [ 7855.451417] vethb06ead6: renamed from eth0 -👾 kernel | [ 7856.038256] br-d1f3e4394e37: port 13(vethd123fc6) entered disabled state -👾 kernel | [ 7856.038405] veth8980cac: renamed from eth0 -👾 kernel | [ 7856.073590] br-d1f3e4394e37: port 9(veth95da60c) entered disabled state -👾 kernel | [ 7856.073896] veth5e9a10b: renamed from eth1 -👾 kernel | [ 7856.398053] br-d1f3e4394e37: port 11(veth02f35a7) entered disabled state -👾 kernel | [ 7856.398800] veth02f35a7 (unregistering): left allmulticast mode -👾 kernel | [ 7856.398833] veth02f35a7 (unregistering): left promiscuous mode -👾 kernel | [ 7856.398855] br-d1f3e4394e37: port 11(veth02f35a7) entered disabled state -👾 kernel | [ 7856.700441] br-d1f3e4394e37: port 12(vethd1957d6) entered disabled state -👾 kernel | [ 7856.701000] vethd1957d6 (unregistering): left allmulticast mode -👾 kernel | [ 7856.701016] vethd1957d6 (unregistering): left promiscuous mode -👾 kernel | [ 7856.701027] br-d1f3e4394e37: port 12(vethd1957d6) entered disabled state -👾 kernel | [ 7856.706258] br-3a2bb40bbcdb: port 3(veth857bb06) entered disabled state -👾 kernel | [ 7856.706476] vethc85f645: renamed from eth0 -👾 kernel | [ 7856.753059] br-d1f3e4394e37: port 8(veth11dfb4b) entered disabled state -👾 kernel | [ 7856.753821] veth11dfb4b (unregistering): left allmulticast mode -👾 kernel | [ 7856.753840] veth11dfb4b (unregistering): left promiscuous mode -👾 kernel | [ 7856.753850] br-d1f3e4394e37: port 8(veth11dfb4b) entered disabled state -👾 kernel | [ 7858.318930] br-d1f3e4394e37: port 13(vethd123fc6) entered disabled state -👾 kernel | [ 7858.319554] vethd123fc6 (unregistering): left allmulticast mode -👾 kernel | [ 7858.319599] vethd123fc6 (unregistering): left promiscuous mode -👾 kernel | [ 7858.319620] br-d1f3e4394e37: port 13(vethd123fc6) entered disabled state -👾 kernel | [ 7858.403416] br-3a2bb40bbcdb: port 3(veth857bb06) entered disabled state -👾 kernel | [ 7858.404046] veth857bb06 (unregistering): left allmulticast mode -👾 kernel | [ 7858.404079] veth857bb06 (unregistering): left promiscuous mode -👾 kernel | [ 7858.404095] br-3a2bb40bbcdb: port 3(veth857bb06) entered disabled state -👾 kernel | [ 7858.566538] br-3a2bb40bbcdb: port 10(veth4a472b7) entered disabled state -👾 kernel | [ 7858.566641] veth1c8b5f2: renamed from eth1 -👾 kernel | [ 7859.057312] br-3a2bb40bbcdb: port 2(veth45aca23) entered disabled state -👾 kernel | [ 7859.057466] veth7874483: renamed from eth0 -👾 kernel | [ 7859.622825] br-d1f3e4394e37: port 9(veth95da60c) entered disabled state -👾 kernel | [ 7859.623470] veth95da60c (unregistering): left allmulticast mode -👾 kernel | [ 7859.623500] veth95da60c (unregistering): left promiscuous mode -👾 kernel | [ 7859.623514] br-d1f3e4394e37: port 9(veth95da60c) entered disabled state -👾 kernel | [ 7860.856582] br-3a2bb40bbcdb: port 10(veth4a472b7) entered disabled state -👾 kernel | [ 7860.857375] veth4a472b7 (unregistering): left allmulticast mode -👾 kernel | [ 7860.857416] veth4a472b7 (unregistering): left promiscuous mode -👾 kernel | [ 7860.857429] br-3a2bb40bbcdb: port 10(veth4a472b7) entered disabled state -👾 kernel | [ 7861.059134] br-3a2bb40bbcdb: port 2(veth45aca23) entered disabled state -👾 kernel | [ 7861.059974] veth45aca23 (unregistering): left allmulticast mode -👾 kernel | [ 7861.059991] veth45aca23 (unregistering): left promiscuous mode -👾 kernel | [ 7861.060003] br-3a2bb40bbcdb: port 2(veth45aca23) entered disabled state -👾 kernel | [ 7861.062242] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered disabled state -👾 kernel | [ 7861.062419] vethdec9453: renamed from eth1 -👾 kernel | [ 7861.887284] br-3a2bb40bbcdb: port 7(veth193b2bc) entered disabled state -👾 kernel | [ 7861.887386] vethcd4b5bd: renamed from eth0 -👾 kernel | [ 7863.501698] br-3a2bb40bbcdb: port 7(veth193b2bc) entered disabled state -👾 kernel | [ 7863.501977] veth193b2bc (unregistering): left allmulticast mode -👾 kernel | [ 7863.502007] veth193b2bc (unregistering): left promiscuous mode -👾 kernel | [ 7863.502070] br-3a2bb40bbcdb: port 7(veth193b2bc) entered disabled state -👾 kernel | [ 7863.796322] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered disabled state -👾 kernel | [ 7863.796558] vethec9cc6d (unregistering): left allmulticast mode -👾 kernel | [ 7863.796609] vethec9cc6d (unregistering): left promiscuous mode -👾 kernel | [ 7863.796628] br-3a2bb40bbcdb: port 11(vethec9cc6d) entered disabled state -👾 kernel | [ 7863.826606] br-3a2bb40bbcdb: port 4(vethaf4387f) entered disabled state -👾 kernel | [ 7863.826900] veth4cf8545: renamed from eth0 -👾 kernel | [ 7863.979354] br-3a2bb40bbcdb: port 4(vethaf4387f) entered disabled state -👾 kernel | [ 7863.980536] vethaf4387f (unregistering): left allmulticast mode -👾 kernel | [ 7863.980561] vethaf4387f (unregistering): left promiscuous mode -👾 kernel | [ 7863.980575] br-3a2bb40bbcdb: port 4(vethaf4387f) entered disabled state -👾 kernel | [ 7864.267222] br-d1f3e4394e37: port 7(veth06b7a22) entered disabled state -👾 kernel | [ 7864.267398] vethd9981cc: renamed from eth0 -👾 kernel | [ 7864.542444] br-d1f3e4394e37: port 5(veth2d5497b) entered disabled state -👾 kernel | [ 7864.542765] vethc63a6b0: renamed from eth0 -👾 kernel | [ 7864.634770] veth062c431: renamed from eth1 -👾 kernel | [ 7864.635618] br-d1f3e4394e37: port 6(vethe4ef3f3) entered disabled state -👾 kernel | [ 7865.047778] br-d1f3e4394e37: port 7(veth06b7a22) entered disabled state -👾 kernel | [ 7865.048495] veth06b7a22 (unregistering): left allmulticast mode -👾 kernel | [ 7865.048522] veth06b7a22 (unregistering): left promiscuous mode -👾 kernel | [ 7865.048540] br-d1f3e4394e37: port 7(veth06b7a22) entered disabled state -👾 kernel | [ 7865.074550] br-d1f3e4394e37: port 6(vethe4ef3f3) entered disabled state -👾 kernel | [ 7865.075144] vethe4ef3f3 (unregistering): left allmulticast mode -👾 kernel | [ 7865.075412] vethe4ef3f3 (unregistering): left promiscuous mode -👾 kernel | [ 7865.075463] br-d1f3e4394e37: port 6(vethe4ef3f3) entered disabled state -👾 kernel | [ 7865.154374] br-d1f3e4394e37: port 5(veth2d5497b) entered disabled state -👾 kernel | [ 7865.155084] veth2d5497b (unregistering): left allmulticast mode -👾 kernel | [ 7865.155120] veth2d5497b (unregistering): left promiscuous mode -👾 kernel | [ 7865.155144] br-d1f3e4394e37: port 5(veth2d5497b) entered disabled state -👾 kernel | [ 7865.196605] br-3a2bb40bbcdb: port 8(vethefb740c) entered disabled state -👾 kernel | [ 7865.196683] vethcd8ca19: renamed from eth1 -🌸 agent:docker | time="01-13 21:29:37" level=error msg="failed to refresh networks" error="list links: results may be incomplete or inconsistent" -👾 kernel | [ 7865.220671] br-3a2bb40bbcdb: port 1(vethc2182b3) entered disabled state -👾 kernel | [ 7865.220782] veth1a8172b: renamed from eth0 -👾 kernel | [ 7865.263168] br-3a2bb40bbcdb: port 6(vethde25cfb) entered disabled state -👾 kernel | [ 7865.263341] vethfab1b55: renamed from eth1 -👾 kernel | [ 7865.282588] br-3a2bb40bbcdb: port 8(vethefb740c) entered disabled state -👾 kernel | [ 7865.282836] vethefb740c (unregistering): left allmulticast mode -👾 kernel | [ 7865.282885] vethefb740c (unregistering): left promiscuous mode -👾 kernel | [ 7865.282931] br-3a2bb40bbcdb: port 8(vethefb740c) entered disabled state -👾 kernel | [ 7865.315376] br-3a2bb40bbcdb: port 1(vethc2182b3) entered disabled state -👾 kernel | [ 7865.315767] vethc2182b3 (unregistering): left allmulticast mode -👾 kernel | [ 7865.315803] vethc2182b3 (unregistering): left promiscuous mode -👾 kernel | [ 7865.315845] br-3a2bb40bbcdb: port 1(vethc2182b3) entered disabled state -👾 kernel | [ 7865.360987] br-3a2bb40bbcdb: port 6(vethde25cfb) entered disabled state -👾 kernel | [ 7865.361271] vethde25cfb (unregistering): left allmulticast mode -👾 kernel | [ 7865.361308] vethde25cfb (unregistering): left promiscuous mode -👾 kernel | [ 7865.361323] br-3a2bb40bbcdb: port 6(vethde25cfb) entered disabled state -👾 kernel | [ 7865.696766] br-d1f3e4394e37: port 10(veth8705a00) entered disabled state -👾 kernel | [ 7865.696974] vethbc9eb11: renamed from eth0 -👾 kernel | [ 7866.063230] br-d1f3e4394e37: port 10(veth8705a00) entered disabled state -👾 kernel | [ 7866.063838] veth8705a00 (unregistering): left allmulticast mode -👾 kernel | [ 7866.063866] veth8705a00 (unregistering): left promiscuous mode -👾 kernel | [ 7866.063884] br-d1f3e4394e37: port 10(veth8705a00) entered disabled state -👾 kernel | [ 7866.168277] br-3a2bb40bbcdb: port 9(veth35f3732) entered disabled state -👾 kernel | [ 7866.168409] vethb33942d: renamed from eth1 -👾 kernel | [ 7866.257749] br-3a2bb40bbcdb: port 9(veth35f3732) entered disabled state -👾 kernel | [ 7866.258352] veth35f3732 (unregistering): left allmulticast mode -👾 kernel | [ 7866.258399] veth35f3732 (unregistering): left promiscuous mode -👾 kernel | [ 7866.258412] br-3a2bb40bbcdb: port 9(veth35f3732) entered disabled state -🌸 agent:docker | time="01-13 21:29:38" level=info msg="removing network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-3a2bb40bbcdb}" name=omega_default -👾 kernel | [ 7873.619040] br-d1f3e4394e37: port 5(vethd32149a) entered blocking state -👾 kernel | [ 7873.619189] br-d1f3e4394e37: port 5(vethd32149a) entered disabled state -👾 kernel | [ 7873.619218] vethd32149a: entered allmulticast mode -👾 kernel | [ 7873.619271] vethd32149a: entered promiscuous mode -👾 kernel | [ 7873.695438] eth0: renamed from veth5c9b989 -👾 kernel | [ 7873.695889] br-d1f3e4394e37: port 5(vethd32149a) entered blocking state -👾 kernel | [ 7873.695928] br-d1f3e4394e37: port 5(vethd32149a) entered forwarding state -👾 kernel | [ 7873.782294] br-805744f862c6: port 1(veth91c050f) entered blocking state -👾 kernel | [ 7873.782346] br-805744f862c6: port 1(veth91c050f) entered disabled state -👾 kernel | [ 7873.782374] veth91c050f: entered allmulticast mode -👾 kernel | [ 7873.782436] veth91c050f: entered promiscuous mode -🌸 agent:docker | time="01-13 21:29:46" level=info msg="adding network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-805744f862c6}" name=omega_default -👾 kernel | [ 7874.088714] eth1: renamed from veth099792d -👾 kernel | [ 7874.093568] br-805744f862c6: port 1(veth91c050f) entered blocking state -👾 kernel | [ 7874.093606] br-805744f862c6: port 1(veth91c050f) entered forwarding state -👾 kernel | [ 7874.095111] br-805744f862c6: port 2(vethf2cae25) entered blocking state -👾 kernel | [ 7874.095171] br-805744f862c6: port 2(vethf2cae25) entered disabled state -👾 kernel | [ 7874.095193] vethf2cae25: entered allmulticast mode -👾 kernel | [ 7874.095241] vethf2cae25: entered promiscuous mode -🌸 agent:docker | time="01-13 21:29:46" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 7874.337160] br-805744f862c6: port 3(veth1a4c2e8) entered blocking state -👾 kernel | [ 7874.337192] br-805744f862c6: port 3(veth1a4c2e8) entered disabled state -👾 kernel | [ 7874.337211] veth1a4c2e8: entered allmulticast mode -👾 kernel | [ 7874.337246] veth1a4c2e8: entered promiscuous mode -👾 kernel | [ 7874.663016] eth0: renamed from vethb3fac7b -👾 kernel | [ 7874.663413] br-805744f862c6: port 2(vethf2cae25) entered blocking state -👾 kernel | [ 7874.663436] br-805744f862c6: port 2(vethf2cae25) entered forwarding state -👾 kernel | [ 7876.017910] br-805744f862c6: port 4(vethded7e18) entered blocking state -👾 kernel | [ 7876.017947] br-805744f862c6: port 4(vethded7e18) entered disabled state -👾 kernel | [ 7876.017969] vethded7e18: entered allmulticast mode -👾 kernel | [ 7876.018005] vethded7e18: entered promiscuous mode -👾 kernel | [ 7876.541231] br-d1f3e4394e37: port 6(vethfbeb5b8) entered blocking state -👾 kernel | [ 7876.541265] br-d1f3e4394e37: port 6(vethfbeb5b8) entered disabled state -👾 kernel | [ 7876.541285] vethfbeb5b8: entered allmulticast mode -👾 kernel | [ 7876.541327] vethfbeb5b8: entered promiscuous mode -👾 kernel | [ 7876.847366] eth0: renamed from vethb61731d -👾 kernel | [ 7876.847820] br-805744f862c6: port 3(veth1a4c2e8) entered blocking state -👾 kernel | [ 7876.847842] br-805744f862c6: port 3(veth1a4c2e8) entered forwarding state -👾 kernel | [ 7877.158059] br-805744f862c6: port 5(veth07a6a4a) entered blocking state -👾 kernel | [ 7877.158123] br-805744f862c6: port 5(veth07a6a4a) entered disabled state -👾 kernel | [ 7877.158141] veth07a6a4a: entered allmulticast mode -👾 kernel | [ 7877.158190] veth07a6a4a: entered promiscuous mode -👾 kernel | [ 7877.173326] eth0: renamed from vethd9e79b2 -👾 kernel | [ 7877.173855] br-d1f3e4394e37: port 6(vethfbeb5b8) entered blocking state -👾 kernel | [ 7877.173878] br-d1f3e4394e37: port 6(vethfbeb5b8) entered forwarding state -👾 kernel | [ 7877.216280] eth0: renamed from veth21fca2f -👾 kernel | [ 7877.216739] br-805744f862c6: port 4(vethded7e18) entered blocking state -👾 kernel | [ 7877.216766] br-805744f862c6: port 4(vethded7e18) entered forwarding state -👾 kernel | [ 7877.220493] br-d1f3e4394e37: port 7(vethee0e368) entered blocking state -👾 kernel | [ 7877.220528] br-d1f3e4394e37: port 7(vethee0e368) entered disabled state -👾 kernel | [ 7877.220547] vethee0e368: entered allmulticast mode -👾 kernel | [ 7877.220594] vethee0e368: entered promiscuous mode -👾 kernel | [ 7877.281159] br-805744f862c6: port 6(vethc73cb7a) entered blocking state -👾 kernel | [ 7877.281196] br-805744f862c6: port 6(vethc73cb7a) entered disabled state -👾 kernel | [ 7877.281216] vethc73cb7a: entered allmulticast mode -👾 kernel | [ 7877.281262] vethc73cb7a: entered promiscuous mode -📦 scon | time="01-14 02:29:50" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:6333" -📦 scon | time="01-14 02:29:50" level=info msg="add forward" container=docker spec="tcp:[::]:6333" -👾 kernel | [ 7877.420124] br-d1f3e4394e37: port 8(veth62d12d5) entered blocking state -👾 kernel | [ 7877.420160] br-d1f3e4394e37: port 8(veth62d12d5) entered disabled state -👾 kernel | [ 7877.420181] veth62d12d5: entered allmulticast mode -👾 kernel | [ 7877.420224] veth62d12d5: entered promiscuous mode -👾 kernel | [ 7877.420453] br-805744f862c6: port 7(vetha2f3f6c) entered blocking state -👾 kernel | [ 7877.420475] br-805744f862c6: port 7(vetha2f3f6c) entered disabled state -👾 kernel | [ 7877.420494] vetha2f3f6c: entered allmulticast mode -👾 kernel | [ 7877.420526] vetha2f3f6c: entered promiscuous mode -👾 kernel | [ 7877.425230] eth0: renamed from veth7794f34 -👾 kernel | [ 7877.425712] br-805744f862c6: port 5(veth07a6a4a) entered blocking state -👾 kernel | [ 7877.425753] br-805744f862c6: port 5(veth07a6a4a) entered forwarding state -👾 kernel | [ 7877.467354] eth0: renamed from vethb73eebe -👾 kernel | [ 7877.468699] br-d1f3e4394e37: port 7(vethee0e368) entered blocking state -👾 kernel | [ 7877.468719] br-d1f3e4394e37: port 7(vethee0e368) entered forwarding state -👾 kernel | [ 7877.469127] eth0: renamed from veth208559a -👾 kernel | [ 7877.470246] br-805744f862c6: port 6(vethc73cb7a) entered blocking state -👾 kernel | [ 7877.470298] br-805744f862c6: port 6(vethc73cb7a) entered forwarding state -👾 kernel | [ 7877.908280] br-d1f3e4394e37: port 9(veth73864c3) entered blocking state -👾 kernel | [ 7877.908321] br-d1f3e4394e37: port 9(veth73864c3) entered disabled state -👾 kernel | [ 7877.908344] veth73864c3: entered allmulticast mode -👾 kernel | [ 7877.908388] veth73864c3: entered promiscuous mode -👾 kernel | [ 7878.008020] eth1: renamed from veth60bcb15 -👾 kernel | [ 7878.008491] eth1: renamed from vethe8931bf -👾 kernel | [ 7878.008884] eth1: renamed from veth4168d4c -👾 kernel | [ 7878.009710] br-d1f3e4394e37: port 8(veth62d12d5) entered blocking state -👾 kernel | [ 7878.009737] br-d1f3e4394e37: port 8(veth62d12d5) entered forwarding state -👾 kernel | [ 7878.009928] br-d1f3e4394e37: port 9(veth73864c3) entered blocking state -👾 kernel | [ 7878.009959] br-d1f3e4394e37: port 9(veth73864c3) entered forwarding state -👾 kernel | [ 7878.010270] br-805744f862c6: port 7(vetha2f3f6c) entered blocking state -👾 kernel | [ 7878.010299] br-805744f862c6: port 7(vetha2f3f6c) entered forwarding state -👾 kernel | [ 7878.105267] br-805744f862c6: port 8(veth81252de) entered blocking state -👾 kernel | [ 7878.105294] br-805744f862c6: port 8(veth81252de) entered disabled state -👾 kernel | [ 7878.105314] veth81252de: entered allmulticast mode -👾 kernel | [ 7878.105357] veth81252de: entered promiscuous mode -👾 kernel | [ 7878.505609] eth1: renamed from vethf8cd222 -👾 kernel | [ 7878.511060] br-805744f862c6: port 8(veth81252de) entered blocking state -👾 kernel | [ 7878.511114] br-805744f862c6: port 8(veth81252de) entered forwarding state -👾 kernel | [ 7879.471426] br-d1f3e4394e37: port 10(veth8587586) entered blocking state -👾 kernel | [ 7879.471467] br-d1f3e4394e37: port 10(veth8587586) entered disabled state -👾 kernel | [ 7879.471486] veth8587586: entered allmulticast mode -👾 kernel | [ 7879.471538] veth8587586: entered promiscuous mode -👾 kernel | [ 7879.537483] br-805744f862c6: port 6(vethc73cb7a) entered disabled state -👾 kernel | [ 7879.538529] veth208559a: renamed from eth0 -👾 kernel | [ 7879.926877] br-805744f862c6: port 6(vethc73cb7a) entered disabled state -👾 kernel | [ 7879.927622] vethc73cb7a (unregistering): left allmulticast mode -👾 kernel | [ 7879.927647] vethc73cb7a (unregistering): left promiscuous mode -👾 kernel | [ 7879.927661] br-805744f862c6: port 6(vethc73cb7a) entered disabled state -👾 kernel | [ 7879.950127] eth0: renamed from veth86599c6 -👾 kernel | [ 7879.951108] br-d1f3e4394e37: port 10(veth8587586) entered blocking state -👾 kernel | [ 7879.951133] br-d1f3e4394e37: port 10(veth8587586) entered forwarding state -👾 kernel | [ 7880.699662] br-805744f862c6: port 6(vethff5319a) entered blocking state -👾 kernel | [ 7880.699695] br-805744f862c6: port 6(vethff5319a) entered disabled state -👾 kernel | [ 7880.699729] vethff5319a: entered allmulticast mode -👾 kernel | [ 7880.699780] vethff5319a: entered promiscuous mode -👾 kernel | [ 7881.449080] eth1: renamed from veth72f6c44 -👾 kernel | [ 7881.450022] br-805744f862c6: port 6(vethff5319a) entered blocking state -👾 kernel | [ 7881.450062] br-805744f862c6: port 6(vethff5319a) entered forwarding state -👾 kernel | [ 7884.206751] br-d1f3e4394e37: port 11(veth2069cd2) entered blocking state -👾 kernel | [ 7884.206854] br-d1f3e4394e37: port 11(veth2069cd2) entered disabled state -👾 kernel | [ 7884.206873] veth2069cd2: entered allmulticast mode -👾 kernel | [ 7884.206915] veth2069cd2: entered promiscuous mode -👾 kernel | [ 7884.891246] eth0: renamed from vethaecc3e5 -👾 kernel | [ 7884.891797] br-d1f3e4394e37: port 11(veth2069cd2) entered blocking state -👾 kernel | [ 7884.891830] br-d1f3e4394e37: port 11(veth2069cd2) entered forwarding state -👾 kernel | [ 7884.915805] br-805744f862c6: port 9(vethd38b01a) entered blocking state -👾 kernel | [ 7884.915862] br-805744f862c6: port 9(vethd38b01a) entered disabled state -👾 kernel | [ 7884.915885] vethd38b01a: entered allmulticast mode -👾 kernel | [ 7884.915941] vethd38b01a: entered promiscuous mode -👾 kernel | [ 7885.373109] eth1: renamed from veth8f3da83 -👾 kernel | [ 7885.374367] br-805744f862c6: port 9(vethd38b01a) entered blocking state -👾 kernel | [ 7885.374389] br-805744f862c6: port 9(vethd38b01a) entered forwarding state -👾 kernel | [ 7886.987884] br-d1f3e4394e37: port 12(veth8736fce) entered blocking state -👾 kernel | [ 7886.987916] br-d1f3e4394e37: port 12(veth8736fce) entered disabled state -👾 kernel | [ 7886.987939] veth8736fce: entered allmulticast mode -👾 kernel | [ 7886.987982] veth8736fce: entered promiscuous mode -👾 kernel | [ 7887.159208] br-805744f862c6: port 10(vethe0894ec) entered blocking state -👾 kernel | [ 7887.159253] br-805744f862c6: port 10(vethe0894ec) entered disabled state -👾 kernel | [ 7887.159284] vethe0894ec: entered allmulticast mode -👾 kernel | [ 7887.159336] vethe0894ec: entered promiscuous mode -👾 kernel | [ 7887.188151] eth0: renamed from veth3e524ab -👾 kernel | [ 7887.189120] br-d1f3e4394e37: port 12(veth8736fce) entered blocking state -👾 kernel | [ 7887.189175] br-d1f3e4394e37: port 12(veth8736fce) entered forwarding state -👾 kernel | [ 7887.205522] eth0: renamed from veth076f92d -👾 kernel | [ 7887.206266] br-805744f862c6: port 10(vethe0894ec) entered blocking state -👾 kernel | [ 7887.206302] br-805744f862c6: port 10(vethe0894ec) entered forwarding state -👾 kernel | [ 7887.364175] br-805744f862c6: port 11(veth5fb3f10) entered blocking state -👾 kernel | [ 7887.364266] br-805744f862c6: port 11(veth5fb3f10) entered disabled state -👾 kernel | [ 7887.364293] veth5fb3f10: entered allmulticast mode -👾 kernel | [ 7887.364349] veth5fb3f10: entered promiscuous mode -👾 kernel | [ 7887.601268] br-d1f3e4394e37: port 13(veth2b0d253) entered blocking state -👾 kernel | [ 7887.601301] br-d1f3e4394e37: port 13(veth2b0d253) entered disabled state -👾 kernel | [ 7887.601318] veth2b0d253: entered allmulticast mode -👾 kernel | [ 7887.601369] veth2b0d253: entered promiscuous mode -👾 kernel | [ 7887.854053] eth1: renamed from veth759db7f -👾 kernel | [ 7887.858530] br-805744f862c6: port 11(veth5fb3f10) entered blocking state -👾 kernel | [ 7887.858554] br-805744f862c6: port 11(veth5fb3f10) entered forwarding state -👾 kernel | [ 7887.859071] eth1: renamed from veth69f0c7f -👾 kernel | [ 7887.862906] br-d1f3e4394e37: port 13(veth2b0d253) entered blocking state -👾 kernel | [ 7887.862928] br-d1f3e4394e37: port 13(veth2b0d253) entered forwarding state -📦 scon | time="01-14 02:32:47" level=info msg="remove forward" key="tcp:0.0.0.0:6333" -📦 scon | time="01-14 02:32:47" level=info msg="remove forward" key="tcp:[::]:6333" -👾 kernel | [ 8055.592464] br-805744f862c6: port 4(vethded7e18) entered disabled state -👾 kernel | [ 8055.592640] veth21fca2f: renamed from eth0 -👾 kernel | [ 8055.722426] br-d1f3e4394e37: port 13(veth2b0d253) entered disabled state -👾 kernel | [ 8055.722533] veth69f0c7f: renamed from eth1 -👾 kernel | [ 8056.399963] br-805744f862c6: port 4(vethded7e18) entered disabled state -👾 kernel | [ 8056.400502] vethded7e18 (unregistering): left allmulticast mode -👾 kernel | [ 8056.400521] vethded7e18 (unregistering): left promiscuous mode -👾 kernel | [ 8056.400533] br-805744f862c6: port 4(vethded7e18) entered disabled state -👾 kernel | [ 8056.783945] br-d1f3e4394e37: port 7(vethee0e368) entered disabled state -👾 kernel | [ 8056.784008] vethb73eebe: renamed from eth0 -👾 kernel | [ 8057.032556] br-d1f3e4394e37: port 13(veth2b0d253) entered disabled state -👾 kernel | [ 8057.033296] veth2b0d253 (unregistering): left allmulticast mode -👾 kernel | [ 8057.033315] veth2b0d253 (unregistering): left promiscuous mode -👾 kernel | [ 8057.033327] br-d1f3e4394e37: port 13(veth2b0d253) entered disabled state -👾 kernel | [ 8057.458403] br-d1f3e4394e37: port 12(veth8736fce) entered disabled state -👾 kernel | [ 8057.458828] veth3e524ab: renamed from eth0 -👾 kernel | [ 8058.332960] br-d1f3e4394e37: port 7(vethee0e368) entered disabled state -👾 kernel | [ 8058.333911] vethee0e368 (unregistering): left allmulticast mode -👾 kernel | [ 8058.333938] vethee0e368 (unregistering): left promiscuous mode -👾 kernel | [ 8058.333957] br-d1f3e4394e37: port 7(vethee0e368) entered disabled state -👾 kernel | [ 8058.339597] br-d1f3e4394e37: port 6(vethfbeb5b8) entered disabled state -👾 kernel | [ 8058.339672] vethd9e79b2: renamed from eth0 -👾 kernel | [ 8058.623559] br-805744f862c6: port 10(vethe0894ec) entered disabled state -👾 kernel | [ 8058.623655] veth076f92d: renamed from eth0 -👾 kernel | [ 8058.945327] br-d1f3e4394e37: port 12(veth8736fce) entered disabled state -👾 kernel | [ 8058.946087] veth8736fce (unregistering): left allmulticast mode -👾 kernel | [ 8058.946112] veth8736fce (unregistering): left promiscuous mode -👾 kernel | [ 8058.946152] br-d1f3e4394e37: port 12(veth8736fce) entered disabled state -👾 kernel | [ 8059.190523] br-805744f862c6: port 8(veth81252de) entered disabled state -👾 kernel | [ 8059.190925] vethf8cd222: renamed from eth1 -👾 kernel | [ 8059.585225] br-d1f3e4394e37: port 6(vethfbeb5b8) entered disabled state -👾 kernel | [ 8059.586250] vethfbeb5b8 (unregistering): left allmulticast mode -👾 kernel | [ 8059.586274] vethfbeb5b8 (unregistering): left promiscuous mode -👾 kernel | [ 8059.586288] br-d1f3e4394e37: port 6(vethfbeb5b8) entered disabled state -👾 kernel | [ 8059.740456] br-805744f862c6: port 10(vethe0894ec) entered disabled state -👾 kernel | [ 8059.741188] vethe0894ec (unregistering): left allmulticast mode -👾 kernel | [ 8059.741216] vethe0894ec (unregistering): left promiscuous mode -👾 kernel | [ 8059.741230] br-805744f862c6: port 10(vethe0894ec) entered disabled state -👾 kernel | [ 8059.858338] br-805744f862c6: port 8(veth81252de) entered disabled state -👾 kernel | [ 8059.859277] veth81252de (unregistering): left allmulticast mode -👾 kernel | [ 8059.859297] veth81252de (unregistering): left promiscuous mode -👾 kernel | [ 8059.859312] br-805744f862c6: port 8(veth81252de) entered disabled state -👾 kernel | [ 8059.941615] br-805744f862c6: port 7(vetha2f3f6c) entered disabled state -👾 kernel | [ 8059.941801] veth4168d4c: renamed from eth1 -👾 kernel | [ 8060.193105] br-805744f862c6: port 11(veth5fb3f10) entered disabled state -👾 kernel | [ 8060.193329] veth759db7f: renamed from eth1 -👾 kernel | [ 8060.228869] br-805744f862c6: port 7(vetha2f3f6c) entered disabled state -👾 kernel | [ 8060.229420] vetha2f3f6c (unregistering): left allmulticast mode -👾 kernel | [ 8060.229435] vetha2f3f6c (unregistering): left promiscuous mode -👾 kernel | [ 8060.229445] br-805744f862c6: port 7(vetha2f3f6c) entered disabled state -👾 kernel | [ 8060.345992] br-805744f862c6: port 11(veth5fb3f10) entered disabled state -👾 kernel | [ 8060.346940] veth5fb3f10 (unregistering): left allmulticast mode -👾 kernel | [ 8060.346973] veth5fb3f10 (unregistering): left promiscuous mode -👾 kernel | [ 8060.346997] br-805744f862c6: port 11(veth5fb3f10) entered disabled state -👾 kernel | [ 8062.164766] br-d1f3e4394e37: port 11(veth2069cd2) entered disabled state -👾 kernel | [ 8062.164935] vethaecc3e5: renamed from eth0 -👾 kernel | [ 8062.740578] br-d1f3e4394e37: port 11(veth2069cd2) entered disabled state -👾 kernel | [ 8062.741252] veth2069cd2 (unregistering): left allmulticast mode -👾 kernel | [ 8062.741284] veth2069cd2 (unregistering): left promiscuous mode -👾 kernel | [ 8062.741302] br-d1f3e4394e37: port 11(veth2069cd2) entered disabled state -👾 kernel | [ 8063.003367] br-805744f862c6: port 9(vethd38b01a) entered disabled state -👾 kernel | [ 8063.003469] veth8f3da83: renamed from eth1 -👾 kernel | [ 8063.917164] br-805744f862c6: port 9(vethd38b01a) entered disabled state -👾 kernel | [ 8063.917861] vethd38b01a (unregistering): left allmulticast mode -👾 kernel | [ 8063.917888] vethd38b01a (unregistering): left promiscuous mode -👾 kernel | [ 8063.917906] br-805744f862c6: port 9(vethd38b01a) entered disabled state -👾 kernel | [ 8065.318274] br-d1f3e4394e37: port 5(vethd32149a) entered disabled state -👾 kernel | [ 8065.318371] veth5c9b989: renamed from eth0 -👾 kernel | [ 8065.344483] veth60bcb15: renamed from eth1 -👾 kernel | [ 8065.344750] br-d1f3e4394e37: port 8(veth62d12d5) entered disabled state -👾 kernel | [ 8065.384806] vethe8931bf: renamed from eth1 -👾 kernel | [ 8065.385011] br-d1f3e4394e37: port 10(veth8587586) entered disabled state -👾 kernel | [ 8065.385077] br-d1f3e4394e37: port 9(veth73864c3) entered disabled state -👾 kernel | [ 8065.429805] veth86599c6: renamed from eth0 -👾 kernel | [ 8065.450533] br-d1f3e4394e37: port 5(vethd32149a) entered disabled state -👾 kernel | [ 8065.451213] vethd32149a (unregistering): left allmulticast mode -👾 kernel | [ 8065.451241] vethd32149a (unregistering): left promiscuous mode -👾 kernel | [ 8065.451255] br-d1f3e4394e37: port 5(vethd32149a) entered disabled state -👾 kernel | [ 8065.502316] br-d1f3e4394e37: port 9(veth73864c3) entered disabled state -👾 kernel | [ 8065.502851] veth73864c3 (unregistering): left allmulticast mode -👾 kernel | [ 8065.502882] veth73864c3 (unregistering): left promiscuous mode -👾 kernel | [ 8065.502904] br-d1f3e4394e37: port 9(veth73864c3) entered disabled state -👾 kernel | [ 8065.527236] br-d1f3e4394e37: port 8(veth62d12d5) entered disabled state -👾 kernel | [ 8065.527545] veth62d12d5 (unregistering): left allmulticast mode -👾 kernel | [ 8065.527635] veth62d12d5 (unregistering): left promiscuous mode -👾 kernel | [ 8065.527666] br-d1f3e4394e37: port 8(veth62d12d5) entered disabled state -👾 kernel | [ 8065.550210] br-805744f862c6: port 1(veth91c050f) entered disabled state -👾 kernel | [ 8065.550347] veth099792d: renamed from eth1 -👾 kernel | [ 8065.573973] br-d1f3e4394e37: port 10(veth8587586) entered disabled state -👾 kernel | [ 8065.574601] veth8587586 (unregistering): left allmulticast mode -👾 kernel | [ 8065.574632] veth8587586 (unregistering): left promiscuous mode -👾 kernel | [ 8065.574650] br-d1f3e4394e37: port 10(veth8587586) entered disabled state -👾 kernel | [ 8065.574913] br-805744f862c6: port 3(veth1a4c2e8) entered disabled state -👾 kernel | [ 8065.574968] br-805744f862c6: port 2(vethf2cae25) entered disabled state -👾 kernel | [ 8065.575051] vethb61731d: renamed from eth0 -👾 kernel | [ 8065.575275] vethb3fac7b: renamed from eth0 -👾 kernel | [ 8065.633180] br-805744f862c6: port 6(vethff5319a) entered disabled state -👾 kernel | [ 8065.633465] br-805744f862c6: port 1(veth91c050f) entered disabled state -👾 kernel | [ 8065.634186] veth91c050f (unregistering): left allmulticast mode -👾 kernel | [ 8065.634208] veth91c050f (unregistering): left promiscuous mode -👾 kernel | [ 8065.634230] br-805744f862c6: port 1(veth91c050f) entered disabled state -👾 kernel | [ 8065.634359] veth72f6c44: renamed from eth1 -👾 kernel | [ 8065.667126] br-805744f862c6: port 2(vethf2cae25) entered disabled state -👾 kernel | [ 8065.667912] vethf2cae25 (unregistering): left allmulticast mode -👾 kernel | [ 8065.667947] vethf2cae25 (unregistering): left promiscuous mode -👾 kernel | [ 8065.667967] br-805744f862c6: port 2(vethf2cae25) entered disabled state -👾 kernel | [ 8065.695487] br-805744f862c6: port 3(veth1a4c2e8) entered disabled state -👾 kernel | [ 8065.696138] veth1a4c2e8 (unregistering): left allmulticast mode -👾 kernel | [ 8065.696162] veth1a4c2e8 (unregistering): left promiscuous mode -👾 kernel | [ 8065.696174] br-805744f862c6: port 3(veth1a4c2e8) entered disabled state -👾 kernel | [ 8065.756269] br-805744f862c6: port 6(vethff5319a) entered disabled state -👾 kernel | [ 8065.756652] vethff5319a (unregistering): left allmulticast mode -👾 kernel | [ 8065.756682] vethff5319a (unregistering): left promiscuous mode -👾 kernel | [ 8065.756698] br-805744f862c6: port 6(vethff5319a) entered disabled state -👾 kernel | [ 8066.914642] br-805744f862c6: port 5(veth07a6a4a) entered disabled state -👾 kernel | [ 8066.914824] veth7794f34: renamed from eth0 -👾 kernel | [ 8067.002001] br-805744f862c6: port 5(veth07a6a4a) entered disabled state -👾 kernel | [ 8067.002586] veth07a6a4a (unregistering): left allmulticast mode -👾 kernel | [ 8067.002622] veth07a6a4a (unregistering): left promiscuous mode -👾 kernel | [ 8067.002634] br-805744f862c6: port 5(veth07a6a4a) entered disabled state -🌸 agent:docker | time="01-13 21:32:59" level=info msg="removing network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-805744f862c6}" name=omega_default -👾 kernel | [ 8074.323192] br-1f640fda3d7c: port 1(veth0c65c53) entered blocking state -👾 kernel | [ 8074.323236] br-1f640fda3d7c: port 1(veth0c65c53) entered disabled state -👾 kernel | [ 8074.323255] veth0c65c53: entered allmulticast mode -👾 kernel | [ 8074.323302] veth0c65c53: entered promiscuous mode -👾 kernel | [ 8074.475064] eth0: renamed from veth99a3876 -👾 kernel | [ 8074.475771] br-1f640fda3d7c: port 1(veth0c65c53) entered blocking state -👾 kernel | [ 8074.475812] br-1f640fda3d7c: port 1(veth0c65c53) entered forwarding state -👾 kernel | [ 8074.634146] br-d1f3e4394e37: port 5(vethb5ca815) entered blocking state -👾 kernel | [ 8074.634177] br-d1f3e4394e37: port 5(vethb5ca815) entered disabled state -👾 kernel | [ 8074.634199] vethb5ca815: entered allmulticast mode -👾 kernel | [ 8074.634245] vethb5ca815: entered promiscuous mode -🌸 agent:docker | time="01-13 21:33:07" level=info msg="adding network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-1f640fda3d7c}" name=omega_default -👾 kernel | [ 8074.650571] br-d1f3e4394e37: port 6(vethe2a5ac8) entered blocking state -👾 kernel | [ 8074.650612] br-d1f3e4394e37: port 6(vethe2a5ac8) entered disabled state -👾 kernel | [ 8074.650655] vethe2a5ac8: entered allmulticast mode -👾 kernel | [ 8074.650710] vethe2a5ac8: entered promiscuous mode -👾 kernel | [ 8074.758246] eth0: renamed from vetha405749 -👾 kernel | [ 8074.758744] br-d1f3e4394e37: port 5(vethb5ca815) entered blocking state -👾 kernel | [ 8074.758763] br-d1f3e4394e37: port 5(vethb5ca815) entered forwarding state -👾 kernel | [ 8074.928988] br-1f640fda3d7c: port 2(veth366f8c4) entered blocking state -👾 kernel | [ 8074.929035] br-1f640fda3d7c: port 2(veth366f8c4) entered disabled state -👾 kernel | [ 8074.929062] veth366f8c4: entered allmulticast mode -👾 kernel | [ 8074.929185] veth366f8c4: entered promiscuous mode -👾 kernel | [ 8074.952849] eth1: renamed from veth3e11ba1 -👾 kernel | [ 8074.956992] br-d1f3e4394e37: port 6(vethe2a5ac8) entered blocking state -👾 kernel | [ 8074.957031] br-d1f3e4394e37: port 6(vethe2a5ac8) entered forwarding state -👾 kernel | [ 8075.451119] br-d1f3e4394e37: port 7(vetheba2816) entered blocking state -👾 kernel | [ 8075.451161] br-d1f3e4394e37: port 7(vetheba2816) entered disabled state -👾 kernel | [ 8075.451183] vetheba2816: entered allmulticast mode -👾 kernel | [ 8075.451230] vetheba2816: entered promiscuous mode -👾 kernel | [ 8075.451509] br-1f640fda3d7c: port 3(vethc2b9b37) entered blocking state -👾 kernel | [ 8075.451546] br-1f640fda3d7c: port 3(vethc2b9b37) entered disabled state -👾 kernel | [ 8075.451613] vethc2b9b37: entered allmulticast mode -👾 kernel | [ 8075.451753] vethc2b9b37: entered promiscuous mode -🌸 agent:docker | time="01-13 21:33:08" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -🌸 agent:docker | time="01-13 21:33:08" level=error msg="failed to refresh networks" error="list links: results may be incomplete or inconsistent" -👾 kernel | [ 8075.463175] eth0: renamed from vethfe1dfa2 -👾 kernel | [ 8075.464053] br-1f640fda3d7c: port 2(veth366f8c4) entered blocking state -👾 kernel | [ 8075.464092] br-1f640fda3d7c: port 2(veth366f8c4) entered forwarding state -👾 kernel | [ 8075.473108] br-d1f3e4394e37: port 8(vethc8c3b5f) entered blocking state -👾 kernel | [ 8075.473142] br-d1f3e4394e37: port 8(vethc8c3b5f) entered disabled state -👾 kernel | [ 8075.473165] vethc8c3b5f: entered allmulticast mode -👾 kernel | [ 8075.473219] vethc8c3b5f: entered promiscuous mode -👾 kernel | [ 8075.549988] br-1f640fda3d7c: port 4(veth0040701) entered blocking state -👾 kernel | [ 8075.550032] br-1f640fda3d7c: port 4(veth0040701) entered disabled state -👾 kernel | [ 8075.550053] veth0040701: entered allmulticast mode -👾 kernel | [ 8075.550175] veth0040701: entered promiscuous mode -📦 scon | time="01-14 02:33:08" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:6333" -📦 scon | time="01-14 02:33:08" level=info msg="add forward" container=docker spec="tcp:[::]:6333" -👾 kernel | [ 8075.583072] eth0: renamed from veth18dead0 -👾 kernel | [ 8075.583748] br-d1f3e4394e37: port 7(vetheba2816) entered blocking state -👾 kernel | [ 8075.583787] br-d1f3e4394e37: port 7(vetheba2816) entered forwarding state -👾 kernel | [ 8075.632012] br-1f640fda3d7c: port 5(veth9813cc5) entered blocking state -👾 kernel | [ 8075.632086] br-1f640fda3d7c: port 5(veth9813cc5) entered disabled state -👾 kernel | [ 8075.632117] veth9813cc5: entered allmulticast mode -👾 kernel | [ 8075.632208] veth9813cc5: entered promiscuous mode -👾 kernel | [ 8075.654720] eth0: renamed from veth7f18f2f -👾 kernel | [ 8075.655072] eth0: renamed from vethe7b735c -👾 kernel | [ 8075.655303] br-1f640fda3d7c: port 3(vethc2b9b37) entered blocking state -👾 kernel | [ 8075.655334] br-1f640fda3d7c: port 3(vethc2b9b37) entered forwarding state -👾 kernel | [ 8075.655776] br-1f640fda3d7c: port 4(veth0040701) entered blocking state -👾 kernel | [ 8075.655799] br-1f640fda3d7c: port 4(veth0040701) entered forwarding state -👾 kernel | [ 8076.017236] eth0: renamed from veth52469ec -👾 kernel | [ 8076.017807] br-d1f3e4394e37: port 8(vethc8c3b5f) entered blocking state -👾 kernel | [ 8076.017826] br-d1f3e4394e37: port 8(vethc8c3b5f) entered forwarding state -👾 kernel | [ 8077.992550] br-1f640fda3d7c: port 6(veth46c47ad) entered blocking state -👾 kernel | [ 8077.992592] br-1f640fda3d7c: port 6(veth46c47ad) entered disabled state -👾 kernel | [ 8077.992607] veth46c47ad: entered allmulticast mode -👾 kernel | [ 8077.992664] veth46c47ad: entered promiscuous mode -👾 kernel | [ 8078.250180] eth1: renamed from veth559c676 -👾 kernel | [ 8078.252871] br-1f640fda3d7c: port 7(vethec23882) entered blocking state -👾 kernel | [ 8078.252901] br-1f640fda3d7c: port 7(vethec23882) entered disabled state -👾 kernel | [ 8078.252916] vethec23882: entered allmulticast mode -👾 kernel | [ 8078.252953] vethec23882: entered promiscuous mode -👾 kernel | [ 8078.255126] br-1f640fda3d7c: port 6(veth46c47ad) entered blocking state -👾 kernel | [ 8078.255167] br-1f640fda3d7c: port 6(veth46c47ad) entered forwarding state -👾 kernel | [ 8078.255231] br-d1f3e4394e37: port 9(vethf41651c) entered blocking state -👾 kernel | [ 8078.255263] br-d1f3e4394e37: port 9(vethf41651c) entered disabled state -👾 kernel | [ 8078.255278] vethf41651c: entered allmulticast mode -👾 kernel | [ 8078.255315] vethf41651c: entered promiscuous mode -👾 kernel | [ 8078.340126] eth0: renamed from veth0091085 -👾 kernel | [ 8078.340719] br-1f640fda3d7c: port 5(veth9813cc5) entered blocking state -👾 kernel | [ 8078.340751] br-1f640fda3d7c: port 5(veth9813cc5) entered forwarding state -👾 kernel | [ 8080.622567] eth1: renamed from veth4d3d5fa -👾 kernel | [ 8080.623304] br-1f640fda3d7c: port 8(veth48282c8) entered blocking state -👾 kernel | [ 8080.623332] br-1f640fda3d7c: port 8(veth48282c8) entered disabled state -👾 kernel | [ 8080.623358] veth48282c8: entered allmulticast mode -👾 kernel | [ 8080.623486] veth48282c8: entered promiscuous mode -👾 kernel | [ 8080.623584] br-d1f3e4394e37: port 9(vethf41651c) entered blocking state -👾 kernel | [ 8080.623613] br-d1f3e4394e37: port 9(vethf41651c) entered forwarding state -👾 kernel | [ 8080.624707] eth1: renamed from vethce6c87c -👾 kernel | [ 8080.631331] br-1f640fda3d7c: port 7(vethec23882) entered blocking state -👾 kernel | [ 8080.631363] br-1f640fda3d7c: port 7(vethec23882) entered forwarding state -👾 kernel | [ 8080.942037] br-1f640fda3d7c: port 3(vethc2b9b37) entered disabled state -👾 kernel | [ 8080.942377] veth7f18f2f: renamed from eth0 -👾 kernel | [ 8082.614141] br-1f640fda3d7c: port 3(vethc2b9b37) entered disabled state -👾 kernel | [ 8082.614923] vethc2b9b37 (unregistering): left allmulticast mode -👾 kernel | [ 8082.614949] vethc2b9b37 (unregistering): left promiscuous mode -👾 kernel | [ 8082.614976] br-1f640fda3d7c: port 3(vethc2b9b37) entered disabled state -👾 kernel | [ 8082.617473] eth1: renamed from veth13f9615 -👾 kernel | [ 8082.618253] br-1f640fda3d7c: port 8(veth48282c8) entered blocking state -👾 kernel | [ 8082.618276] br-1f640fda3d7c: port 8(veth48282c8) entered forwarding state -👾 kernel | [ 8084.140747] br-d1f3e4394e37: port 10(veth9f44cd4) entered blocking state -👾 kernel | [ 8084.140784] br-d1f3e4394e37: port 10(veth9f44cd4) entered disabled state -👾 kernel | [ 8084.140807] veth9f44cd4: entered allmulticast mode -👾 kernel | [ 8084.140854] veth9f44cd4: entered promiscuous mode -👾 kernel | [ 8084.310364] eth0: renamed from vethdcb9eeb -👾 kernel | [ 8084.314446] br-d1f3e4394e37: port 10(veth9f44cd4) entered blocking state -👾 kernel | [ 8084.314476] br-d1f3e4394e37: port 10(veth9f44cd4) entered forwarding state -🌸 agent:docker | time="01-13 21:33:17" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 8084.528925] br-1f640fda3d7c: port 3(veth696c6aa) entered blocking state -👾 kernel | [ 8084.528963] br-1f640fda3d7c: port 3(veth696c6aa) entered disabled state -👾 kernel | [ 8084.528994] veth696c6aa: entered allmulticast mode -👾 kernel | [ 8084.530027] veth696c6aa: entered promiscuous mode -👾 kernel | [ 8084.592973] eth1: renamed from vethebed719 -👾 kernel | [ 8084.671013] br-1f640fda3d7c: port 3(veth696c6aa) entered blocking state -👾 kernel | [ 8084.671053] br-1f640fda3d7c: port 3(veth696c6aa) entered forwarding state -👾 kernel | [ 8084.897013] br-d1f3e4394e37: port 11(veth7ce32ea) entered blocking state -👾 kernel | [ 8084.897060] br-d1f3e4394e37: port 11(veth7ce32ea) entered disabled state -👾 kernel | [ 8084.897084] veth7ce32ea: entered allmulticast mode -👾 kernel | [ 8084.897131] veth7ce32ea: entered promiscuous mode -👾 kernel | [ 8085.253118] eth0: renamed from veth4af7150 -👾 kernel | [ 8085.254051] br-d1f3e4394e37: port 11(veth7ce32ea) entered blocking state -👾 kernel | [ 8085.254082] br-d1f3e4394e37: port 11(veth7ce32ea) entered forwarding state -👾 kernel | [ 8085.350675] br-1f640fda3d7c: port 9(veth160e502) entered blocking state -👾 kernel | [ 8085.350710] br-1f640fda3d7c: port 9(veth160e502) entered disabled state -👾 kernel | [ 8085.350727] veth160e502: entered allmulticast mode -👾 kernel | [ 8085.350776] veth160e502: entered promiscuous mode -👾 kernel | [ 8085.426607] eth1: renamed from vetha2bea8e -👾 kernel | [ 8085.438723] br-1f640fda3d7c: port 9(veth160e502) entered blocking state -👾 kernel | [ 8085.438755] br-1f640fda3d7c: port 9(veth160e502) entered forwarding state -👾 kernel | [ 8086.335706] br-1f640fda3d7c: port 10(vethafcf843) entered blocking state -👾 kernel | [ 8086.335744] br-1f640fda3d7c: port 10(vethafcf843) entered disabled state -👾 kernel | [ 8086.335779] vethafcf843: entered allmulticast mode -👾 kernel | [ 8086.335836] vethafcf843: entered promiscuous mode -👾 kernel | [ 8086.402337] br-d1f3e4394e37: port 12(veth4878f56) entered blocking state -👾 kernel | [ 8086.402374] br-d1f3e4394e37: port 12(veth4878f56) entered disabled state -👾 kernel | [ 8086.402397] veth4878f56: entered allmulticast mode -👾 kernel | [ 8086.402444] veth4878f56: entered promiscuous mode -👾 kernel | [ 8086.457899] eth0: renamed from veth9d4b5ef -👾 kernel | [ 8086.466443] br-1f640fda3d7c: port 10(vethafcf843) entered blocking state -👾 kernel | [ 8086.466471] br-1f640fda3d7c: port 10(vethafcf843) entered forwarding state -👾 kernel | [ 8086.547231] br-d1f3e4394e37: port 13(veth9ac84f7) entered blocking state -👾 kernel | [ 8086.547271] br-d1f3e4394e37: port 13(veth9ac84f7) entered disabled state -👾 kernel | [ 8086.547290] veth9ac84f7: entered allmulticast mode -👾 kernel | [ 8086.547340] veth9ac84f7: entered promiscuous mode -👾 kernel | [ 8086.585109] eth1: renamed from vethc74e08e -👾 kernel | [ 8086.591594] br-d1f3e4394e37: port 13(veth9ac84f7) entered blocking state -👾 kernel | [ 8086.591629] br-d1f3e4394e37: port 13(veth9ac84f7) entered forwarding state -👾 kernel | [ 8086.594541] eth0: renamed from veth44c922c -👾 kernel | [ 8086.595724] br-d1f3e4394e37: port 12(veth4878f56) entered blocking state -👾 kernel | [ 8086.595751] br-d1f3e4394e37: port 12(veth4878f56) entered forwarding state -👾 kernel | [ 8087.047928] br-1f640fda3d7c: port 11(vethc70f322) entered blocking state -👾 kernel | [ 8087.047972] br-1f640fda3d7c: port 11(vethc70f322) entered disabled state -👾 kernel | [ 8087.048022] vethc70f322: entered allmulticast mode -👾 kernel | [ 8087.048091] vethc70f322: entered promiscuous mode -👾 kernel | [ 8087.169525] eth1: renamed from vethad31555 -👾 kernel | [ 8087.183931] br-1f640fda3d7c: port 11(vethc70f322) entered blocking state -👾 kernel | [ 8087.183963] br-1f640fda3d7c: port 11(vethc70f322) entered forwarding state -📦 scon | time="01-14 02:42:28" level=info msg="remove forward" key="tcp:0.0.0.0:6333" -👾 kernel | [ 8636.045964] br-1f640fda3d7c: port 2(veth366f8c4) entered disabled state -👾 kernel | [ 8636.046037] vethfe1dfa2: renamed from eth0 -📦 scon | time="01-14 02:42:28" level=info msg="remove forward" key="tcp:[::]:6333" -👾 kernel | [ 8636.517608] br-1f640fda3d7c: port 2(veth366f8c4) entered disabled state -👾 kernel | [ 8636.518552] veth366f8c4 (unregistering): left allmulticast mode -👾 kernel | [ 8636.518623] veth366f8c4 (unregistering): left promiscuous mode -👾 kernel | [ 8636.518661] br-1f640fda3d7c: port 2(veth366f8c4) entered disabled state -👾 kernel | [ 8636.682277] br-d1f3e4394e37: port 8(vethc8c3b5f) entered disabled state -👾 kernel | [ 8636.682688] veth52469ec: renamed from eth0 -👾 kernel | [ 8637.257714] br-d1f3e4394e37: port 8(vethc8c3b5f) entered disabled state -👾 kernel | [ 8637.258792] vethc8c3b5f (unregistering): left allmulticast mode -👾 kernel | [ 8637.258815] vethc8c3b5f (unregistering): left promiscuous mode -👾 kernel | [ 8637.258825] br-d1f3e4394e37: port 8(vethc8c3b5f) entered disabled state -👾 kernel | [ 8637.696090] br-d1f3e4394e37: port 13(veth9ac84f7) entered disabled state -👾 kernel | [ 8637.696459] vethc74e08e: renamed from eth1 -👾 kernel | [ 8638.243259] veth13f9615: renamed from eth1 -👾 kernel | [ 8638.243665] br-1f640fda3d7c: port 8(veth48282c8) entered disabled state -👾 kernel | [ 8638.324203] br-d1f3e4394e37: port 13(veth9ac84f7) entered disabled state -👾 kernel | [ 8638.331318] veth9ac84f7 (unregistering): left allmulticast mode -👾 kernel | [ 8638.331382] veth9ac84f7 (unregistering): left promiscuous mode -👾 kernel | [ 8638.331399] br-d1f3e4394e37: port 13(veth9ac84f7) entered disabled state -👾 kernel | [ 8638.335791] br-d1f3e4394e37: port 12(veth4878f56) entered disabled state -👾 kernel | [ 8638.336088] veth44c922c: renamed from eth0 -👾 kernel | [ 8638.428292] veth3e11ba1: renamed from eth1 -👾 kernel | [ 8638.428740] br-d1f3e4394e37: port 6(vethe2a5ac8) entered disabled state -👾 kernel | [ 8638.440739] br-1f640fda3d7c: port 8(veth48282c8) entered disabled state -👾 kernel | [ 8638.444315] veth48282c8 (unregistering): left allmulticast mode -👾 kernel | [ 8638.444397] veth48282c8 (unregistering): left promiscuous mode -👾 kernel | [ 8638.448019] br-1f640fda3d7c: port 8(veth48282c8) entered disabled state -👾 kernel | [ 8638.456716] br-1f640fda3d7c: port 10(vethafcf843) entered disabled state -👾 kernel | [ 8638.456799] veth9d4b5ef: renamed from eth0 -👾 kernel | [ 8638.872020] br-d1f3e4394e37: port 12(veth4878f56) entered disabled state -👾 kernel | [ 8638.872545] veth4878f56 (unregistering): left allmulticast mode -👾 kernel | [ 8638.872562] veth4878f56 (unregistering): left promiscuous mode -👾 kernel | [ 8638.872572] br-d1f3e4394e37: port 12(veth4878f56) entered disabled state -👾 kernel | [ 8640.363674] br-d1f3e4394e37: port 6(vethe2a5ac8) entered disabled state -👾 kernel | [ 8640.364610] vethe2a5ac8 (unregistering): left allmulticast mode -👾 kernel | [ 8640.364647] vethe2a5ac8 (unregistering): left promiscuous mode -👾 kernel | [ 8640.364669] br-d1f3e4394e37: port 6(vethe2a5ac8) entered disabled state -👾 kernel | [ 8640.553365] br-1f640fda3d7c: port 10(vethafcf843) entered disabled state -👾 kernel | [ 8640.554588] vethafcf843 (unregistering): left allmulticast mode -👾 kernel | [ 8640.554613] vethafcf843 (unregistering): left promiscuous mode -👾 kernel | [ 8640.554627] br-1f640fda3d7c: port 10(vethafcf843) entered disabled state -👾 kernel | [ 8640.713688] br-1f640fda3d7c: port 11(vethc70f322) entered disabled state -👾 kernel | [ 8640.713775] vethad31555: renamed from eth1 -👾 kernel | [ 8641.445178] br-1f640fda3d7c: port 1(veth0c65c53) entered disabled state -👾 kernel | [ 8641.445276] veth99a3876: renamed from eth0 -👾 kernel | [ 8641.713533] br-1f640fda3d7c: port 11(vethc70f322) entered disabled state -👾 kernel | [ 8641.714718] vethc70f322 (unregistering): left allmulticast mode -👾 kernel | [ 8641.714733] vethc70f322 (unregistering): left promiscuous mode -👾 kernel | [ 8641.714744] br-1f640fda3d7c: port 11(vethc70f322) entered disabled state -👾 kernel | [ 8642.236911] br-1f640fda3d7c: port 1(veth0c65c53) entered disabled state -👾 kernel | [ 8642.237637] veth0c65c53 (unregistering): left allmulticast mode -👾 kernel | [ 8642.237661] veth0c65c53 (unregistering): left promiscuous mode -👾 kernel | [ 8642.237678] br-1f640fda3d7c: port 1(veth0c65c53) entered disabled state -👾 kernel | [ 8644.010194] br-d1f3e4394e37: port 11(veth7ce32ea) entered disabled state -👾 kernel | [ 8644.010326] veth4af7150: renamed from eth0 -👾 kernel | [ 8645.062185] br-d1f3e4394e37: port 11(veth7ce32ea) entered disabled state -👾 kernel | [ 8645.062917] veth7ce32ea (unregistering): left allmulticast mode -👾 kernel | [ 8645.062951] veth7ce32ea (unregistering): left promiscuous mode -👾 kernel | [ 8645.062973] br-d1f3e4394e37: port 11(veth7ce32ea) entered disabled state -👾 kernel | [ 8645.569366] br-1f640fda3d7c: port 9(veth160e502) entered disabled state -👾 kernel | [ 8645.569567] vetha2bea8e: renamed from eth1 -👾 kernel | [ 8645.985076] br-1f640fda3d7c: port 9(veth160e502) entered disabled state -👾 kernel | [ 8645.985675] veth160e502 (unregistering): left allmulticast mode -👾 kernel | [ 8645.985701] veth160e502 (unregistering): left promiscuous mode -👾 kernel | [ 8645.985722] br-1f640fda3d7c: port 9(veth160e502) entered disabled state -👾 kernel | [ 8646.323237] br-d1f3e4394e37: port 5(vethb5ca815) entered disabled state -👾 kernel | [ 8646.323337] vetha405749: renamed from eth0 -👾 kernel | [ 8646.503602] br-d1f3e4394e37: port 9(vethf41651c) entered disabled state -👾 kernel | [ 8646.503686] veth4d3d5fa: renamed from eth1 -👾 kernel | [ 8646.665256] br-d1f3e4394e37: port 7(vetheba2816) entered disabled state -👾 kernel | [ 8646.665374] veth18dead0: renamed from eth0 -👾 kernel | [ 8646.812071] br-d1f3e4394e37: port 5(vethb5ca815) entered disabled state -👾 kernel | [ 8646.813436] vethb5ca815 (unregistering): left allmulticast mode -👾 kernel | [ 8646.813460] vethb5ca815 (unregistering): left promiscuous mode -👾 kernel | [ 8646.813472] br-d1f3e4394e37: port 5(vethb5ca815) entered disabled state -👾 kernel | [ 8646.828469] br-d1f3e4394e37: port 10(veth9f44cd4) entered disabled state -👾 kernel | [ 8646.828657] vethdcb9eeb: renamed from eth0 -👾 kernel | [ 8646.851879] br-d1f3e4394e37: port 9(vethf41651c) entered disabled state -👾 kernel | [ 8646.852659] vethf41651c (unregistering): left allmulticast mode -👾 kernel | [ 8646.852687] vethf41651c (unregistering): left promiscuous mode -👾 kernel | [ 8646.852708] br-d1f3e4394e37: port 9(vethf41651c) entered disabled state -👾 kernel | [ 8646.894939] br-d1f3e4394e37: port 7(vetheba2816) entered disabled state -👾 kernel | [ 8646.895639] vetheba2816 (unregistering): left allmulticast mode -👾 kernel | [ 8646.895667] vetheba2816 (unregistering): left promiscuous mode -👾 kernel | [ 8646.895692] br-d1f3e4394e37: port 7(vetheba2816) entered disabled state -👾 kernel | [ 8646.905053] br-1f640fda3d7c: port 6(veth46c47ad) entered disabled state -👾 kernel | [ 8646.905161] veth559c676: renamed from eth1 -👾 kernel | [ 8646.971843] br-d1f3e4394e37: port 10(veth9f44cd4) entered disabled state -👾 kernel | [ 8646.972726] veth9f44cd4 (unregistering): left allmulticast mode -👾 kernel | [ 8646.972753] veth9f44cd4 (unregistering): left promiscuous mode -👾 kernel | [ 8646.972768] br-d1f3e4394e37: port 10(veth9f44cd4) entered disabled state -👾 kernel | [ 8646.974121] br-1f640fda3d7c: port 7(vethec23882) entered disabled state -👾 kernel | [ 8646.974184] vethce6c87c: renamed from eth1 -👾 kernel | [ 8647.007992] br-1f640fda3d7c: port 6(veth46c47ad) entered disabled state -👾 kernel | [ 8647.008773] veth46c47ad (unregistering): left allmulticast mode -👾 kernel | [ 8647.008820] veth46c47ad (unregistering): left promiscuous mode -👾 kernel | [ 8647.008835] br-1f640fda3d7c: port 6(veth46c47ad) entered disabled state -👾 kernel | [ 8647.010971] br-1f640fda3d7c: port 4(veth0040701) entered disabled state -👾 kernel | [ 8647.011142] vethe7b735c: renamed from eth0 -👾 kernel | [ 8647.011935] br-1f640fda3d7c: port 3(veth696c6aa) entered disabled state -👾 kernel | [ 8647.065122] br-1f640fda3d7c: port 7(vethec23882) entered disabled state -👾 kernel | [ 8647.065879] vethec23882 (unregistering): left allmulticast mode -👾 kernel | [ 8647.065927] vethec23882 (unregistering): left promiscuous mode -👾 kernel | [ 8647.065944] br-1f640fda3d7c: port 7(vethec23882) entered disabled state -👾 kernel | [ 8647.066254] vethebed719: renamed from eth1 -👾 kernel | [ 8647.121035] br-1f640fda3d7c: port 4(veth0040701) entered disabled state -👾 kernel | [ 8647.121647] veth0040701 (unregistering): left allmulticast mode -👾 kernel | [ 8647.121675] veth0040701 (unregistering): left promiscuous mode -👾 kernel | [ 8647.121704] br-1f640fda3d7c: port 4(veth0040701) entered disabled state -👾 kernel | [ 8647.370271] br-1f640fda3d7c: port 3(veth696c6aa) entered disabled state -👾 kernel | [ 8647.371280] veth696c6aa (unregistering): left allmulticast mode -👾 kernel | [ 8647.371316] veth696c6aa (unregistering): left promiscuous mode -👾 kernel | [ 8647.371378] br-1f640fda3d7c: port 3(veth696c6aa) entered disabled state -👾 kernel | [ 8648.569954] br-1f640fda3d7c: port 5(veth9813cc5) entered disabled state -👾 kernel | [ 8648.570059] veth0091085: renamed from eth0 -👾 kernel | [ 8648.600913] br-1f640fda3d7c: port 5(veth9813cc5) entered disabled state -👾 kernel | [ 8648.601481] veth9813cc5 (unregistering): left allmulticast mode -👾 kernel | [ 8648.601527] veth9813cc5 (unregistering): left promiscuous mode -👾 kernel | [ 8648.601542] br-1f640fda3d7c: port 5(veth9813cc5) entered disabled state -🌸 agent:docker | time="01-13 21:42:41" level=info msg="removing network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-1f640fda3d7c}" name=omega_default -👾 kernel | [ 8678.794727] docker0: port 1(veth0ced42e) entered blocking state -👾 kernel | [ 8678.794765] docker0: port 1(veth0ced42e) entered disabled state -👾 kernel | [ 8678.794783] veth0ced42e: entered allmulticast mode -👾 kernel | [ 8678.794871] veth0ced42e: entered promiscuous mode -👾 kernel | [ 8678.990212] eth0: renamed from veth12bd97c -👾 kernel | [ 8678.990772] docker0: port 1(veth0ced42e) entered blocking state -👾 kernel | [ 8678.990850] docker0: port 1(veth0ced42e) entered forwarding state -👾 kernel | [ 8840.914248] docker0: port 1(veth0ced42e) entered disabled state -👾 kernel | [ 8840.914414] veth12bd97c: renamed from eth0 -👾 kernel | [ 8840.986397] docker0: port 1(veth0ced42e) entered disabled state -👾 kernel | [ 8840.987054] veth0ced42e (unregistering): left allmulticast mode -👾 kernel | [ 8840.987087] veth0ced42e (unregistering): left promiscuous mode -👾 kernel | [ 8840.987104] docker0: port 1(veth0ced42e) entered disabled state -👾 kernel | [ 8841.321062] docker0: port 1(veth49abba5) entered blocking state -👾 kernel | [ 8841.321104] docker0: port 1(veth49abba5) entered disabled state -👾 kernel | [ 8841.321152] veth49abba5: entered allmulticast mode -👾 kernel | [ 8841.321211] veth49abba5: entered promiscuous mode -👾 kernel | [ 8841.424156] eth0: renamed from vethcf2233a -👾 kernel | [ 8841.424611] docker0: port 1(veth49abba5) entered blocking state -👾 kernel | [ 8841.424659] docker0: port 1(veth49abba5) entered forwarding state -👾 kernel | [ 9200.275376] docker0: port 1(veth49abba5) entered disabled state -👾 kernel | [ 9200.275505] vethcf2233a: renamed from eth0 -👾 kernel | [ 9201.137754] docker0: port 1(veth49abba5) entered disabled state -👾 kernel | [ 9201.143546] veth49abba5 (unregistering): left allmulticast mode -👾 kernel | [ 9201.143576] veth49abba5 (unregistering): left promiscuous mode -👾 kernel | [ 9201.143606] docker0: port 1(veth49abba5) entered disabled state -👾 kernel | [ 9215.360849] br-0023ddea276e: port 1(veth9088918) entered blocking state -👾 kernel | [ 9215.360896] br-0023ddea276e: port 1(veth9088918) entered disabled state -👾 kernel | [ 9215.360921] veth9088918: entered allmulticast mode -👾 kernel | [ 9215.360963] veth9088918: entered promiscuous mode -👾 kernel | [ 9215.583964] eth0: renamed from vethb3accc2 -👾 kernel | [ 9215.584408] br-0023ddea276e: port 1(veth9088918) entered blocking state -👾 kernel | [ 9215.584432] br-0023ddea276e: port 1(veth9088918) entered forwarding state -🌸 agent:docker | time="01-13 21:52:08" level=info msg="adding network" config="{192.168.147.0/24 192.168.147.1 invalid Prefix invalid IP br-0023ddea276e}" name=omega_default -👾 kernel | [ 9215.629312] br-d1f3e4394e37: port 5(vethe62891d) entered blocking state -👾 kernel | [ 9215.629350] br-d1f3e4394e37: port 5(vethe62891d) entered disabled state -👾 kernel | [ 9215.629378] vethe62891d: entered allmulticast mode -👾 kernel | [ 9215.630082] vethe62891d: entered promiscuous mode -👾 kernel | [ 9215.846804] br-0023ddea276e: port 2(vethb0f4bd7) entered blocking state -👾 kernel | [ 9215.846840] br-0023ddea276e: port 2(vethb0f4bd7) entered disabled state -👾 kernel | [ 9215.846859] vethb0f4bd7: entered allmulticast mode -👾 kernel | [ 9215.846913] vethb0f4bd7: entered promiscuous mode -👾 kernel | [ 9215.849087] br-d1f3e4394e37: port 6(veth7e80829) entered blocking state -👾 kernel | [ 9215.849118] br-d1f3e4394e37: port 6(veth7e80829) entered disabled state -👾 kernel | [ 9215.849137] veth7e80829: entered allmulticast mode -👾 kernel | [ 9215.849266] veth7e80829: entered promiscuous mode -👾 kernel | [ 9215.862371] eth0: renamed from veth4e187ba -👾 kernel | [ 9215.864905] br-d1f3e4394e37: port 5(vethe62891d) entered blocking state -👾 kernel | [ 9215.864937] br-d1f3e4394e37: port 5(vethe62891d) entered forwarding state -👾 kernel | [ 9216.527121] br-0023ddea276e: port 3(vetheb20425) entered blocking state -👾 kernel | [ 9216.527158] br-0023ddea276e: port 3(vetheb20425) entered disabled state -👾 kernel | [ 9216.527179] vetheb20425: entered allmulticast mode -👾 kernel | [ 9216.527283] vetheb20425: entered promiscuous mode -👾 kernel | [ 9216.545148] br-d1f3e4394e37: port 7(veth281e2a1) entered blocking state -👾 kernel | [ 9216.545198] br-d1f3e4394e37: port 7(veth281e2a1) entered disabled state -👾 kernel | [ 9216.545224] veth281e2a1: entered allmulticast mode -👾 kernel | [ 9216.545286] veth281e2a1: entered promiscuous mode -👾 kernel | [ 9216.578398] eth0: renamed from veth878d292 -👾 kernel | [ 9216.582128] br-0023ddea276e: port 2(vethb0f4bd7) entered blocking state -👾 kernel | [ 9216.582171] br-0023ddea276e: port 2(vethb0f4bd7) entered forwarding state -👾 kernel | [ 9216.582374] eth0: renamed from vethcf2497f -👾 kernel | [ 9216.583105] br-d1f3e4394e37: port 6(veth7e80829) entered blocking state -👾 kernel | [ 9216.583136] br-d1f3e4394e37: port 6(veth7e80829) entered forwarding state -👾 kernel | [ 9216.663578] br-0023ddea276e: port 1(veth9088918) entered disabled state -👾 kernel | [ 9216.663725] vethb3accc2: renamed from eth0 -👾 kernel | [ 9216.685148] br-0023ddea276e: port 4(vethe8f9085) entered blocking state -👾 kernel | [ 9216.685187] br-0023ddea276e: port 4(vethe8f9085) entered disabled state -👾 kernel | [ 9216.685212] vethe8f9085: entered allmulticast mode -👾 kernel | [ 9216.685265] vethe8f9085: entered promiscuous mode -👾 kernel | [ 9216.690505] br-d1f3e4394e37: port 8(veth3d9994a) entered blocking state -👾 kernel | [ 9216.690585] br-d1f3e4394e37: port 8(veth3d9994a) entered disabled state -👾 kernel | [ 9216.690610] veth3d9994a: entered allmulticast mode -👾 kernel | [ 9216.690667] veth3d9994a: entered promiscuous mode -👾 kernel | [ 9216.725801] eth0: renamed from vethc98c62e -👾 kernel | [ 9216.726464] br-0023ddea276e: port 3(vetheb20425) entered blocking state -👾 kernel | [ 9216.726517] br-0023ddea276e: port 3(vetheb20425) entered forwarding state -👾 kernel | [ 9216.762257] eth0: renamed from vethe1b7f39 -👾 kernel | [ 9216.762789] br-d1f3e4394e37: port 7(veth281e2a1) entered blocking state -👾 kernel | [ 9216.762817] br-d1f3e4394e37: port 7(veth281e2a1) entered forwarding state -👾 kernel | [ 9216.812766] br-0023ddea276e: port 1(veth9088918) entered disabled state -👾 kernel | [ 9216.813316] veth9088918 (unregistering): left allmulticast mode -👾 kernel | [ 9216.813343] veth9088918 (unregistering): left promiscuous mode -👾 kernel | [ 9216.813398] br-0023ddea276e: port 1(veth9088918) entered disabled state -👾 kernel | [ 9216.854192] eth0: renamed from veth8f3908b -👾 kernel | [ 9216.854785] br-0023ddea276e: port 4(vethe8f9085) entered blocking state -👾 kernel | [ 9216.854819] br-0023ddea276e: port 4(vethe8f9085) entered forwarding state -👾 kernel | [ 9216.873972] eth0: renamed from veth5d47b7b -👾 kernel | [ 9216.874556] br-d1f3e4394e37: port 8(veth3d9994a) entered blocking state -👾 kernel | [ 9216.874586] br-d1f3e4394e37: port 8(veth3d9994a) entered forwarding state -👾 kernel | [ 9216.955822] br-0023ddea276e: port 1(veth8b5fbba) entered blocking state -👾 kernel | [ 9216.955853] br-0023ddea276e: port 1(veth8b5fbba) entered disabled state -👾 kernel | [ 9216.955873] veth8b5fbba: entered allmulticast mode -👾 kernel | [ 9216.955922] veth8b5fbba: entered promiscuous mode -📦 scon | time="01-14 02:52:09" level=info msg="add forward" container=docker spec="tcp:0.0.0.0:6333" -📦 scon | time="01-14 02:52:09" level=info msg="add forward" container=docker spec="tcp:[::]:6333" -👾 kernel | [ 9217.001665] br-d1f3e4394e37: port 9(vethba13d78) entered blocking state -👾 kernel | [ 9217.001701] br-d1f3e4394e37: port 9(vethba13d78) entered disabled state -👾 kernel | [ 9217.001734] vethba13d78: entered allmulticast mode -👾 kernel | [ 9217.001811] vethba13d78: entered promiscuous mode -👾 kernel | [ 9217.046649] eth1: renamed from veth37d0d7d -👾 kernel | [ 9217.047960] br-d1f3e4394e37: port 9(vethba13d78) entered blocking state -👾 kernel | [ 9217.047994] br-d1f3e4394e37: port 9(vethba13d78) entered forwarding state -👾 kernel | [ 9217.114078] eth1: renamed from vethf0d0a5a -👾 kernel | [ 9217.117328] br-0023ddea276e: port 1(veth8b5fbba) entered blocking state -👾 kernel | [ 9217.117371] br-0023ddea276e: port 1(veth8b5fbba) entered forwarding state -👾 kernel | [ 9217.120270] br-0023ddea276e: port 5(vethe3a5c6c) entered blocking state -👾 kernel | [ 9217.120307] br-0023ddea276e: port 5(vethe3a5c6c) entered disabled state -👾 kernel | [ 9217.120454] vethe3a5c6c: entered allmulticast mode -👾 kernel | [ 9217.120609] vethe3a5c6c: entered promiscuous mode -👾 kernel | [ 9217.463607] eth1: renamed from veth2baabe2 -👾 kernel | [ 9217.465296] br-0023ddea276e: port 5(vethe3a5c6c) entered blocking state -👾 kernel | [ 9217.465320] br-0023ddea276e: port 5(vethe3a5c6c) entered forwarding state -👾 kernel | [ 9217.465812] br-0023ddea276e: port 6(veth01ab908) entered blocking state -👾 kernel | [ 9217.465860] br-0023ddea276e: port 6(veth01ab908) entered disabled state -👾 kernel | [ 9217.465894] veth01ab908: entered allmulticast mode -👾 kernel | [ 9217.465949] veth01ab908: entered promiscuous mode -👾 kernel | [ 9217.466112] br-d1f3e4394e37: port 10(vethde10747) entered blocking state -👾 kernel | [ 9217.466150] br-d1f3e4394e37: port 10(vethde10747) entered disabled state -👾 kernel | [ 9217.466180] vethde10747: entered allmulticast mode -👾 kernel | [ 9217.466236] vethde10747: entered promiscuous mode -👾 kernel | [ 9218.916819] eth1: renamed from veth1d986d8 -👾 kernel | [ 9218.917201] br-0023ddea276e: port 7(veth3b74e83) entered blocking state -👾 kernel | [ 9218.917222] br-0023ddea276e: port 7(veth3b74e83) entered disabled state -👾 kernel | [ 9218.917240] veth3b74e83: entered allmulticast mode -👾 kernel | [ 9218.917281] veth3b74e83: entered promiscuous mode -👾 kernel | [ 9218.919307] br-0023ddea276e: port 6(veth01ab908) entered blocking state -👾 kernel | [ 9218.919345] br-0023ddea276e: port 6(veth01ab908) entered forwarding state -👾 kernel | [ 9219.117648] eth0: renamed from vethfdac852 -👾 kernel | [ 9219.118967] br-d1f3e4394e37: port 10(vethde10747) entered blocking state -👾 kernel | [ 9219.119006] br-d1f3e4394e37: port 10(vethde10747) entered forwarding state -👾 kernel | [ 9219.280571] eth1: renamed from vetha361ffa -👾 kernel | [ 9219.290764] br-0023ddea276e: port 7(veth3b74e83) entered blocking state -👾 kernel | [ 9219.290805] br-0023ddea276e: port 7(veth3b74e83) entered forwarding state -👾 kernel | [ 9219.293653] br-0023ddea276e: port 8(veth9c2900e) entered blocking state -👾 kernel | [ 9219.293689] br-0023ddea276e: port 8(veth9c2900e) entered disabled state -👾 kernel | [ 9219.293723] veth9c2900e: entered allmulticast mode -👾 kernel | [ 9219.293781] veth9c2900e: entered promiscuous mode -👾 kernel | [ 9219.885042] br-0023ddea276e: port 9(vethe33f6da) entered blocking state -👾 kernel | [ 9219.885072] br-0023ddea276e: port 9(vethe33f6da) entered disabled state -👾 kernel | [ 9219.885103] vethe33f6da: entered allmulticast mode -👾 kernel | [ 9219.885158] vethe33f6da: entered promiscuous mode -👾 kernel | [ 9219.894972] eth0: renamed from veth5c4bc29 -👾 kernel | [ 9219.895496] br-0023ddea276e: port 8(veth9c2900e) entered blocking state -👾 kernel | [ 9219.895521] br-0023ddea276e: port 8(veth9c2900e) entered forwarding state -👾 kernel | [ 9220.273030] eth1: renamed from vethdc605ae -👾 kernel | [ 9220.298539] br-0023ddea276e: port 9(vethe33f6da) entered blocking state -👾 kernel | [ 9220.302671] br-0023ddea276e: port 9(vethe33f6da) entered forwarding state -👾 kernel | [ 9220.463356] br-d1f3e4394e37: port 11(veth2efba04) entered blocking state -👾 kernel | [ 9220.463392] br-d1f3e4394e37: port 11(veth2efba04) entered disabled state -👾 kernel | [ 9220.463434] veth2efba04: entered allmulticast mode -👾 kernel | [ 9220.463483] veth2efba04: entered promiscuous mode -👾 kernel | [ 9220.607986] eth1: renamed from veth3c154ac -👾 kernel | [ 9220.614010] br-d1f3e4394e37: port 11(veth2efba04) entered blocking state -👾 kernel | [ 9220.614045] br-d1f3e4394e37: port 11(veth2efba04) entered forwarding state -👾 kernel | [ 9221.646426] br-d1f3e4394e37: port 12(veth38580bf) entered blocking state -👾 kernel | [ 9221.646464] br-d1f3e4394e37: port 12(veth38580bf) entered disabled state -👾 kernel | [ 9221.646484] veth38580bf: entered allmulticast mode -👾 kernel | [ 9221.646530] veth38580bf: entered promiscuous mode -👾 kernel | [ 9221.733302] br-0023ddea276e: port 10(veth5b7518c) entered blocking state -👾 kernel | [ 9221.733333] br-0023ddea276e: port 10(veth5b7518c) entered disabled state -👾 kernel | [ 9221.733351] veth5b7518c: entered allmulticast mode -👾 kernel | [ 9221.733420] veth5b7518c: entered promiscuous mode -👾 kernel | [ 9221.755509] eth0: renamed from veth4e67922 -👾 kernel | [ 9221.756500] br-d1f3e4394e37: port 12(veth38580bf) entered blocking state -👾 kernel | [ 9221.756521] br-d1f3e4394e37: port 12(veth38580bf) entered forwarding state -👾 kernel | [ 9221.992660] br-0023ddea276e: port 11(vethb87fee6) entered blocking state -👾 kernel | [ 9221.992700] br-0023ddea276e: port 11(vethb87fee6) entered disabled state -👾 kernel | [ 9221.992722] vethb87fee6: entered allmulticast mode -🌸 agent:docker | time="01-13 21:52:14" level=error msg="failed to refresh networks" error="list links: results may be incomplete or inconsistent" -👾 kernel | [ 9221.992843] vethb87fee6: entered promiscuous mode -🌸 agent:docker | time="01-13 21:52:14" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 9221.997954] eth0: renamed from vethbf32232 -👾 kernel | [ 9221.999640] br-0023ddea276e: port 10(veth5b7518c) entered blocking state -👾 kernel | [ 9221.999666] br-0023ddea276e: port 10(veth5b7518c) entered forwarding state -👾 kernel | [ 9222.240817] eth1: renamed from veth34037c5 -👾 kernel | [ 9222.243149] br-0023ddea276e: port 11(vethb87fee6) entered blocking state -👾 kernel | [ 9222.243173] br-0023ddea276e: port 11(vethb87fee6) entered forwarding state -👾 kernel | [ 9222.451000] br-d1f3e4394e37: port 13(veth301a9f1) entered blocking state -👾 kernel | [ 9222.451036] br-d1f3e4394e37: port 13(veth301a9f1) entered disabled state -👾 kernel | [ 9222.451058] veth301a9f1: entered allmulticast mode -👾 kernel | [ 9222.451113] veth301a9f1: entered promiscuous mode -🌸 agent:docker | time="01-13 21:52:15" level=error msg="unable to set all bridgeports to hairpin" error="unable to get links: results may be incomplete or inconsistent" -👾 kernel | [ 9222.545431] eth1: renamed from veth791eda0 -👾 kernel | [ 9222.546982] br-d1f3e4394e37: port 13(veth301a9f1) entered blocking state -👾 kernel | [ 9222.547008] br-d1f3e4394e37: port 13(veth301a9f1) entered forwarding state -🌲 vmgr | time="01-13 21:54:28" level=error msg="TCP forward [162.159.140.245:443] create endpoint failed: connection was refused" -👾 kernel | [12262.642467] br-d1f3e4394e37: port 14(veth741e2d3) entered blocking state -👾 kernel | [12262.642532] br-d1f3e4394e37: port 14(veth741e2d3) entered disabled state -👾 kernel | [12262.642557] veth741e2d3: entered allmulticast mode -👾 kernel | [12262.642604] veth741e2d3: entered promiscuous mode -👾 kernel | [12262.749325] eth0: renamed from vetha41a121 -👾 kernel | [12262.750210] br-d1f3e4394e37: port 14(veth741e2d3) entered blocking state -👾 kernel | [12262.750240] br-d1f3e4394e37: port 14(veth741e2d3) entered forwarding state -👾 kernel | [12262.975420] br-0023ddea276e: port 12(veth9cc0449) entered blocking state -👾 kernel | [12262.975455] br-0023ddea276e: port 12(veth9cc0449) entered disabled state -👾 kernel | [12262.975475] veth9cc0449: entered allmulticast mode -👾 kernel | [12262.975603] veth9cc0449: entered promiscuous mode -👾 kernel | [12262.999636] eth1: renamed from veth99b296d -👾 kernel | [12263.000391] br-0023ddea276e: port 12(veth9cc0449) entered blocking state -👾 kernel | [12263.000565] br-0023ddea276e: port 12(veth9cc0449) entered forwarding state -👾 kernel | [12263.846994] br-d1f3e4394e37: port 14(veth741e2d3) entered disabled state -👾 kernel | [12263.847076] vetha41a121: renamed from eth0 -👾 kernel | [12263.918665] br-d1f3e4394e37: port 14(veth741e2d3) entered disabled state -👾 kernel | [12263.919751] veth741e2d3 (unregistering): left allmulticast mode -👾 kernel | [12263.919780] veth741e2d3 (unregistering): left promiscuous mode -👾 kernel | [12263.919805] br-d1f3e4394e37: port 14(veth741e2d3) entered disabled state -👾 kernel | [12263.952608] br-0023ddea276e: port 12(veth9cc0449) entered disabled state -👾 kernel | [12263.952691] veth99b296d: renamed from eth1 -👾 kernel | [12263.987927] br-0023ddea276e: port 12(veth9cc0449) entered disabled state -👾 kernel | [12263.988773] veth9cc0449 (unregistering): left allmulticast mode -👾 kernel | [12263.988806] veth9cc0449 (unregistering): left promiscuous mode -👾 kernel | [12263.988820] br-0023ddea276e: port 12(veth9cc0449) entered disabled state -👾 kernel | [12282.445077] br-d1f3e4394e37: port 14(vethf82a11b) entered blocking state -👾 kernel | [12282.445133] br-d1f3e4394e37: port 14(vethf82a11b) entered disabled state -👾 kernel | [12282.445182] vethf82a11b: entered allmulticast mode -👾 kernel | [12282.445251] vethf82a11b: entered promiscuous mode -👾 kernel | [12282.618384] eth0: renamed from veth65d769b -👾 kernel | [12282.619051] br-d1f3e4394e37: port 14(vethf82a11b) entered blocking state -👾 kernel | [12282.619107] br-d1f3e4394e37: port 14(vethf82a11b) entered forwarding state -👾 kernel | [12282.701453] br-0023ddea276e: port 12(veth2b5a7b3) entered blocking state -👾 kernel | [12282.701485] br-0023ddea276e: port 12(veth2b5a7b3) entered disabled state -👾 kernel | [12282.701509] veth2b5a7b3: entered allmulticast mode -👾 kernel | [12282.701561] veth2b5a7b3: entered promiscuous mode -👾 kernel | [12282.736124] eth1: renamed from veth1e2066a -👾 kernel | [12282.736977] br-0023ddea276e: port 12(veth2b5a7b3) entered blocking state -👾 kernel | [12282.737040] br-0023ddea276e: port 12(veth2b5a7b3) entered forwarding state -👾 kernel | [12296.967205] veth65d769b: renamed from eth0 -👾 kernel | [12296.967745] br-d1f3e4394e37: port 14(vethf82a11b) entered disabled state -👾 kernel | [12297.007652] br-d1f3e4394e37: port 14(vethf82a11b) entered disabled state -👾 kernel | [12297.008675] vethf82a11b (unregistering): left allmulticast mode -👾 kernel | [12297.008713] vethf82a11b (unregistering): left promiscuous mode -👾 kernel | [12297.008731] br-d1f3e4394e37: port 14(vethf82a11b) entered disabled state -👾 kernel | [12297.045404] br-0023ddea276e: port 12(veth2b5a7b3) entered disabled state -👾 kernel | [12297.045576] veth1e2066a: renamed from eth1 -👾 kernel | [12297.077608] br-0023ddea276e: port 12(veth2b5a7b3) entered disabled state -👾 kernel | [12297.078112] veth2b5a7b3 (unregistering): left allmulticast mode -👾 kernel | [12297.078138] veth2b5a7b3 (unregistering): left promiscuous mode -👾 kernel | [12297.078152] br-0023ddea276e: port 12(veth2b5a7b3) entered disabled state -👾 kernel | [13373.000696] br-dd78b5d9f51d: port 1(veth6735fa2) entered blocking state -👾 kernel | [13373.000733] br-dd78b5d9f51d: port 1(veth6735fa2) entered disabled state -👾 kernel | [13373.000762] veth6735fa2: entered allmulticast mode -👾 kernel | [13373.000805] veth6735fa2: entered promiscuous mode -👾 kernel | [13373.274397] br-dd78b5d9f51d: port 2(vethc7cb1bd) entered blocking state -👾 kernel | [13373.274430] br-dd78b5d9f51d: port 2(vethc7cb1bd) entered disabled state -👾 kernel | [13373.274452] vethc7cb1bd: entered allmulticast mode -👾 kernel | [13373.274492] vethc7cb1bd: entered promiscuous mode -👾 kernel | [13373.304096] eth0: renamed from veth3055819 -👾 kernel | [13373.304679] br-dd78b5d9f51d: port 1(veth6735fa2) entered blocking state -👾 kernel | [13373.304722] br-dd78b5d9f51d: port 1(veth6735fa2) entered forwarding state -👾 kernel | [13373.398948] eth0: renamed from vethcca96b9 -👾 kernel | [13373.399559] br-dd78b5d9f51d: port 2(vethc7cb1bd) entered blocking state -👾 kernel | [13373.399591] br-dd78b5d9f51d: port 2(vethc7cb1bd) entered forwarding state -👾 kernel | [13373.449695] br-d1f3e4394e37: port 14(veth3f7bb9e) entered blocking state -👾 kernel | [13373.449735] br-d1f3e4394e37: port 14(veth3f7bb9e) entered disabled state -👾 kernel | [13373.449757] veth3f7bb9e: entered allmulticast mode -👾 kernel | [13373.449806] veth3f7bb9e: entered promiscuous mode -🌸 agent:docker | time="01-13 23:01:26" level=error msg="failed to refresh networks" error="list links: results may be incomplete or inconsistent" -👾 kernel | [13373.812887] eth1: renamed from veth0b3e32b -👾 kernel | [13373.813813] br-d1f3e4394e37: port 14(veth3f7bb9e) entered blocking state -👾 kernel | [13373.813843] br-d1f3e4394e37: port 14(veth3f7bb9e) entered forwarding state -🌸 agent:docker | time="01-13 23:01:26" level=info msg="adding network" config="{192.168.148.0/24 192.168.148.1 invalid Prefix invalid IP br-dd78b5d9f51d}" name=event-agent_default -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection reset by peer" -👾 kernel | [13374.566916] br-dd78b5d9f51d: port 3(veth6f24e75) entered blocking state -👾 kernel | [13374.566951] br-dd78b5d9f51d: port 3(veth6f24e75) entered disabled state -👾 kernel | [13374.567037] veth6f24e75: entered allmulticast mode -👾 kernel | [13374.567108] veth6f24e75: entered promiscuous mode -👾 kernel | [13374.641623] eth0: renamed from veth1f47954 -👾 kernel | [13374.642049] br-dd78b5d9f51d: port 3(veth6f24e75) entered blocking state -👾 kernel | [13374.642072] br-dd78b5d9f51d: port 3(veth6f24e75) entered forwarding state -👾 kernel | [13374.723557] br-d1f3e4394e37: port 15(vethefa6155) entered blocking state -👾 kernel | [13374.723650] br-d1f3e4394e37: port 15(vethefa6155) entered disabled state -👾 kernel | [13374.723676] vethefa6155: entered allmulticast mode -👾 kernel | [13374.723724] vethefa6155: entered promiscuous mode -👾 kernel | [13375.203786] eth1: renamed from veth0f4566d -👾 kernel | [13375.204496] br-d1f3e4394e37: port 15(vethefa6155) entered blocking state -👾 kernel | [13375.204527] br-d1f3e4394e37: port 15(vethefa6155) entered forwarding state -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:27" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.3.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.11.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.0.34:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:01:28" level=error msg="TCP forward [104.16.10.34:443] create endpoint failed: connection was refused" -👾 kernel | [13385.705366] br-dd78b5d9f51d: port 3(veth6f24e75) entered disabled state -👾 kernel | [13385.705625] veth1f47954: renamed from eth0 -👾 kernel | [13385.838570] br-dd78b5d9f51d: port 3(veth6f24e75) entered disabled state -👾 kernel | [13385.839606] veth6f24e75 (unregistering): left allmulticast mode -👾 kernel | [13385.839693] veth6f24e75 (unregistering): left promiscuous mode -👾 kernel | [13385.839705] br-dd78b5d9f51d: port 3(veth6f24e75) entered disabled state -👾 kernel | [13385.883405] br-d1f3e4394e37: port 15(vethefa6155) entered disabled state -👾 kernel | [13385.883802] veth0f4566d: renamed from eth1 -👾 kernel | [13385.916111] br-d1f3e4394e37: port 15(vethefa6155) entered disabled state -👾 kernel | [13385.917214] vethefa6155 (unregistering): left allmulticast mode -👾 kernel | [13385.917248] vethefa6155 (unregistering): left promiscuous mode -👾 kernel | [13385.917266] br-d1f3e4394e37: port 15(vethefa6155) entered disabled state -👾 kernel | [13407.276716] br-dd78b5d9f51d: port 1(veth6735fa2) entered disabled state -👾 kernel | [13407.277073] veth3055819: renamed from eth0 -👾 kernel | [13407.321816] br-dd78b5d9f51d: port 1(veth6735fa2) entered disabled state -👾 kernel | [13407.322821] veth6735fa2 (unregistering): left allmulticast mode -👾 kernel | [13407.322876] veth6735fa2 (unregistering): left promiscuous mode -👾 kernel | [13407.322931] br-dd78b5d9f51d: port 1(veth6735fa2) entered disabled state -👾 kernel | [13407.389098] br-d1f3e4394e37: port 14(veth3f7bb9e) entered disabled state -👾 kernel | [13407.389539] veth0b3e32b: renamed from eth1 -👾 kernel | [13407.421174] br-d1f3e4394e37: port 14(veth3f7bb9e) entered disabled state -👾 kernel | [13407.421443] veth3f7bb9e (unregistering): left allmulticast mode -👾 kernel | [13407.421466] veth3f7bb9e (unregistering): left promiscuous mode -👾 kernel | [13407.421500] br-d1f3e4394e37: port 14(veth3f7bb9e) entered disabled state -👾 kernel | [13408.055352] br-dd78b5d9f51d: port 1(veth9e3874a) entered blocking state -👾 kernel | [13408.055391] br-dd78b5d9f51d: port 1(veth9e3874a) entered disabled state -👾 kernel | [13408.055423] veth9e3874a: entered allmulticast mode -👾 kernel | [13408.055486] veth9e3874a: entered promiscuous mode -👾 kernel | [13408.203996] eth0: renamed from vethfe10c79 -👾 kernel | [13408.204671] br-dd78b5d9f51d: port 1(veth9e3874a) entered blocking state -👾 kernel | [13408.204701] br-dd78b5d9f51d: port 1(veth9e3874a) entered forwarding state -👾 kernel | [13408.397379] br-dd78b5d9f51d: port 3(veth2fedc64) entered blocking state -👾 kernel | [13408.397408] br-dd78b5d9f51d: port 3(veth2fedc64) entered disabled state -👾 kernel | [13408.397437] veth2fedc64: entered allmulticast mode -👾 kernel | [13408.397520] veth2fedc64: entered promiscuous mode -👾 kernel | [13408.552178] br-d1f3e4394e37: port 14(vetha4694c1) entered blocking state -👾 kernel | [13408.552219] br-d1f3e4394e37: port 14(vetha4694c1) entered disabled state -👾 kernel | [13408.552243] vetha4694c1: entered allmulticast mode -👾 kernel | [13408.552396] vetha4694c1: entered promiscuous mode -👾 kernel | [13408.568372] eth0: renamed from veth3a3088f -👾 kernel | [13408.568909] br-dd78b5d9f51d: port 3(veth2fedc64) entered blocking state -👾 kernel | [13408.568937] br-dd78b5d9f51d: port 3(veth2fedc64) entered forwarding state -👾 kernel | [13408.812422] eth0: renamed from vetha217aa3 -👾 kernel | [13408.812989] br-d1f3e4394e37: port 14(vetha4694c1) entered blocking state -👾 kernel | [13408.813023] br-d1f3e4394e37: port 14(vetha4694c1) entered forwarding state -👾 kernel | [13409.027340] br-d1f3e4394e37: port 15(veth60b9bce) entered blocking state -👾 kernel | [13409.027423] br-d1f3e4394e37: port 15(veth60b9bce) entered disabled state -👾 kernel | [13409.027461] veth60b9bce: entered allmulticast mode -👾 kernel | [13409.027549] veth60b9bce: entered promiscuous mode -👾 kernel | [13409.085380] br-dd78b5d9f51d: port 4(vethf6b6667) entered blocking state -👾 kernel | [13409.085419] br-dd78b5d9f51d: port 4(vethf6b6667) entered disabled state -👾 kernel | [13409.085452] vethf6b6667: entered allmulticast mode -👾 kernel | [13409.085501] vethf6b6667: entered promiscuous mode -👾 kernel | [13409.088908] eth1: renamed from vethd63c68b -👾 kernel | [13409.090303] br-d1f3e4394e37: port 15(veth60b9bce) entered blocking state -👾 kernel | [13409.090331] br-d1f3e4394e37: port 15(veth60b9bce) entered forwarding state -👾 kernel | [13409.090662] br-d1f3e4394e37: port 16(veth4afe96e) entered blocking state -👾 kernel | [13409.090705] br-d1f3e4394e37: port 16(veth4afe96e) entered disabled state -👾 kernel | [13409.090728] veth4afe96e: entered allmulticast mode -👾 kernel | [13409.090781] veth4afe96e: entered promiscuous mode -👾 kernel | [13409.120313] br-dd78b5d9f51d: port 5(vethe9f386c) entered blocking state -👾 kernel | [13409.120363] br-dd78b5d9f51d: port 5(vethe9f386c) entered disabled state -👾 kernel | [13409.120410] vethe9f386c: entered allmulticast mode -👾 kernel | [13409.120476] vethe9f386c: entered promiscuous mode -👾 kernel | [13409.152907] br-d1f3e4394e37: port 17(vethed190e4) entered blocking state -👾 kernel | [13409.152948] br-d1f3e4394e37: port 17(vethed190e4) entered disabled state -👾 kernel | [13409.152965] vethed190e4: entered allmulticast mode -👾 kernel | [13409.153007] vethed190e4: entered promiscuous mode -👾 kernel | [13409.183272] br-dd78b5d9f51d: port 6(vetha4d866a) entered blocking state -👾 kernel | [13409.183312] br-dd78b5d9f51d: port 6(vetha4d866a) entered disabled state -👾 kernel | [13409.183368] vetha4d866a: entered allmulticast mode -👾 kernel | [13409.183455] vetha4d866a: entered promiscuous mode -👾 kernel | [13409.189599] eth0: renamed from veth4007c7c -👾 kernel | [13409.190165] br-dd78b5d9f51d: port 4(vethf6b6667) entered blocking state -👾 kernel | [13409.190198] br-dd78b5d9f51d: port 4(vethf6b6667) entered forwarding state -👾 kernel | [13409.234442] eth0: renamed from veth2516e18 -👾 kernel | [13409.235591] br-d1f3e4394e37: port 16(veth4afe96e) entered blocking state -👾 kernel | [13409.235610] br-d1f3e4394e37: port 16(veth4afe96e) entered forwarding state -👾 kernel | [13409.237767] eth0: renamed from veth0e169b7 -👾 kernel | [13409.238745] br-dd78b5d9f51d: port 5(vethe9f386c) entered blocking state -👾 kernel | [13409.238770] br-dd78b5d9f51d: port 5(vethe9f386c) entered forwarding state -👾 kernel | [13411.641326] br-dd78b5d9f51d: port 7(vethab92897) entered blocking state -👾 kernel | [13411.641362] br-dd78b5d9f51d: port 7(vethab92897) entered disabled state -👾 kernel | [13411.641376] vethab92897: entered allmulticast mode -👾 kernel | [13411.641415] vethab92897: entered promiscuous mode -👾 kernel | [13411.649543] eth1: renamed from vethf416245 -👾 kernel | [13411.650277] br-d1f3e4394e37: port 17(vethed190e4) entered blocking state -👾 kernel | [13411.650311] br-d1f3e4394e37: port 17(vethed190e4) entered forwarding state -👾 kernel | [13411.811511] br-d1f3e4394e37: port 18(veth8efe72d) entered blocking state -👾 kernel | [13411.811554] br-d1f3e4394e37: port 18(veth8efe72d) entered disabled state -👾 kernel | [13411.811575] veth8efe72d: entered allmulticast mode -👾 kernel | [13411.811611] veth8efe72d: entered promiscuous mode -👾 kernel | [13411.816554] br-dd78b5d9f51d: port 8(veth266cbc8) entered blocking state -👾 kernel | [13411.816603] br-dd78b5d9f51d: port 8(veth266cbc8) entered disabled state -👾 kernel | [13411.816625] veth266cbc8: entered allmulticast mode -👾 kernel | [13411.816674] veth266cbc8: entered promiscuous mode -👾 kernel | [13411.965926] eth0: renamed from vethf24eccd -👾 kernel | [13411.966508] br-dd78b5d9f51d: port 6(vetha4d866a) entered blocking state -👾 kernel | [13411.966543] br-dd78b5d9f51d: port 6(vetha4d866a) entered forwarding state -👾 kernel | [13413.401706] eth1: renamed from vethef6ea07 -👾 kernel | [13413.403482] eth1: renamed from veth443a822 -👾 kernel | [13413.404958] eth1: renamed from veth67879c9 -👾 kernel | [13413.410132] br-dd78b5d9f51d: port 8(veth266cbc8) entered blocking state -👾 kernel | [13413.410156] br-dd78b5d9f51d: port 8(veth266cbc8) entered forwarding state -👾 kernel | [13413.410588] br-d1f3e4394e37: port 18(veth8efe72d) entered blocking state -👾 kernel | [13413.410608] br-d1f3e4394e37: port 18(veth8efe72d) entered forwarding state -👾 kernel | [13413.410730] br-dd78b5d9f51d: port 7(vethab92897) entered blocking state -👾 kernel | [13413.410745] br-dd78b5d9f51d: port 7(vethab92897) entered forwarding state -👾 kernel | [13413.412747] br-d1f3e4394e37: port 19(veth655cbce) entered blocking state -👾 kernel | [13413.412776] br-d1f3e4394e37: port 19(veth655cbce) entered disabled state -👾 kernel | [13413.412803] veth655cbce: entered allmulticast mode -👾 kernel | [13413.412854] veth655cbce: entered promiscuous mode -👾 kernel | [13415.263896] eth1: renamed from veth70a3c96 -👾 kernel | [13415.266015] br-d1f3e4394e37: port 19(veth655cbce) entered blocking state -👾 kernel | [13415.266038] br-d1f3e4394e37: port 19(veth655cbce) entered forwarding state -👾 kernel | [13415.268659] br-d1f3e4394e37: port 20(vethe57e911) entered blocking state -👾 kernel | [13415.268728] br-d1f3e4394e37: port 20(vethe57e911) entered disabled state -👾 kernel | [13415.268812] vethe57e911: entered allmulticast mode -👾 kernel | [13415.268891] vethe57e911: entered promiscuous mode -👾 kernel | [13415.910988] eth1: renamed from veth81fe564 -👾 kernel | [13415.912728] br-d1f3e4394e37: port 20(vethe57e911) entered blocking state -👾 kernel | [13415.913091] br-d1f3e4394e37: port 20(vethe57e911) entered forwarding state -🌲 vmgr | time="01-13 23:03:27" level=error msg="TCP forward [35.171.115.154:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:03:35" level=error msg="TCP forward [16.182.98.130:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:03:35" level=error msg="TCP forward [3.5.22.10:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:03:35" level=error msg="TCP forward [52.217.80.120:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:03:36" level=error msg="TCP forward [162.159.140.245:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:03:53" level=error msg="TCP forward [54.231.198.194:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:03:53" level=error msg="TCP forward [3.5.22.10:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:03:53" level=error msg="TCP forward [52.217.80.120:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:06:56" level=error msg="TCP forward [16.182.108.18:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:07:41" level=error msg="TCP forward [142.250.105.95:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:07:41" level=error msg="TCP forward [172.253.124.95:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:07:41" level=error msg="TCP forward [64.233.177.95:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:08:27" level=error msg="TCP forward [172.66.0.243:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:09:25" level=error msg="TCP forward [54.231.138.58:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:09:25" level=error msg="TCP forward [3.5.10.104:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:09:25" level=error msg="TCP forward [16.15.178.40:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:10:48" level=error msg="TCP forward [52.216.61.138:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:10:48" level=error msg="TCP forward [52.216.207.142:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:10:48" level=error msg="TCP forward [52.217.107.200:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:10:51" level=error msg="TCP forward [34.204.109.15:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:11:28" level=error msg="TCP forward [3.5.14.109:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:11:28" level=error msg="TCP forward [52.216.222.186:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:11:28" level=error msg="TCP forward [16.15.183.33:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:12:18" level=error msg="TCP forward [16.15.191.20:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:12:20" level=error msg="TCP forward [34.204.109.15:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:12:20" level=error msg="TCP forward [34.237.201.68:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:13:26" level=error msg="TCP forward [16.15.195.242:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:13:26" level=error msg="TCP forward [16.15.183.225:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:13:26" level=error msg="TCP forward [16.15.192.154:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:14:46" level=error msg="TCP forward [52.216.57.234:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:14:46" level=error msg="TCP forward [16.15.223.13:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:17:12" level=error msg="TCP forward [16.15.183.62:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:17:12" level=error msg="TCP forward [16.15.189.224:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:17:12" level=error msg="TCP forward [16.15.186.252:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:19:52" level=error msg="TCP forward [54.231.192.58:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:20:52" level=error msg="TCP forward [34.204.109.15:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:20:52" level=error msg="TCP forward [34.237.253.141:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:22:29" level=error msg="TCP forward [52.217.170.98:443] create endpoint failed: connection reset by peer" -🌲 vmgr | time="01-13 23:22:29" level=error msg="TCP forward [16.182.39.50:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:22:29" level=error msg="TCP forward [16.15.178.175:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:23:30" level=error msg="TCP forward [16.182.37.82:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:23:30" level=error msg="TCP forward [52.216.41.98:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:23:30" level=error msg="TCP forward [52.216.57.138:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:23:32" level=error msg="TCP forward [34.237.201.68:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:24:05" level=error msg="TCP forward [52.216.78.112:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:24:05" level=error msg="TCP forward [16.15.182.164:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:24:05" level=error msg="TCP forward [52.217.95.82:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:25:38" level=error msg="TCP forward [52.217.120.122:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:25:38" level=error msg="TCP forward [54.231.195.106:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:25:38" level=error msg="TCP forward [52.217.114.162:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:25:40" level=error msg="TCP forward [34.202.153.183:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:26:02" level=error msg="TCP forward [162.159.140.245:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:26:23" level=error msg="TCP forward [16.15.183.75:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:26:23" level=error msg="TCP forward [52.217.233.106:443] create endpoint failed: connection was refused" -🌲 vmgr | time="01-13 23:36:29" level=error msg="TCP forward [34.202.153.183:443] create endpoint failed: connection was refused" - - -Check logs for more details. \ No newline at end of file diff --git a/package.json b/package.json index 29927016..6c711ba4 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "test:e2e:gateway": "bun run scripts/gateway-e2e.ts" }, "devDependencies": { + "@biomejs/biome": "2.3.11", "@commitlint/cli": "19.8.1", "@commitlint/config-conventional": "19.8.1", "@semantic-release/changelog": "6.0.3", @@ -41,10 +42,11 @@ "@types/qrcode": "^1.5.6", "commitizen": "4.3.1", "cz-conventional-changelog": "3.3.0", - "husky": "9.1.7", + "husky": "^9.1.7", "prettier": "3.7.4", "prettier-plugin-sort-imports": "^1.8.9", - "semantic-release": "25.0.2" + "semantic-release": "25.0.2", + "ultracite": "7.0.12" }, "config": { "commitizen": { @@ -60,6 +62,7 @@ "@modelcontextprotocol/sdk": "1.25.3", "@opentui/core": "^0.1.74", "qrcode": "^1.5.4", + "qrcode-terminal": "^0.12.0", "zod": "4.3.5" } } diff --git a/scripts/build-macos-release.sh b/scripts/build-macos-release.sh index f479df4a..b42ba3ca 100755 --- a/scripts/build-macos-release.sh +++ b/scripts/build-macos-release.sh @@ -272,6 +272,14 @@ echo read -p "Press Enter to close..." INSTALLER_EOF chmod +x "$DMG_CONTENTS/Install Hack CLI.command" + + # Sign the .command file with Developer ID (required for Gatekeeper) + log "Signing Install Hack CLI.command..." + codesign --force --options runtime --timestamp \ + --sign "$SIGNING_IDENTITY" \ + "$DMG_CONTENTS/Install Hack CLI.command" + codesign -vvv "$DMG_CONTENTS/Install Hack CLI.command" + success "Install script signed" fi # Create Applications symlink @@ -328,6 +336,73 @@ ditto -c -k --keepParent \ "$BUILD_DIR/HackDesktop-$VERSION-macOS.zip" success "ZIP created" +# Generate hack-install.sh (download installer script) +log "Generating hack-install.sh..." +INSTALL_SCRIPT_PATH="$BUILD_DIR/hack-install.sh" +INSTALL_SCRIPT_VERSIONED="$BUILD_DIR/hack-$VERSION-install.sh" +cat > "$INSTALL_SCRIPT_PATH" << 'DOWNLOAD_INSTALLER_EOF' +#!/usr/bin/env bash +set -euo pipefail + +REPO_OWNER="hack-dance" +REPO_NAME="hack-cli" +REPO="$REPO_OWNER/$REPO_NAME" +API_URL="https://api.github.com/repos/$REPO/releases/latest" +BASE_URL="${HACK_RELEASE_BASE_URL:-https://github.com/$REPO/releases/download}" + +if [ -n "${HACK_INSTALL_TAG:-}" ]; then + TAG="$HACK_INSTALL_TAG" +elif [ -n "${HACK_INSTALL_VERSION:-}" ]; then + TAG="v$HACK_INSTALL_VERSION" +else + TAG=$(curl -fsSL "$API_URL" | sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p' | head -n1) +fi + +if [ -z "$TAG" ]; then + echo "Failed to resolve release tag." + exit 1 +fi + +VERSION="${TAG#v}" +OS="$(uname -s | tr '[:upper:]' '[:lower:]')" +ARCH="$(uname -m)" +if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then + ARCH="x86_64" +elif [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then + ARCH="arm64" +else + echo "Unsupported architecture: $ARCH" + exit 1 +fi + +if [ "$OS" != "darwin" ] && [ "$OS" != "linux" ]; then + echo "Unsupported OS: $OS" + exit 1 +fi + +TARBALL="hack-$VERSION-$OS-$ARCH.tar.gz" +URL="$BASE_URL/$TAG/$TARBALL" + +tmpdir=$(mktemp -d) +cleanup() { rm -rf "$tmpdir"; } +trap cleanup EXIT + +echo "Downloading $URL" +curl -fsSL "$URL" -o "$tmpdir/$TARBALL" +tar -xzf "$tmpdir/$TARBALL" -C "$tmpdir" + +INSTALL_DIR="$tmpdir/hack-$VERSION-release" +if [ ! -d "$INSTALL_DIR" ]; then + echo "Missing release directory: $INSTALL_DIR" + exit 1 +fi + +bash "$INSTALL_DIR/install.sh" +DOWNLOAD_INSTALLER_EOF +chmod +x "$INSTALL_SCRIPT_PATH" +cp "$INSTALL_SCRIPT_PATH" "$INSTALL_SCRIPT_VERSIONED" +success "hack-install.sh created" + # Summary echo echo -e "${GREEN}Release build complete!${NC}" @@ -337,9 +412,15 @@ echo echo "Artifacts:" echo " $DMG_PATH" echo " $BUILD_DIR/HackDesktop-$VERSION-macOS.zip" +echo " $INSTALL_SCRIPT_PATH" +echo " $INSTALL_SCRIPT_VERSIONED" echo echo "To install:" echo " open \"$DMG_PATH\"" echo echo "To upload to GitHub release:" -echo " gh release upload v$VERSION \"$DMG_PATH\" \"$BUILD_DIR/HackDesktop-$VERSION-macOS.zip\"" +echo " gh release upload v$VERSION \\" +echo " \"$DMG_PATH\" \\" +echo " \"$BUILD_DIR/HackDesktop-$VERSION-macOS.zip\" \\" +echo " \"$INSTALL_SCRIPT_PATH\" \\" +echo " \"$INSTALL_SCRIPT_VERSIONED\"" diff --git a/scripts/build-release.ts b/scripts/build-release.ts index c82cac7c..524a9f27 100644 --- a/scripts/build-release.ts +++ b/scripts/build-release.ts @@ -1,162 +1,204 @@ #!/usr/bin/env bun -import { basename, resolve, relative } from "node:path" -import { mkdir, readdir, rm } from "node:fs/promises" +import { mkdir, readdir, rm } from "node:fs/promises"; +import { basename, relative, resolve } from "node:path"; import { renderProjectBranchesSchemaJson, - renderProjectConfigSchemaJson -} from "../src/templates.ts" - -type BuildArgs = { - readonly outDirRaw: string | null - readonly versionOverride: string | null - readonly skipTests: boolean - readonly noClean: boolean + renderProjectConfigSchemaJson, +} from "../src/templates.ts"; + +interface BuildArgs { + readonly outDirRaw: string | null; + readonly versionOverride: string | null; + readonly skipTests: boolean; + readonly noClean: boolean; } -type ParseOk = { readonly ok: true; readonly args: BuildArgs } -type ParseErr = { readonly ok: false; readonly message: string } +interface ParseOk { + readonly ok: true; + readonly args: BuildArgs; +} +interface ParseErr { + readonly ok: false; + readonly message: string; +} -const parsed = parseArgs({ argv: Bun.argv.slice(2) }) -if (!parsed.ok) { - process.stderr.write(`${parsed.message}\n`) - process.exitCode = 1 +const parsed = parseArgs({ argv: Bun.argv.slice(2) }); +if (parsed.ok) { + process.exitCode = await main({ args: parsed.args }); } else { - process.exitCode = await main({ args: parsed.args }) + process.stderr.write(`${parsed.message}\n`); + process.exitCode = 1; } async function main({ args }: { readonly args: BuildArgs }): Promise { - const repoRoot = resolve(import.meta.dir, "..") - const pkg = await Bun.file(resolve(repoRoot, "package.json")).json() - const version = typeof args.versionOverride === "string" ? args.versionOverride : pkg.version + const repoRoot = resolve(import.meta.dir, ".."); + const pkg = await Bun.file(resolve(repoRoot, "package.json")).json(); + const version = + typeof args.versionOverride === "string" + ? args.versionOverride + : pkg.version; if (typeof version !== "string" || version.trim().length === 0) { - process.stderr.write("Unable to determine version from package.json or --version.\n") - return 1 + process.stderr.write( + "Unable to determine version from package.json or --version.\n" + ); + return 1; } - const distRoot = resolve(repoRoot, "dist") + const distRoot = resolve(repoRoot, "dist"); const releaseRoot = args.outDirRaw ? resolve(repoRoot, args.outDirRaw) - : resolve(distRoot, "release") - const target = resolveTarget() + : resolve(distRoot, "release"); + const target = resolveTarget(); if (!target) { - process.stderr.write(`Unsupported platform/arch: ${process.platform}/${process.arch}\n`) - return 1 + process.stderr.write( + `Unsupported platform/arch: ${process.platform}/${process.arch}\n` + ); + return 1; } - const releaseDirName = `hack-${version}-release` - const releaseDir = resolve(releaseRoot, releaseDirName) + const releaseDirName = `hack-${version}-release`; + const releaseDir = resolve(releaseRoot, releaseDirName); if (!args.noClean) { - await rm(releaseDir, { recursive: true, force: true }) + await rm(releaseDir, { recursive: true, force: true }); } - await ensureDir(releaseDir) + await ensureDir(releaseDir); if (!args.skipTests) { - const testExit = await run({ cmd: ["bun", "test"], cwd: repoRoot }) - if (testExit !== 0) return testExit + const testExit = await run({ cmd: ["bun", "test"], cwd: repoRoot }); + if (testExit !== 0) { + return testExit; + } } - const binaryPath = resolve(distRoot, "hack") + const binaryPath = resolve(distRoot, "hack"); const buildExit = await run({ cmd: ["bun", "build", "index.ts", "--compile", "--outfile", binaryPath], - cwd: repoRoot - }) - if (buildExit !== 0) return buildExit + cwd: repoRoot, + }); + if (buildExit !== 0) { + return buildExit; + } - await copyFile({ from: binaryPath, to: resolve(releaseDir, "hack") }) + await copyFile({ from: binaryPath, to: resolve(releaseDir, "hack") }); - const assetsDir = resolve(releaseDir, "assets") - const gifsDir = resolve(assetsDir, "gifs") - const schemasDir = resolve(assetsDir, "schemas") - await ensureDir(gifsDir) - await ensureDir(schemasDir) + const assetsDir = resolve(releaseDir, "assets"); + const gifsDir = resolve(assetsDir, "gifs"); + const schemasDir = resolve(assetsDir, "schemas"); + await ensureDir(gifsDir); + await ensureDir(schemasDir); - await copyIfPresent({ path: resolve(repoRoot, "assets/cut.gif"), destDir: gifsDir }) - await copyIfPresent({ path: resolve(repoRoot, "assets/hacker-mash.gif"), destDir: gifsDir }) + await copyIfPresent({ + path: resolve(repoRoot, "assets/cut.gif"), + destDir: gifsDir, + }); + await copyIfPresent({ + path: resolve(repoRoot, "assets/hacker-mash.gif"), + destDir: gifsDir, + }); - await Bun.write(resolve(schemasDir, "hack.config.schema.json"), renderProjectConfigSchemaJson()) + await Bun.write( + resolve(schemasDir, "hack.config.schema.json"), + renderProjectConfigSchemaJson() + ); await Bun.write( resolve(schemasDir, "hack.branches.schema.json"), renderProjectBranchesSchemaJson() - ) + ); - const gumSourceDir = resolve(repoRoot, "binaries", "gum") - const gumDestDir = resolve(releaseDir, "binaries", "gum") - const gumFiles = await listFiles({ dir: gumSourceDir }) + const gumSourceDir = resolve(repoRoot, "binaries", "gum"); + const gumDestDir = resolve(releaseDir, "binaries", "gum"); + const gumFiles = await listFiles({ dir: gumSourceDir }); if (gumFiles.length > 0) { - await ensureDir(gumDestDir) + await ensureDir(gumDestDir); for (const file of gumFiles) { - await copyFile({ from: resolve(gumSourceDir, file), to: resolve(gumDestDir, file) }) + await copyFile({ + from: resolve(gumSourceDir, file), + to: resolve(gumDestDir, file), + }); } } - await copyIfPresent({ path: resolve(repoRoot, "README.md"), destDir: releaseDir }) + await copyIfPresent({ + path: resolve(repoRoot, "README.md"), + destDir: releaseDir, + }); - const installScriptPath = resolve(releaseDir, "install.sh") - await Bun.write(installScriptPath, renderInstallScript()) - await chmodExecutable({ path: installScriptPath }) + const installScriptPath = resolve(releaseDir, "install.sh"); + await Bun.write(installScriptPath, renderInstallScript()); + await chmodExecutable({ path: installScriptPath }); - const checksumPath = resolve(releaseDir, "SHA256SUMS") - await Bun.write(checksumPath, await renderChecksums({ root: releaseDir })) + const checksumPath = resolve(releaseDir, "SHA256SUMS"); + await Bun.write(checksumPath, await renderChecksums({ root: releaseDir })); - const tarballName = `hack-${version}-${target.platform}-${target.arch}.tar.gz` - const tarballPath = resolve(releaseRoot, tarballName) + const tarballName = `hack-${version}-${target.platform}-${target.arch}.tar.gz`; + const tarballPath = resolve(releaseRoot, tarballName); const tarExit = await run({ cmd: ["tar", "-czf", tarballPath, "-C", releaseRoot, releaseDirName], - cwd: repoRoot - }) - if (tarExit !== 0) return tarExit - - const downloadScriptName = `hack-${version}-install.sh` - const downloadScriptPath = resolve(releaseRoot, downloadScriptName) - const downloadScriptAltPath = resolve(releaseRoot, "hack-install.sh") - const downloadScript = renderDownloadInstallScript() - await Bun.write(downloadScriptPath, downloadScript) - await Bun.write(downloadScriptAltPath, downloadScript) - await chmodExecutable({ path: downloadScriptPath }) - await chmodExecutable({ path: downloadScriptAltPath }) + cwd: repoRoot, + }); + if (tarExit !== 0) { + return tarExit; + } + + const downloadScriptName = `hack-${version}-install.sh`; + const downloadScriptPath = resolve(releaseRoot, downloadScriptName); + const downloadScriptAltPath = resolve(releaseRoot, "hack-install.sh"); + const downloadScript = renderDownloadInstallScript(); + await Bun.write(downloadScriptPath, downloadScript); + await Bun.write(downloadScriptAltPath, downloadScript); + await chmodExecutable({ path: downloadScriptPath }); + await chmodExecutable({ path: downloadScriptAltPath }); process.stdout.write( - [ + `${[ "Release prepared:", ` Dir: ${releaseDir}`, ` Tarball: ${tarballPath}`, ` Install script: ${downloadScriptPath}`, - ` Install script (latest): ${downloadScriptAltPath}` - ].join("\n") + "\n" - ) - return 0 + ` Install script (latest): ${downloadScriptAltPath}`, + ].join("\n")}\n` + ); + return 0; } -function parseArgs({ argv }: { readonly argv: readonly string[] }): ParseOk | ParseErr { - let outDirRaw: string | null = null - let versionOverride: string | null = null - let skipTests = false - let noClean = false +function parseArgs({ + argv, +}: { + readonly argv: readonly string[]; +}): ParseOk | ParseErr { + let outDirRaw: string | null = null; + let versionOverride: string | null = null; + let skipTests = false; + let noClean = false; for (const arg of argv) { if (arg === "--skip-tests") { - skipTests = true - continue + skipTests = true; + continue; } if (arg === "--no-clean") { - noClean = true - continue + noClean = true; + continue; } if (arg.startsWith("--out=")) { - const value = arg.slice("--out=".length).trim() - if (value.length === 0) return { ok: false, message: "Invalid --out (empty)" } - outDirRaw = value - continue + const value = arg.slice("--out=".length).trim(); + if (value.length === 0) { + return { ok: false, message: "Invalid --out (empty)" }; + } + outDirRaw = value; + continue; } if (arg.startsWith("--version=")) { - const value = arg.slice("--version=".length).trim() - if (value.length === 0) return { ok: false, message: "Invalid --version (empty)" } - versionOverride = value - continue + const value = arg.slice("--version=".length).trim(); + if (value.length === 0) { + return { ok: false, message: "Invalid --version (empty)" }; + } + versionOverride = value; + continue; } if (arg === "--help" || arg === "-h") { return { @@ -167,69 +209,92 @@ function parseArgs({ argv }: { readonly argv: readonly string[] }): ParseOk | Pa "Usage:", " bun run scripts/build-release.ts [--out=dist/release] [--version=X.Y.Z]", " [--skip-tests] [--no-clean]", - "" - ].join("\n") - } + "", + ].join("\n"), + }; } - return { ok: false, message: `Unknown arg: ${arg}` } + return { ok: false, message: `Unknown arg: ${arg}` }; } return { ok: true, - args: { outDirRaw, versionOverride, skipTests, noClean } - } + args: { outDirRaw, versionOverride, skipTests, noClean }, + }; } async function run({ cmd, - cwd + cwd, }: { - readonly cmd: readonly string[] - readonly cwd: string + readonly cmd: readonly string[]; + readonly cwd: string; }): Promise { - const proc = Bun.spawn([...cmd], { cwd, stdin: "inherit", stdout: "inherit", stderr: "inherit" }) - return await proc.exited + const proc = Bun.spawn([...cmd], { + cwd, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + return await proc.exited; } async function ensureDir(path: string): Promise { - await mkdir(path, { recursive: true }) + await mkdir(path, { recursive: true }); } async function listFiles({ dir }: { readonly dir: string }): Promise { try { - const entries = await readdir(dir) - return entries.filter(entry => !entry.startsWith(".")).sort() + const entries = await readdir(dir); + return entries.filter((entry) => !entry.startsWith(".")).sort(); } catch { - return [] + return []; } } async function fileExists(path: string): Promise { try { - await Bun.file(path).stat() - return true + await Bun.file(path).stat(); + return true; } catch { - return false + return false; } } -async function copyIfPresent({ path, destDir }: { readonly path: string; readonly destDir: string }) { - const exists = await fileExists(path) - if (!exists) return - await copyFile({ from: path, to: resolve(destDir, basename(path)) }) +async function copyIfPresent({ + path, + destDir, +}: { + readonly path: string; + readonly destDir: string; +}) { + const exists = await fileExists(path); + if (!exists) { + return; + } + await copyFile({ from: path, to: resolve(destDir, basename(path)) }); } -async function copyFile({ from, to }: { readonly from: string; readonly to: string }): Promise { - await Bun.write(to, Bun.file(from)) +async function copyFile({ + from, + to, +}: { + readonly from: string; + readonly to: string; +}): Promise { + await Bun.write(to, Bun.file(from)); } -async function chmodExecutable({ path }: { readonly path: string }): Promise { +async function chmodExecutable({ + path, +}: { + readonly path: string; +}): Promise { const proc = Bun.spawn(["chmod", "+x", path], { stdin: "ignore", stdout: "ignore", - stderr: "ignore" - }) - await proc.exited + stderr: "ignore", + }); + await proc.exited; } function renderInstallScript(): string { @@ -237,122 +302,122 @@ function renderInstallScript(): string { "#!/usr/bin/env bash", "set -euo pipefail", "", - "ROOT=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"", - "INSTALL_BIN=\"${HACK_INSTALL_BIN:-$HOME/.hack/bin}\"", - "INSTALL_ASSETS=\"${HACK_INSTALL_ASSETS:-$HOME/.hack/assets}\"", - "ASSETS_DIR=\"$ROOT/assets\"", - "BINARIES_DIR=\"$ROOT/binaries\"", + 'ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"', + 'INSTALL_BIN="${HACK_INSTALL_BIN:-$HOME/.hack/bin}"', + 'INSTALL_ASSETS="${HACK_INSTALL_ASSETS:-$HOME/.hack/assets}"', + 'ASSETS_DIR="$ROOT/assets"', + 'BINARIES_DIR="$ROOT/binaries"', "", - "mkdir -p \"$INSTALL_BIN\" \"$INSTALL_ASSETS\"", - "cp \"$ROOT/hack\" \"$INSTALL_BIN/hack\"", - "chmod +x \"$INSTALL_BIN/hack\"", + 'mkdir -p "$INSTALL_BIN" "$INSTALL_ASSETS"', + 'cp "$ROOT/hack" "$INSTALL_BIN/hack"', + 'chmod +x "$INSTALL_BIN/hack"', "", - "if [ -d \"$ASSETS_DIR\" ]; then", - " mkdir -p \"$INSTALL_ASSETS\"", - " cp -R \"$ASSETS_DIR/.\" \"$INSTALL_ASSETS\"", + 'if [ -d "$ASSETS_DIR" ]; then', + ' mkdir -p "$INSTALL_ASSETS"', + ' cp -R "$ASSETS_DIR/." "$INSTALL_ASSETS"', "fi", "", - "if [ -d \"$BINARIES_DIR\" ]; then", - " mkdir -p \"$INSTALL_ASSETS/binaries\"", - " cp -R \"$BINARIES_DIR/.\" \"$INSTALL_ASSETS/binaries\"", + 'if [ -d "$BINARIES_DIR" ]; then', + ' mkdir -p "$INSTALL_ASSETS/binaries"', + ' cp -R "$BINARIES_DIR/." "$INSTALL_ASSETS/binaries"', "fi", "", - "has_cmd() { command -v \"$1\" >/dev/null 2>&1; }", + 'has_cmd() { command -v "$1" >/dev/null 2>&1; }', "", "prompt_confirm() {", - " local prompt=\"$1\"", - " local default=\"${2:-n}\"", - " if [ \"${HACK_INSTALL_NONINTERACTIVE:-}\" = \"1\" ]; then", - " [ \"$default\" = \"y\" ] && return 0 || return 1", + ' local prompt="$1"', + ' local default="${2:-n}"', + ' if [ "${HACK_INSTALL_NONINTERACTIVE:-}" = "1" ]; then', + ' [ "$default" = "y" ] && return 0 || return 1', " fi", - " local suffix=\"[y/N]\"", - " if [ \"$default\" = \"y\" ]; then", - " suffix=\"[Y/n]\"", + ' local suffix="[y/N]"', + ' if [ "$default" = "y" ]; then', + ' suffix="[Y/n]"', " fi", " if has_cmd gum; then", - " if [ \"$default\" = \"y\" ]; then", - " gum confirm \"$prompt\" && return 0 || return 1", + ' if [ "$default" = "y" ]; then', + ' gum confirm "$prompt" && return 0 || return 1', " else", - " gum confirm --default=false \"$prompt\" && return 0 || return 1", + ' gum confirm --default=false "$prompt" && return 0 || return 1', " fi", " fi", - " read -r -p \"$prompt $suffix \" reply", - " if [ -z \"$reply\" ]; then", - " reply=\"$default\"", + ' read -r -p "$prompt $suffix " reply', + ' if [ -z "$reply" ]; then', + ' reply="$default"', " fi", - " case \"$reply\" in", + ' case "$reply" in', " y|Y|yes|YES) return 0 ;;", " *) return 1 ;;", " esac", "}", "", "ensure_brew_pkg() {", - " local pkg=\"$1\"", - " local reason=\"$2\"", - " local default=\"$3\"", + ' local pkg="$1"', + ' local reason="$2"', + ' local default="$3"', " if ! has_cmd brew; then", - " echo \"Homebrew not found; skipping $pkg install ($reason).\"", + ' echo "Homebrew not found; skipping $pkg install ($reason)."', " return", " fi", - " if brew list \"$pkg\" >/dev/null 2>&1; then", + ' if brew list "$pkg" >/dev/null 2>&1; then', " return", " fi", - " if prompt_confirm \"Install $pkg via Homebrew? ($reason)\" \"$default\"; then", - " brew install \"$pkg\"", + ' if prompt_confirm "Install $pkg via Homebrew? ($reason)" "$default"; then', + ' brew install "$pkg"', " else", - " echo \"Skipping $pkg install.\"", + ' echo "Skipping $pkg install."', " fi", "}", "", "if has_cmd docker; then", " :", "else", - " echo \"Docker not found. Install Docker before running hack.\"", + ' echo "Docker not found. Install Docker before running hack."', "fi", "", - "ensure_brew_pkg \"chafa\" \"used for hack the planet\" \"y\"", - "ensure_brew_pkg \"dnsmasq\" \"required for *.hack DNS\" \"y\"", - "ensure_brew_pkg \"mkcert\" \"used for hack global cert\" \"n\"", + 'ensure_brew_pkg "chafa" "used for hack the planet" "y"', + 'ensure_brew_pkg "dnsmasq" "required for *.hack DNS" "y"', + 'ensure_brew_pkg "mkcert" "used for hack global cert" "n"', "", - "echo \"Installed hack to $INSTALL_BIN/hack\"", - "if [[ \":$PATH:\" != *\":$INSTALL_BIN:\"* ]]; then", - " if prompt_confirm \"Add hack to PATH by updating your shell config?\" \"y\"; then", - " shell_name=\"$(basename \"${SHELL:-}\")\"", - " if [ \"$shell_name\" = \"zsh\" ]; then", - " rc_file=\"$HOME/.zshrc\"", - " elif [ \"$shell_name\" = \"bash\" ]; then", - " rc_file=\"$HOME/.bashrc\"", + 'echo "Installed hack to $INSTALL_BIN/hack"', + 'if [[ ":$PATH:" != *":$INSTALL_BIN:"* ]]; then', + ' if prompt_confirm "Add hack to PATH by updating your shell config?" "y"; then', + ' shell_name="$(basename "${SHELL:-}")"', + ' if [ "$shell_name" = "zsh" ]; then', + ' rc_file="$HOME/.zshrc"', + ' elif [ "$shell_name" = "bash" ]; then', + ' rc_file="$HOME/.bashrc"', " else", - " rc_file=\"$HOME/.profile\"", + ' rc_file="$HOME/.profile"', " fi", - " line=\"export PATH=\\\"$INSTALL_BIN:\\$PATH\\\"\"", - " assets_line=\"export HACK_ASSETS_DIR=\\\"$INSTALL_ASSETS\\\"\"", - " if [ -f \"$rc_file\" ] && grep -Fq \"$line\" \"$rc_file\"; then", + ' line="export PATH=\\"$INSTALL_BIN:\\$PATH\\""', + ' assets_line="export HACK_ASSETS_DIR=\\"$INSTALL_ASSETS\\""', + ' if [ -f "$rc_file" ] && grep -Fq "$line" "$rc_file"; then', " :", " else", - " echo \"$line\" >> \"$rc_file\"", + ' echo "$line" >> "$rc_file"', " fi", - " if [ -f \"$rc_file\" ] && grep -Fq \"$assets_line\" \"$rc_file\"; then", + ' if [ -f "$rc_file" ] && grep -Fq "$assets_line" "$rc_file"; then', " :", " else", - " echo \"$assets_line\" >> \"$rc_file\"", + ' echo "$assets_line" >> "$rc_file"', " fi", - " export PATH=\"$INSTALL_BIN:$PATH\"", + ' export PATH="$INSTALL_BIN:$PATH"', " else", - " echo \"Add $INSTALL_BIN to PATH if needed:\"", - " echo \" export PATH=\\\"$INSTALL_BIN:\\$PATH\\\"\"", + ' echo "Add $INSTALL_BIN to PATH if needed:"', + ' echo " export PATH=\\"$INSTALL_BIN:\\$PATH\\""', " fi", "fi", - "if [ -z \"${HACK_ASSETS_DIR:-}\" ]; then", - " export HACK_ASSETS_DIR=\"$INSTALL_ASSETS\"", + 'if [ -z "${HACK_ASSETS_DIR:-}" ]; then', + ' export HACK_ASSETS_DIR="$INSTALL_ASSETS"', "fi", - "if prompt_confirm \"Run 'hack global install' now?\" \"y\"; then", - " \"$INSTALL_BIN/hack\" global install || true", + 'if prompt_confirm "Run \'hack global install\' now?" "y"; then', + ' "$INSTALL_BIN/hack" global install || true', "else", - " echo \"Next: hack global install\"", + ' echo "Next: hack global install"', "fi", - "" - ].join("\n") + "", + ].join("\n"); } function renderDownloadInstallScript(): string { @@ -360,112 +425,130 @@ function renderDownloadInstallScript(): string { "#!/usr/bin/env bash", "set -euo pipefail", "", - "REPO_OWNER=\"hack-dance\"", - "REPO_NAME=\"hack-cli\"", - "REPO=\"$REPO_OWNER/$REPO_NAME\"", - "API_URL=\"https://api.github.com/repos/$REPO/releases/latest\"", - "BASE_URL=\"${HACK_RELEASE_BASE_URL:-https://github.com/$REPO/releases/download}\"", + 'REPO_OWNER="hack-dance"', + 'REPO_NAME="hack-cli"', + 'REPO="$REPO_OWNER/$REPO_NAME"', + 'API_URL="https://api.github.com/repos/$REPO/releases/latest"', + 'BASE_URL="${HACK_RELEASE_BASE_URL:-https://github.com/$REPO/releases/download}"', "", - "if [ -n \"${HACK_INSTALL_TAG:-}\" ]; then", - " TAG=\"$HACK_INSTALL_TAG\"", - "elif [ -n \"${HACK_INSTALL_VERSION:-}\" ]; then", - " TAG=\"v$HACK_INSTALL_VERSION\"", + 'if [ -n "${HACK_INSTALL_TAG:-}" ]; then', + ' TAG="$HACK_INSTALL_TAG"', + 'elif [ -n "${HACK_INSTALL_VERSION:-}" ]; then', + ' TAG="v$HACK_INSTALL_VERSION"', "else", - " TAG=$(curl -fsSL \"$API_URL\" | sed -n 's/.*\"tag_name\": \"\\([^\"]*\\)\".*/\\1/p' | head -n1)", + ' TAG=$(curl -fsSL "$API_URL" | sed -n \'s/.*"tag_name": "\\([^"]*\\)".*/\\1/p\' | head -n1)', "fi", "", - "if [ -z \"$TAG\" ]; then", - " echo \"Failed to resolve release tag.\"", + 'if [ -z "$TAG" ]; then', + ' echo "Failed to resolve release tag."', " exit 1", "fi", "", - "VERSION=\"${TAG#v}\"", + 'VERSION="${TAG#v}"', "OS=\"$(uname -s | tr '[:upper:]' '[:lower:]')\"", - "ARCH=\"$(uname -m)\"", - "if [ \"$ARCH\" = \"x86_64\" ] || [ \"$ARCH\" = \"amd64\" ]; then", - " ARCH=\"x86_64\"", - "elif [ \"$ARCH\" = \"arm64\" ] || [ \"$ARCH\" = \"aarch64\" ]; then", - " ARCH=\"arm64\"", + 'ARCH="$(uname -m)"', + 'if [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "amd64" ]; then', + ' ARCH="x86_64"', + 'elif [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then', + ' ARCH="arm64"', "else", - " echo \"Unsupported architecture: $ARCH\"", + ' echo "Unsupported architecture: $ARCH"', " exit 1", "fi", "", - "if [ \"$OS\" != \"darwin\" ] && [ \"$OS\" != \"linux\" ]; then", - " echo \"Unsupported OS: $OS\"", + 'if [ "$OS" != "darwin" ] && [ "$OS" != "linux" ]; then', + ' echo "Unsupported OS: $OS"', " exit 1", "fi", "", - "TARBALL=\"hack-$VERSION-$OS-$ARCH.tar.gz\"", - "URL=\"$BASE_URL/$TAG/$TARBALL\"", + 'TARBALL="hack-$VERSION-$OS-$ARCH.tar.gz"', + 'URL="$BASE_URL/$TAG/$TARBALL"', "", "tmpdir=$(mktemp -d)", - "cleanup() { rm -rf \"$tmpdir\"; }", + 'cleanup() { rm -rf "$tmpdir"; }', "trap cleanup EXIT", "", - "echo \"Downloading $URL\"", - "curl -fsSL \"$URL\" -o \"$tmpdir/$TARBALL\"", - "tar -xzf \"$tmpdir/$TARBALL\" -C \"$tmpdir\"", + 'echo "Downloading $URL"', + 'curl -fsSL "$URL" -o "$tmpdir/$TARBALL"', + 'tar -xzf "$tmpdir/$TARBALL" -C "$tmpdir"', "", - "INSTALL_DIR=\"$tmpdir/hack-$VERSION-release\"", - "if [ ! -d \"$INSTALL_DIR\" ]; then", - " echo \"Missing release directory: $INSTALL_DIR\"", + 'INSTALL_DIR="$tmpdir/hack-$VERSION-release"', + 'if [ ! -d "$INSTALL_DIR" ]; then', + ' echo "Missing release directory: $INSTALL_DIR"', " exit 1", "fi", "", - "bash \"$INSTALL_DIR/install.sh\"", - "" - ].join("\n") + 'bash "$INSTALL_DIR/install.sh"', + "", + ].join("\n"); } -type ReleaseTarget = { - readonly platform: string - readonly arch: string +interface ReleaseTarget { + readonly platform: string; + readonly arch: string; } function resolveTarget(): ReleaseTarget | null { const platform = - process.platform === "darwin" ? "darwin" - : process.platform === "linux" ? "linux" - : null - if (!platform) return null + process.platform === "darwin" + ? "darwin" + : process.platform === "linux" + ? "linux" + : null; + if (!platform) { + return null; + } const arch = - process.arch === "arm64" ? "arm64" - : process.arch === "x64" ? "x86_64" - : null - if (!arch) return null + process.arch === "arm64" + ? "arm64" + : process.arch === "x64" + ? "x86_64" + : null; + if (!arch) { + return null; + } - return { platform, arch } + return { platform, arch }; } -async function renderChecksums({ root }: { readonly root: string }): Promise { - const files = await walkFiles({ root }) - const lines: string[] = [] +async function renderChecksums({ + root, +}: { + readonly root: string; +}): Promise { + const files = await walkFiles({ root }); + const lines: string[] = []; for (const file of files) { - const rel = relative(root, file) - const data = await Bun.file(file).arrayBuffer() - const hasher = new Bun.CryptoHasher("sha256") - hasher.update(new Uint8Array(data)) - const hash = hasher.digest("hex") - lines.push(`${hash} ${rel}`) + const rel = relative(root, file); + const data = await Bun.file(file).arrayBuffer(); + const hasher = new Bun.CryptoHasher("sha256"); + hasher.update(new Uint8Array(data)); + const hash = hasher.digest("hex"); + lines.push(`${hash} ${rel}`); } - return lines.join("\n") + "\n" + return `${lines.join("\n")}\n`; } -async function walkFiles({ root }: { readonly root: string }): Promise { - const out: string[] = [] - const entries = await readdir(root, { withFileTypes: true }) +async function walkFiles({ + root, +}: { + readonly root: string; +}): Promise { + const out: string[] = []; + const entries = await readdir(root, { withFileTypes: true }); for (const entry of entries) { - const path = resolve(root, entry.name) + const path = resolve(root, entry.name); if (entry.isDirectory()) { - const nested = await walkFiles({ root: path }) - out.push(...nested) - continue + const nested = await walkFiles({ root: path }); + out.push(...nested); + continue; + } + if (entry.isFile()) { + out.push(path); } - if (entry.isFile()) out.push(path) } - return out.sort() + return out.sort(); } diff --git a/scripts/gateway-e2e.ts b/scripts/gateway-e2e.ts index e5d91ad0..7fa7274c 100644 --- a/scripts/gateway-e2e.ts +++ b/scripts/gateway-e2e.ts @@ -1,20 +1,22 @@ -import { fileURLToPath } from "node:url" +import { fileURLToPath } from "node:url"; -const testPath = fileURLToPath(new URL("../tests/gateway-e2e.test.ts", import.meta.url)) -const command = [process.execPath, "test", testPath] -const cwd = process.env.HACK_GATEWAY_E2E_CWD?.trim() || process.cwd() +const testPath = fileURLToPath( + new URL("../tests/gateway-e2e.test.ts", import.meta.url) +); +const command = [process.execPath, "test", testPath]; +const cwd = process.env.HACK_GATEWAY_E2E_CWD?.trim() || process.cwd(); const proc = Bun.spawn({ cmd: command, cwd, env: { ...process.env, HACK_GATEWAY_E2E: "1", - HACK_GATEWAY_E2E_WRITE: process.env.HACK_GATEWAY_E2E_WRITE ?? "1" + HACK_GATEWAY_E2E_WRITE: process.env.HACK_GATEWAY_E2E_WRITE ?? "1", }, stdin: "inherit", stdout: "inherit", - stderr: "inherit" -}) + stderr: "inherit", +}); -const exitCode = await proc.exited -process.exit(exitCode) +const exitCode = await proc.exited; +process.exit(exitCode); diff --git a/scripts/generate-planet-animations.ts b/scripts/generate-planet-animations.ts index e958b497..237d18d3 100644 --- a/scripts/generate-planet-animations.ts +++ b/scripts/generate-planet-animations.ts @@ -1,51 +1,57 @@ -import { basename, resolve } from "node:path" -import { readdir } from "node:fs/promises" +import { readdir } from "node:fs/promises"; +import { basename, resolve } from "node:path"; -type VariantName = "cut" | "mash" +type VariantName = "cut" | "mash"; -type VariantInput = { - readonly name: VariantName - readonly gifPath: string - readonly durationSeconds: number +interface VariantInput { + readonly name: VariantName; + readonly gifPath: string; + readonly durationSeconds: number; } -type GeneratedVariant = { - readonly name: VariantName - readonly fps: number - readonly framesGzipBase64: string +interface GeneratedVariant { + readonly name: VariantName; + readonly fps: number; + readonly framesGzipBase64: string; } -const FPS = 20 -const SIZE = "120x32" +const FPS = 20; +const SIZE = "120x32"; -const repoRoot = resolve(import.meta.dir, "..") +const repoRoot = resolve(import.meta.dir, ".."); async function main(): Promise { const variants: readonly VariantInput[] = [ - { name: "cut", gifPath: resolve(repoRoot, "assets/cut.gif"), durationSeconds: 10 }, + { + name: "cut", + gifPath: resolve(repoRoot, "assets/cut.gif"), + durationSeconds: 10, + }, { name: "mash", gifPath: resolve(repoRoot, "hacker-mash.gif"), - durationSeconds: 15 - } - ] + durationSeconds: 15, + }, + ]; - const outputs: GeneratedVariant[] = [] + const outputs: GeneratedVariant[] = []; for (const v of variants) { - outputs.push(await generateVariant(v)) + outputs.push(await generateVariant(v)); } - const outFile = resolve(repoRoot, "src/ui/planet-animations.data.ts") - await writeTextFile(outFile, renderTs(outputs)) - process.stdout.write(`Wrote ${basename(outFile)} (${outputs.length} variants)\n`) + const outFile = resolve(repoRoot, "src/ui/planet-animations.data.ts"); + await writeTextFile(outFile, renderTs(outputs)); + process.stdout.write( + `Wrote ${basename(outFile)} (${outputs.length} variants)\n` + ); } async function generateVariant(input: VariantInput): Promise { - const tmpDir = resolve("/tmp", `hack-planet-${input.name}`) - await run(["rm", "-rf", tmpDir]) - await run(["mkdir", "-p", tmpDir]) + const tmpDir = resolve("/tmp", `hack-planet-${input.name}`); + await run(["rm", "-rf", tmpDir]); + await run(["mkdir", "-p", tmpDir]); - const framePattern = resolve(tmpDir, "frame-%04d.png") + const framePattern = resolve(tmpDir, "frame-%04d.png"); await run([ "ffmpeg", "-hide_banner", @@ -58,29 +64,29 @@ async function generateVariant(input: VariantInput): Promise { String(input.durationSeconds), "-vf", `fps=${FPS}`, - framePattern - ]) + framePattern, + ]); const files = (await readdir(tmpDir)) - .filter(f => f.endsWith(".png")) - .sort((a, b) => a.localeCompare(b)) + .filter((f) => f.endsWith(".png")) + .sort((a, b) => a.localeCompare(b)); if (files.length === 0) { - throw new Error(`No frames extracted for ${input.name}`) + throw new Error(`No frames extracted for ${input.name}`); } - const frames: string[] = [] + const frames: string[] = []; for (const file of files) { - const framePath = resolve(tmpDir, file) - const frame = await renderFrame(framePath) - frames.push(frame) + const framePath = resolve(tmpDir, file); + const frame = await renderFrame(framePath); + frames.push(frame); } - const payload = JSON.stringify({ frames }) - const gz = Bun.gzipSync(new TextEncoder().encode(payload)) - const base64 = Buffer.from(gz).toString("base64") + const payload = JSON.stringify({ frames }); + const gz = Bun.gzipSync(new TextEncoder().encode(payload)); + const base64 = Buffer.from(gz).toString("base64"); - return { name: input.name, fps: FPS, framesGzipBase64: base64 } + return { name: input.name, fps: FPS, framesGzipBase64: base64 }; } async function renderFrame(framePath: string): Promise { @@ -97,19 +103,19 @@ async function renderFrame(framePath: string): Promise { "--preprocess=off", "--work=1", "--optimize=9", - "--relative=off" - ]) + "--relative=off", + ]); // Keep frames deterministic + avoid per-frame cursor flicker (player controls cursor visibility). - return stdout.replaceAll("\x1b[?25l", "").replaceAll("\x1b[?25h", "") + return stdout.replaceAll("\x1b[?25l", "").replaceAll("\x1b[?25h", ""); } function chunkString(input: string, size: number): string[] { - const out: string[] = [] + const out: string[] = []; for (let i = 0; i < input.length; i += size) { - out.push(input.slice(i, i + size)) + out.push(input.slice(i, i + size)); } - return out + return out; } function renderTs(variants: readonly GeneratedVariant[]): string { @@ -117,36 +123,38 @@ function renderTs(variants: readonly GeneratedVariant[]): string { "// @generated by `bun scripts/generate-planet-animations.ts`", "// Do not edit by hand.", "", - "export const PLANET_ANIMATIONS_DATA = [" - ] + "export const PLANET_ANIMATIONS_DATA = [", + ]; - const body = variants.flatMap(v => { - const chunks = chunkString(v.framesGzipBase64, 120) + const body = variants.flatMap((v) => { + const chunks = chunkString(v.framesGzipBase64, 120); return [ " {", - ` name: \"${v.name}\",`, + ` name: "${v.name}",`, ` fps: ${v.fps},`, " framesGzipBase64: [", - ...chunks.map(c => ` \"${c}\",`), + ...chunks.map((c) => ` "${c}",`), ' ].join(""),', - " }," - ] - }) + " },", + ]; + }); - const footer = ["] as const;", ""] - return [...header, ...body, ...footer].join("\n") + const footer = ["] as const;", ""]; + return [...header, ...body, ...footer].join("\n"); } async function run(cmd: string[]): Promise { const proc = Bun.spawn(cmd, { stdin: "ignore", stdout: "ignore", - stderr: "pipe" - }) - const stderr = await new Response(proc.stderr).text() - const exitCode = await proc.exited + stderr: "pipe", + }); + const stderr = await new Response(proc.stderr).text(); + const exitCode = await proc.exited; if (exitCode !== 0) { - throw new Error(`Command failed (${exitCode}): ${cmd.join(" ")}\n${stderr}`) + throw new Error( + `Command failed (${exitCode}): ${cmd.join(" ")}\n${stderr}` + ); } } @@ -156,19 +164,21 @@ async function runCapture( const proc = Bun.spawn(cmd, { stdin: "ignore", stdout: "pipe", - stderr: "pipe" - }) - const stdout = await new Response(proc.stdout).text() - const stderr = await new Response(proc.stderr).text() - const exitCode = await proc.exited + stderr: "pipe", + }); + const stdout = await new Response(proc.stdout).text(); + const stderr = await new Response(proc.stderr).text(); + const exitCode = await proc.exited; if (exitCode !== 0) { - throw new Error(`Command failed (${exitCode}): ${cmd.join(" ")}\n${stderr}`) + throw new Error( + `Command failed (${exitCode}): ${cmd.join(" ")}\n${stderr}` + ); } - return { stdout, stderr } + return { stdout, stderr }; } async function writeTextFile(path: string, content: string): Promise { - await Bun.write(path, content) + await Bun.write(path, content); } -await main() +await main(); diff --git a/scripts/install-cli.ts b/scripts/install-cli.ts index c8abb940..d023b1f0 100644 --- a/scripts/install-cli.ts +++ b/scripts/install-cli.ts @@ -1,112 +1,122 @@ #!/usr/bin/env bun -import { dirname, resolve } from "node:path" -import { lstat, readlink, rm, symlink } from "node:fs/promises" +import { lstat, readlink, rm, symlink } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; -import { ensureDir, readTextFile, writeTextFile } from "../src/lib/fs.ts" +import { ensureDir, readTextFile, writeTextFile } from "../src/lib/fs.ts"; -type InstallMode = "dev" | "bin" +type InstallMode = "dev" | "bin"; -const CLI_NAME = "hack" as const -const DEFAULT_INSTALL_DIR_RELATIVE = ".hack/bin" as const +const CLI_NAME = "hack" as const; +const DEFAULT_INSTALL_DIR_RELATIVE = ".hack/bin" as const; -type ParseOk = { - readonly ok: true - readonly mode: InstallMode - readonly installDirRaw: string | null - readonly force: boolean +interface ParseOk { + readonly ok: true; + readonly mode: InstallMode; + readonly installDirRaw: string | null; + readonly force: boolean; } -type ParseErr = { readonly ok: false; readonly message: string } +interface ParseErr { + readonly ok: false; + readonly message: string; +} -const parsed = parseArgs(Bun.argv.slice(2)) -if (!parsed.ok) { - process.stderr.write(parsed.message + "\n") - process.exitCode = 1 +const parsed = parseArgs(Bun.argv.slice(2)); +if (parsed.ok) { + process.exitCode = await main(parsed); } else { - process.exitCode = await main(parsed) + process.stderr.write(`${parsed.message}\n`); + process.exitCode = 1; } async function main(parsed: ParseOk): Promise { - const repoRoot = resolve(import.meta.dir, "..") + const repoRoot = resolve(import.meta.dir, ".."); - const home = (process.env.HOME ?? "").trim() + const home = (process.env.HOME ?? "").trim(); if (home.length === 0) { - process.stderr.write("HOME is not set; cannot determine install directory.\n") - return 1 + process.stderr.write( + "HOME is not set; cannot determine install directory.\n" + ); + return 1; } - const installDir = resolveInstallDir({ home, installDirRaw: parsed.installDirRaw }) - await ensureDir(installDir) + const installDir = resolveInstallDir({ + home, + installDirRaw: parsed.installDirRaw, + }); + await ensureDir(installDir); - const targetPath = resolve(installDir, CLI_NAME) - let desired: DesiredInstall + const targetPath = resolve(installDir, CLI_NAME); + let desired: DesiredInstall; try { desired = await desiredInstall({ mode: parsed.mode, repoRoot, installDir, - targetPath - }) + targetPath, + }); } catch (error: unknown) { - const message = error instanceof Error ? error.message : "Unknown error" - process.stderr.write(message + "\n") - return 1 + const message = error instanceof Error ? error.message : "Unknown error"; + process.stderr.write(`${message}\n`); + return 1; } - const current = await readCurrentInstall(targetPath) + const current = await readCurrentInstall(targetPath); if (current.status === "present" && isSameInstall({ current, desired })) { printSuccess({ mode: parsed.mode, installDir, targetPath, repoRoot, - note: "Already installed" - }) - return 0 + note: "Already installed", + }); + return 0; } if (current.status === "present" && !parsed.force) { - process.stderr.write(`Refusing to overwrite existing '${CLI_NAME}' at:\n`) - process.stderr.write(` ${targetPath}\n`) - process.stderr.write("Re-run with --force to replace it.\n") - return 1 + process.stderr.write(`Refusing to overwrite existing '${CLI_NAME}' at:\n`); + process.stderr.write(` ${targetPath}\n`); + process.stderr.write("Re-run with --force to replace it.\n"); + return 1; } if (current.status === "present") { - await rm(targetPath, { force: true }) + await rm(targetPath, { force: true }); } - await applyInstall({ desired }) - printSuccess({ mode: parsed.mode, installDir, targetPath, repoRoot }) - return 0 + await applyInstall({ desired }); + printSuccess({ mode: parsed.mode, installDir, targetPath, repoRoot }); + return 0; } function parseArgs(argv: readonly string[]): ParseOk | ParseErr { - let mode: InstallMode = "dev" - let installDirRaw: string | null = null - let force = false + let mode: InstallMode = "dev"; + let installDirRaw: string | null = null; + let force = false; for (const arg of argv) { if (arg === "--force") { - force = true - continue + force = true; + continue; } if (arg.startsWith("--mode=")) { - const v = arg.slice("--mode=".length).trim() + const v = arg.slice("--mode=".length).trim(); if (v === "dev" || v === "bin") { - mode = v - continue + mode = v; + continue; } - return { ok: false, message: `Invalid --mode: ${v} (expected dev|bin)` } + return { ok: false, message: `Invalid --mode: ${v} (expected dev|bin)` }; } if (arg.startsWith("--dir=")) { - const v = arg.slice("--dir=".length).trim() - if (v.length === 0) return { ok: false, message: "Invalid --dir (empty)" } - installDirRaw = v - continue + const v = arg.slice("--dir=".length).trim(); + if (v.length === 0) { + return { ok: false, message: "Invalid --dir (empty)" }; + } + installDirRaw = v; + continue; } if (arg === "--help" || arg === "-h") { @@ -121,48 +131,48 @@ function parseArgs(argv: readonly string[]): ParseOk | ParseErr { "Modes:", " --mode=dev Install a wrapper that runs this repo's source via Bun (fastest iteration).", " --mode=bin Install a symlink to dist/hack (compiled binary).", - "" - ].join("\n") - } + "", + ].join("\n"), + }; } - return { ok: false, message: `Unknown arg: ${arg}` } + return { ok: false, message: `Unknown arg: ${arg}` }; } - return { ok: true, mode, installDirRaw, force } + return { ok: true, mode, installDirRaw, force }; } function resolveInstallDir(opts: { - readonly home: string - readonly installDirRaw: string | null + readonly home: string; + readonly installDirRaw: string | null; }): string { if (opts.installDirRaw && opts.installDirRaw.trim().length > 0) { - return resolve(opts.installDirRaw) + return resolve(opts.installDirRaw); } - return resolve(opts.home, DEFAULT_INSTALL_DIR_RELATIVE) + return resolve(opts.home, DEFAULT_INSTALL_DIR_RELATIVE); } type DesiredInstall = | { - readonly kind: "wrapper" - readonly mode: "dev" - readonly installDir: string - readonly targetPath: string - readonly content: string + readonly kind: "wrapper"; + readonly mode: "dev"; + readonly installDir: string; + readonly targetPath: string; + readonly content: string; } | { - readonly kind: "symlink" - readonly mode: "bin" - readonly installDir: string - readonly targetPath: string - readonly linkTarget: string - } + readonly kind: "symlink"; + readonly mode: "bin"; + readonly installDir: string; + readonly targetPath: string; + readonly linkTarget: string; + }; async function desiredInstall(opts: { - readonly mode: InstallMode - readonly repoRoot: string - readonly installDir: string - readonly targetPath: string + readonly mode: InstallMode; + readonly repoRoot: string; + readonly installDir: string; + readonly targetPath: string; }): Promise { if (opts.mode === "dev") { const content = [ @@ -170,23 +180,25 @@ async function desiredInstall(opts: { "set -euo pipefail", "# hack-cli local-dev shim (auto-generated)", "", - `exec bun ${shellQuote(resolve(opts.repoRoot, "index.ts"))} \"$@\"`, - "" - ].join("\n") + `exec bun ${shellQuote(resolve(opts.repoRoot, "index.ts"))} "$@"`, + "", + ].join("\n"); return { kind: "wrapper", mode: "dev", installDir: opts.installDir, targetPath: opts.targetPath, - content - } + content, + }; } - const linkTarget = resolve(opts.repoRoot, "dist/hack") - const exists = await fileExists(linkTarget) + const linkTarget = resolve(opts.repoRoot, "dist/hack"); + const exists = await fileExists(linkTarget); if (!exists) { - throw new Error(`Missing compiled binary at ${linkTarget}\nRun: bun run build`) + throw new Error( + `Missing compiled binary at ${linkTarget}\nRun: bun run build` + ); } return { @@ -194,107 +206,125 @@ async function desiredInstall(opts: { mode: "bin", installDir: opts.installDir, targetPath: opts.targetPath, - linkTarget - } + linkTarget, + }; } type CurrentInstall = | { readonly status: "missing" } - | { readonly status: "present"; readonly kind: "symlink"; readonly linkTarget: string } - | { readonly status: "present"; readonly kind: "file"; readonly content: string } + | { + readonly status: "present"; + readonly kind: "symlink"; + readonly linkTarget: string; + } + | { + readonly status: "present"; + readonly kind: "file"; + readonly content: string; + }; async function readCurrentInstall(targetPath: string): Promise { try { - const stat = await lstat(targetPath) + const stat = await lstat(targetPath); if (stat.isSymbolicLink()) { - const linkTargetRaw = await readlink(targetPath) - const linkTarget = resolve(dirname(targetPath), linkTargetRaw) - return { status: "present", kind: "symlink", linkTarget } + const linkTargetRaw = await readlink(targetPath); + const linkTarget = resolve(dirname(targetPath), linkTargetRaw); + return { status: "present", kind: "symlink", linkTarget }; } - const content = await readTextFile(targetPath) - return { status: "present", kind: "file", content: content ?? "" } + const content = await readTextFile(targetPath); + return { status: "present", kind: "file", content: content ?? "" }; } catch { - return { status: "missing" } + return { status: "missing" }; } } function isSameInstall(opts: { - readonly current: CurrentInstall - readonly desired: DesiredInstall + readonly current: CurrentInstall; + readonly desired: DesiredInstall; }): boolean { - if (opts.current.status !== "present") return false + if (opts.current.status !== "present") { + return false; + } if (opts.desired.kind === "symlink") { - if (opts.current.kind !== "symlink") return false - return resolve(opts.current.linkTarget) === resolve(opts.desired.linkTarget) + if (opts.current.kind !== "symlink") { + return false; + } + return ( + resolve(opts.current.linkTarget) === resolve(opts.desired.linkTarget) + ); } - if (opts.current.kind !== "file") return false - return opts.current.content === opts.desired.content + if (opts.current.kind !== "file") { + return false; + } + return opts.current.content === opts.desired.content; } -async function applyInstall(opts: { readonly desired: DesiredInstall }): Promise { +async function applyInstall(opts: { + readonly desired: DesiredInstall; +}): Promise { if (opts.desired.kind === "wrapper") { - await writeTextFile(opts.desired.targetPath, opts.desired.content) - await chmodExecutable(opts.desired.targetPath) - return + await writeTextFile(opts.desired.targetPath, opts.desired.content); + await chmodExecutable(opts.desired.targetPath); + return; } - await symlink(opts.desired.linkTarget, opts.desired.targetPath) + await symlink(opts.desired.linkTarget, opts.desired.targetPath); } async function chmodExecutable(path: string): Promise { const proc = Bun.spawn(["chmod", "+x", path], { stdin: "ignore", stdout: "ignore", - stderr: "ignore" - }) - await proc.exited + stderr: "ignore", + }); + await proc.exited; } async function fileExists(path: string): Promise { try { - await Bun.file(path).stat() - return true + await Bun.file(path).stat(); + return true; } catch { - return false + return false; } } function shellQuote(value: string): string { // Minimal safe quoting for bash. - return `"${value.replaceAll("\\\\", "\\\\\\\\").replaceAll('"', '\\\\"')}"` + return `"${value.replaceAll("\\\\", "\\\\\\\\").replaceAll('"', '\\\\"')}"`; } function printSuccess(opts: { - readonly mode: InstallMode - readonly installDir: string - readonly targetPath: string - readonly repoRoot: string - readonly note?: string + readonly mode: InstallMode; + readonly installDir: string; + readonly targetPath: string; + readonly repoRoot: string; + readonly note?: string; }): void { - const note = opts.note ? `${opts.note}. ` : "" + const note = opts.note ? `${opts.note}. ` : ""; process.stdout.write( `${note}Installed '${CLI_NAME}' (${opts.mode}) to:\n ${opts.targetPath}\n\n` - ) + ); const isOnPath = (process.env.PATH ?? "") .split(":") - .map(p => p.trim()) - .filter(p => p.length > 0) - .some(p => resolve(p) === resolve(opts.installDir)) + .map((p) => p.trim()) + .filter((p) => p.length > 0) + .some((p) => resolve(p) === resolve(opts.installDir)); if (!isOnPath) { - process.stdout.write("Add this to your shell config (e.g. ~/.zshrc):\n") - process.stdout.write(` export PATH=\"${opts.installDir}:$PATH\"\n\n`) + process.stdout.write("Add this to your shell config (e.g. ~/.zshrc):\n"); + process.stdout.write(` export PATH="${opts.installDir}:$PATH"\n\n`); } if (opts.mode === "dev") { - process.stdout.write("Dev workflow:\n") - process.stdout.write(` hack --help # runs from ${opts.repoRoot}\n\n`) + process.stdout.write("Dev workflow:\n"); + process.stdout.write(` hack --help # runs from ${opts.repoRoot}\n\n`); } else { - process.stdout.write("Binary workflow:\n") - process.stdout.write(" bun run build && hack --help\n\n") + process.stdout.write("Binary workflow:\n"); + process.stdout.write(" bun run build && hack --help\n\n"); } } diff --git a/scripts/install-status.ts b/scripts/install-status.ts index b982d3cc..adfbc835 100644 --- a/scripts/install-status.ts +++ b/scripts/install-status.ts @@ -1,61 +1,73 @@ #!/usr/bin/env bun -import { dirname, resolve } from "node:path" -import { lstat, readlink } from "node:fs/promises" +import { lstat, readlink } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; -import { readTextFile } from "../src/lib/fs.ts" +import { readTextFile } from "../src/lib/fs.ts"; -const CLI_NAME = "hack" -const DEFAULT_INSTALL_DIR_RELATIVE = ".hack/bin" +const CLI_NAME = "hack"; +const DEFAULT_INSTALL_DIR_RELATIVE = ".hack/bin"; -const home = (process.env.HOME ?? "").trim() +const home = (process.env.HOME ?? "").trim(); if (home.length === 0) { - process.stderr.write("HOME is not set; cannot determine install directory.\n") - process.exit(1) + process.stderr.write( + "HOME is not set; cannot determine install directory.\n" + ); + process.exit(1); } -const installDir = resolve(home, DEFAULT_INSTALL_DIR_RELATIVE) -const targetPath = resolve(installDir, CLI_NAME) +const installDir = resolve(home, DEFAULT_INSTALL_DIR_RELATIVE); +const targetPath = resolve(installDir, CLI_NAME); -const current = await readCurrentInstall({ targetPath }) +const current = await readCurrentInstall({ targetPath }); if (current.status === "missing") { - process.stdout.write(`No install found at:\n ${targetPath}\n`) - process.exit(0) + process.stdout.write(`No install found at:\n ${targetPath}\n`); + process.exit(0); } if (current.kind === "symlink") { - process.stdout.write("Install mode: bin (symlink)\n") - process.stdout.write(`Path: ${targetPath}\n`) - process.stdout.write(`Target: ${current.linkTarget}\n`) - process.exit(0) + process.stdout.write("Install mode: bin (symlink)\n"); + process.stdout.write(`Path: ${targetPath}\n`); + process.stdout.write(`Target: ${current.linkTarget}\n`); + process.exit(0); } -const isDevWrapper = current.content.includes("hack-cli local-dev shim") -process.stdout.write(`Install mode: ${isDevWrapper ? "dev (wrapper)" : "file (unknown)"}\n`) -process.stdout.write(`Path: ${targetPath}\n`) -process.exit(0) +const isDevWrapper = current.content.includes("hack-cli local-dev shim"); +process.stdout.write( + `Install mode: ${isDevWrapper ? "dev (wrapper)" : "file (unknown)"}\n` +); +process.stdout.write(`Path: ${targetPath}\n`); +process.exit(0); type CurrentInstall = | { readonly status: "missing" } - | { readonly status: "present"; readonly kind: "symlink"; readonly linkTarget: string } - | { readonly status: "present"; readonly kind: "file"; readonly content: string } + | { + readonly status: "present"; + readonly kind: "symlink"; + readonly linkTarget: string; + } + | { + readonly status: "present"; + readonly kind: "file"; + readonly content: string; + }; async function readCurrentInstall({ - targetPath + targetPath, }: { - readonly targetPath: string + readonly targetPath: string; }): Promise { try { - const stat = await lstat(targetPath) + const stat = await lstat(targetPath); if (stat.isSymbolicLink()) { - const linkTargetRaw = await readlink(targetPath) - const linkTarget = resolve(dirname(targetPath), linkTargetRaw) - return { status: "present", kind: "symlink", linkTarget } + const linkTargetRaw = await readlink(targetPath); + const linkTarget = resolve(dirname(targetPath), linkTargetRaw); + return { status: "present", kind: "symlink", linkTarget }; } - const content = await readTextFile(targetPath) - return { status: "present", kind: "file", content: content ?? "" } + const content = await readTextFile(targetPath); + return { status: "present", kind: "file", content: content ?? "" }; } catch { - return { status: "missing" } + return { status: "missing" }; } } diff --git a/scripts/lint.ts b/scripts/lint.ts index 13b7e527..c96bcbe7 100644 --- a/scripts/lint.ts +++ b/scripts/lint.ts @@ -1,42 +1,51 @@ #!/usr/bin/env bun -import { resolve } from "node:path" +import { resolve } from "node:path"; -type LintConfig = { - readonly cwd: string - readonly configFiles: readonly string[] +interface LintConfig { + readonly cwd: string; + readonly configFiles: readonly string[]; } -const repoRoot = resolve(import.meta.dir, "..") +const repoRoot = resolve(import.meta.dir, ".."); const config = { cwd: repoRoot, - configFiles: ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs"] -} satisfies LintConfig + configFiles: ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs"], +} satisfies LintConfig; -const hasConfig = await hasAnyConfig(config) -if (!hasConfig) { - process.stdout.write("lint: no ESLint config found; skipping.\n") - process.exitCode = 0 +const hasConfig = await hasAnyConfig(config); +if (hasConfig) { + const exitCode = await runEslint({ cwd: config.cwd }); + process.exitCode = exitCode; } else { - const exitCode = await runEslint({ cwd: config.cwd }) - process.exitCode = exitCode + process.stdout.write("lint: no ESLint config found; skipping.\n"); + process.exitCode = 0; } -async function hasAnyConfig({ cwd, configFiles }: LintConfig): Promise { +async function hasAnyConfig({ + cwd, + configFiles, +}: LintConfig): Promise { for (const file of configFiles) { - const path = resolve(cwd, file) - const exists = await fileExists({ path }) - if (exists) return true + const path = resolve(cwd, file); + const exists = await fileExists({ path }); + if (exists) { + return true; + } } - return false + return false; } -async function fileExists({ path }: { readonly path: string }): Promise { +async function fileExists({ + path, +}: { + readonly path: string; +}): Promise { try { - await Bun.file(path).stat() - return true + await Bun.file(path).stat(); + return true; } catch { - return false + return false; } } @@ -45,7 +54,7 @@ async function runEslint({ cwd }: { readonly cwd: string }): Promise { cwd, stdin: "inherit", stdout: "inherit", - stderr: "inherit" - }) - return await proc.exited + stderr: "inherit", + }); + return await proc.exited; } diff --git a/scripts/macos-ghostty-setup.ts b/scripts/macos-ghostty-setup.ts index e7c91ca0..2ce7083b 100644 --- a/scripts/macos-ghostty-setup.ts +++ b/scripts/macos-ghostty-setup.ts @@ -1,99 +1,103 @@ #!/usr/bin/env bun -import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs" -import path from "node:path" -import { $ } from "bun" +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { $ } from "bun"; -const repoRoot = path.resolve(import.meta.dir, "..") -const vendorDir = path.join(repoRoot, "apps/macos/vendor/ghostty") -const bridgeDir = path.join(repoRoot, "apps/macos/Experiments/GhosttyVTBridge") +const repoRoot = path.resolve(import.meta.dir, ".."); +const vendorDir = path.join(repoRoot, "apps/macos/vendor/ghostty"); +const bridgeDir = path.join(repoRoot, "apps/macos/Experiments/GhosttyVTBridge"); const installDir = path.join( process.env.HOME ?? "", "Library/Application Support/Hack/ghostty/lib" -) +); -const zigVersion = (await $`zig version`.text()).trim() +const zigVersion = (await $`zig version`.text()).trim(); const parseVersion = (value: string) => { - const match = value.match(/(\d+)\.(\d+)\.(\d+)/) + const match = value.match(/(\d+)\.(\d+)\.(\d+)/); if (!match) { - return null + return null; } - const [, major, minor, patch] = match + const [, major, minor, patch] = match; return { major: Number.parseInt(major ?? "0", 10), minor: Number.parseInt(minor ?? "0", 10), patch: Number.parseInt(patch ?? "0", 10), isDev: value.includes("dev"), - } -} + }; +}; -const isAtLeast = (current: { major: number; minor: number; patch: number }, min: { - major: number - minor: number - patch: number -}) => { +const _isAtLeast = ( + current: { major: number; minor: number; patch: number }, + min: { + major: number; + minor: number; + patch: number; + } +) => { if (current.major !== min.major) { - return current.major > min.major + return current.major > min.major; } if (current.minor !== min.minor) { - return current.minor > min.minor + return current.minor > min.minor; } - return current.patch >= min.patch -} + return current.patch >= min.patch; +}; -if (!existsSync(vendorDir)) { - await $`git clone --depth 1 https://github.com/ghostty-org/ghostty ${vendorDir}` +if (existsSync(vendorDir)) { + await $`git -C ${vendorDir} fetch --depth 1 origin main`; + await $`git -C ${vendorDir} reset --hard origin/main`; } else { - await $`git -C ${vendorDir} fetch --depth 1 origin main` - await $`git -C ${vendorDir} reset --hard origin/main` + await $`git clone --depth 1 https://github.com/ghostty-org/ghostty ${vendorDir}`; } -const minVersionMatch = readFileSync(path.join(vendorDir, "build.zig.zon"), "utf8").match( - /minimum_zig_version\\s*=\\s*\"(\\d+\\.\\d+\\.\\d+)\"/ -) +const minVersionMatch = readFileSync( + path.join(vendorDir, "build.zig.zon"), + "utf8" +).match(/minimum_zig_version\\s*=\\s*"(\\d+\\.\\d+\\.\\d+)"/); const minVersion = parseVersion(minVersionMatch?.[1] ?? "0.15.2") ?? { major: 0, minor: 15, patch: 2, isDev: false, -} +}; -const parsedZigVersion = parseVersion(zigVersion) +const parsedZigVersion = parseVersion(zigVersion); if (!parsedZigVersion) { - console.error(`Unable to parse Zig version "${zigVersion}".`) - process.exit(1) + console.error(`Unable to parse Zig version "${zigVersion}".`); + process.exit(1); } const supportsGhostty = parsedZigVersion.major === minVersion.major && parsedZigVersion.minor === minVersion.minor && - (parsedZigVersion.patch >= minVersion.patch || parsedZigVersion.isDev) + (parsedZigVersion.patch >= minVersion.patch || parsedZigVersion.isDev); if (!supportsGhostty) { console.error( `Ghostty VT currently targets Zig ${minVersion.major}.${minVersion.minor}.x (min ${minVersion.major}.${minVersion.minor}.${minVersion.patch}). Install Zig ${minVersion.major}.${minVersion.minor}.${minVersion.patch} (mise: "mise install zig@0.15.2") and retry.` - ) - process.exit(1) + ); + process.exit(1); } -const libVtPath = path.join(vendorDir, "src/lib_vt.zig") -let libVtSource = readFileSync(libVtPath, "utf8") -const guard = 'if (@import("root") == lib) {' -const patchedGuard = 'if (@import("root") == lib and terminal.options.c_abi) {' +const libVtPath = path.join(vendorDir, "src/lib_vt.zig"); +let libVtSource = readFileSync(libVtPath, "utf8"); +const guard = 'if (@import("root") == lib) {'; +const patchedGuard = 'if (@import("root") == lib and terminal.options.c_abi) {'; if (libVtSource.includes(guard) && !libVtSource.includes(patchedGuard)) { - libVtSource = libVtSource.replace(guard, patchedGuard) + libVtSource = libVtSource.replace(guard, patchedGuard); } if (libVtSource.includes("@export(&")) { - libVtSource = libVtSource.replaceAll("@export(&", "@export(") + libVtSource = libVtSource.replaceAll("@export(&", "@export("); } -writeFileSync(libVtPath, libVtSource) +writeFileSync(libVtPath, libVtSource); -await $`zig build -Dghostty=${vendorDir} -Doptimize=ReleaseSafe`.cwd(bridgeDir) +await $`zig build -Dghostty=${vendorDir} -Doptimize=ReleaseSafe`.cwd(bridgeDir); -mkdirSync(installDir, { recursive: true }) -const builtLib = path.join(bridgeDir, "zig-out/lib/libhack_ghostty_vt.dylib") -const targetLib = path.join(installDir, "libhack_ghostty_vt.dylib") -await $`cp ${builtLib} ${targetLib}` -await $`codesign --force --sign - ${targetLib}` -await $`xattr -d com.apple.provenance ${targetLib}`.quiet().nothrow() +mkdirSync(installDir, { recursive: true }); +const builtLib = path.join(bridgeDir, "zig-out/lib/libhack_ghostty_vt.dylib"); +const targetLib = path.join(installDir, "libhack_ghostty_vt.dylib"); +await $`cp ${builtLib} ${targetLib}`; +await $`codesign --force --sign - ${targetLib}`; +await $`xattr -d com.apple.provenance ${targetLib}`.quiet().nothrow(); -console.log(`Ghostty VT library installed: ${targetLib}`) +console.log(`Ghostty VT library installed: ${targetLib}`); diff --git a/scripts/prepare-release.ts b/scripts/prepare-release.ts index 126f5b06..3efaba8c 100644 --- a/scripts/prepare-release.ts +++ b/scripts/prepare-release.ts @@ -1,77 +1,93 @@ #!/usr/bin/env bun -import { resolve } from "node:path" +import { resolve } from "node:path"; -type Args = { - readonly version: string | null +interface Args { + readonly version: string | null; } -type ParseOk = { readonly ok: true; readonly args: Args } -type ParseErr = { readonly ok: false; readonly message: string } +interface ParseOk { + readonly ok: true; + readonly args: Args; +} +interface ParseErr { + readonly ok: false; + readonly message: string; +} -const parsed = parseArgs({ argv: Bun.argv.slice(2) }) -if (!parsed.ok) { - process.stderr.write(`${parsed.message}\n`) - process.exitCode = 1 +const parsed = parseArgs({ argv: Bun.argv.slice(2) }); +if (parsed.ok) { + process.exitCode = await main({ args: parsed.args }); } else { - process.exitCode = await main({ args: parsed.args }) + process.stderr.write(`${parsed.message}\n`); + process.exitCode = 1; } async function main({ args }: { readonly args: Args }): Promise { - const nextVersion = args.version?.trim() ?? "" + const nextVersion = args.version?.trim() ?? ""; if (nextVersion.length === 0) { - process.stderr.write("Missing --version.\n") - return 1 + process.stderr.write("Missing --version.\n"); + return 1; } - const repoRoot = resolve(import.meta.dir, "..") + const repoRoot = resolve(import.meta.dir, ".."); // Update package.json - const packageJsonPath = resolve(repoRoot, "package.json") - const pkg = await Bun.file(packageJsonPath).json() + const packageJsonPath = resolve(repoRoot, "package.json"); + const pkg = await Bun.file(packageJsonPath).json(); if (typeof pkg !== "object" || pkg === null) { - process.stderr.write("Unable to read package.json.\n") - return 1 + process.stderr.write("Unable to read package.json.\n"); + return 1; } - const currentVersion = typeof pkg.version === "string" ? pkg.version : null + const currentVersion = typeof pkg.version === "string" ? pkg.version : null; if (currentVersion === null) { - process.stderr.write("package.json is missing a string version.\n") - return 1 + process.stderr.write("package.json is missing a string version.\n"); + return 1; } if (currentVersion !== nextVersion) { - pkg.version = nextVersion - await Bun.write(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n") - process.stdout.write(`Updated package.json: ${currentVersion} → ${nextVersion}\n`) + pkg.version = nextVersion; + await Bun.write(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`); + process.stdout.write( + `Updated package.json: ${currentVersion} → ${nextVersion}\n` + ); } // Update macOS app version in Base.xcconfig - const xconfigPath = resolve(repoRoot, "apps/macos/Config/Base.xcconfig") + const xconfigPath = resolve(repoRoot, "apps/macos/Config/Base.xcconfig"); try { - const xconfigContent = await Bun.file(xconfigPath).text() + const xconfigContent = await Bun.file(xconfigPath).text(); const updatedXconfig = xconfigContent.replace( /^MARKETING_VERSION = .*/m, `MARKETING_VERSION = ${nextVersion}` - ) + ); if (updatedXconfig !== xconfigContent) { - await Bun.write(xconfigPath, updatedXconfig) - process.stdout.write(`Updated Base.xcconfig: MARKETING_VERSION → ${nextVersion}\n`) + await Bun.write(xconfigPath, updatedXconfig); + process.stdout.write( + `Updated Base.xcconfig: MARKETING_VERSION → ${nextVersion}\n` + ); } } catch { // macOS config may not exist, that's fine } - return 0 + return 0; } -function parseArgs({ argv }: { readonly argv: readonly string[] }): ParseOk | ParseErr { - let version: string | null = null +function parseArgs({ + argv, +}: { + readonly argv: readonly string[]; +}): ParseOk | ParseErr { + let version: string | null = null; for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index] ?? "" - if (arg.length === 0) continue + const arg = argv[index] ?? ""; + if (arg.length === 0) { + continue; + } if (arg === "--help" || arg === "-h") { return { @@ -82,30 +98,36 @@ function parseArgs({ argv }: { readonly argv: readonly string[] }): ParseOk | Pa "Usage:", " bun run scripts/prepare-release.ts --version=X.Y.Z", " bun run scripts/prepare-release.ts --version X.Y.Z", - "" - ].join("\n") - } + "", + ].join("\n"), + }; } if (arg === "--version") { - const value = argv[index + 1]?.trim() - if (!value) return { ok: false, message: "Missing value for --version." } - version = value - index += 1 - continue + const value = argv[index + 1]?.trim(); + if (!value) { + return { ok: false, message: "Missing value for --version." }; + } + version = value; + index += 1; + continue; } if (arg.startsWith("--version=")) { - const value = arg.slice("--version=".length).trim() - if (!value) return { ok: false, message: "Missing value for --version." } - version = value - continue + const value = arg.slice("--version=".length).trim(); + if (!value) { + return { ok: false, message: "Missing value for --version." }; + } + version = value; + continue; } - return { ok: false, message: `Unknown arg: ${arg}` } + return { ok: false, message: `Unknown arg: ${arg}` }; } - if (!version) return { ok: false, message: "Missing --version." } + if (!version) { + return { ok: false, message: "Missing --version." }; + } - return { ok: true, args: { version } } + return { ok: true, args: { version } }; } diff --git a/scripts/uninstall-cli.ts b/scripts/uninstall-cli.ts index ce0f9063..eb350f7d 100644 --- a/scripts/uninstall-cli.ts +++ b/scripts/uninstall-cli.ts @@ -1,33 +1,35 @@ #!/usr/bin/env bun -import { resolve } from "node:path" -import { lstat, rm } from "node:fs/promises" +import { lstat, rm } from "node:fs/promises"; +import { resolve } from "node:path"; -const CLI_NAME = "hack" as const -const home = (process.env.HOME ?? "").trim() +const CLI_NAME = "hack" as const; +const home = (process.env.HOME ?? "").trim(); if (home.length === 0) { - process.stderr.write("HOME is not set; cannot determine install directory.\n") - process.exitCode = 1 + process.stderr.write( + "HOME is not set; cannot determine install directory.\n" + ); + process.exitCode = 1; } else { - const installDir = resolve(home, ".hack/bin") - const targetPath = resolve(installDir, CLI_NAME) + const installDir = resolve(home, ".hack/bin"); + const targetPath = resolve(installDir, CLI_NAME); - const exists = await pathExists(targetPath) - if (!exists) { - process.stdout.write(`No '${CLI_NAME}' found at ${targetPath}\n`) - process.exitCode = 0 + const exists = await pathExists(targetPath); + if (exists) { + await rm(targetPath, { force: true }); + process.stdout.write(`Removed '${CLI_NAME}' from ${targetPath}\n`); + process.exitCode = 0; } else { - await rm(targetPath, { force: true }) - process.stdout.write(`Removed '${CLI_NAME}' from ${targetPath}\n`) - process.exitCode = 0 + process.stdout.write(`No '${CLI_NAME}' found at ${targetPath}\n`); + process.exitCode = 0; } } async function pathExists(path: string): Promise { try { - await lstat(path) - return true + await lstat(path); + return true; } catch { - return false + return false; } } diff --git a/src/agents/claude.ts b/src/agents/claude.ts index 0c8baf8a..aee54af4 100644 --- a/src/agents/claude.ts +++ b/src/agents/claude.ts @@ -1,267 +1,326 @@ -import { dirname, resolve } from "node:path" +import { dirname, resolve } from "node:path"; -import { ensureDir, pathExists, readTextFile, writeTextFileIfChanged } from "../lib/fs.ts" -import { isRecord } from "../lib/guards.ts" +import { + ensureDir, + pathExists, + readTextFile, + writeTextFileIfChanged, +} from "../lib/fs.ts"; +import { isRecord } from "../lib/guards.ts"; -export type ClaudeScope = "project" | "user" +export type ClaudeScope = "project" | "user"; export type ClaudeHookResult = { - readonly scope: ClaudeScope - readonly status: "updated" | "noop" | "removed" | "missing" | "error" - readonly path: string - readonly message?: string -} + readonly scope: ClaudeScope; + readonly status: "updated" | "noop" | "removed" | "missing" | "error"; + readonly path: string; + readonly message?: string; +}; -const HOOK_COMMAND = "hack agent prime" -const HOOK_EVENTS = ["SessionStart", "PreCompact"] as const +const HOOK_COMMAND = "hack agent prime"; +const HOOK_EVENTS = ["SessionStart", "PreCompact"] as const; /** * Install Claude Code hooks to run the hack agent primer. */ export async function installClaudeHooks(opts: { - readonly scope: ClaudeScope - readonly projectRoot?: string + readonly scope: ClaudeScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveClaudeSettingsPath(opts) + const resolved = resolveClaudeSettingsPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? "settings.json", - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path - await ensureDir(dirname(path)) + const path = resolved.path; + await ensureDir(dirname(path)); - const settings = await readSettingsFile({ path }) + const settings = await readSettingsFile({ path }); if (!settings.ok) { return { scope: opts.scope, status: "error", path, - message: settings.message - } + message: settings.message, + }; } - const updated = upsertHooks({ settings: settings.value, command: HOOK_COMMAND }) - const nextText = `${JSON.stringify(settings.value, null, 2)}\n` - const result = await writeTextFileIfChanged(path, nextText) + const updated = upsertHooks({ + settings: settings.value, + command: HOOK_COMMAND, + }); + const nextText = `${JSON.stringify(settings.value, null, 2)}\n`; + const result = await writeTextFileIfChanged(path, nextText); return { scope: opts.scope, status: updated || result.changed ? "updated" : "noop", - path - } + path, + }; } /** * Check whether Claude Code hooks are installed. */ export async function checkClaudeHooks(opts: { - readonly scope: ClaudeScope - readonly projectRoot?: string + readonly scope: ClaudeScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveClaudeSettingsPath(opts) + const resolved = resolveClaudeSettingsPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? "settings.json", - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path + const path = resolved.path; if (!(await pathExists(path))) { - return { scope: opts.scope, status: "missing", path } + return { scope: opts.scope, status: "missing", path }; } - const settings = await readSettingsFile({ path }) + const settings = await readSettingsFile({ path }); if (!settings.ok) { - return { scope: opts.scope, status: "error", path, message: settings.message } + return { + scope: opts.scope, + status: "error", + path, + message: settings.message, + }; } - const hasAll = hasHooks({ settings: settings.value, command: HOOK_COMMAND }) - return { scope: opts.scope, status: hasAll ? "noop" : "missing", path } + const hasAll = hasHooks({ settings: settings.value, command: HOOK_COMMAND }); + return { scope: opts.scope, status: hasAll ? "noop" : "missing", path }; } /** * Remove Claude Code hooks for the hack agent primer. */ export async function removeClaudeHooks(opts: { - readonly scope: ClaudeScope - readonly projectRoot?: string + readonly scope: ClaudeScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveClaudeSettingsPath(opts) + const resolved = resolveClaudeSettingsPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? "settings.json", - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path + const path = resolved.path; if (!(await pathExists(path))) { - return { scope: opts.scope, status: "missing", path } + return { scope: opts.scope, status: "missing", path }; } - const settings = await readSettingsFile({ path }) + const settings = await readSettingsFile({ path }); if (!settings.ok) { - return { scope: opts.scope, status: "error", path, message: settings.message } + return { + scope: opts.scope, + status: "error", + path, + message: settings.message, + }; } - const changed = removeHooks({ settings: settings.value, command: HOOK_COMMAND }) + const changed = removeHooks({ + settings: settings.value, + command: HOOK_COMMAND, + }); if (!changed) { - return { scope: opts.scope, status: "noop", path } + return { scope: opts.scope, status: "noop", path }; } - const nextText = `${JSON.stringify(settings.value, null, 2)}\n` - await writeTextFileIfChanged(path, nextText) - return { scope: opts.scope, status: "removed", path } + const nextText = `${JSON.stringify(settings.value, null, 2)}\n`; + await writeTextFileIfChanged(path, nextText); + return { scope: opts.scope, status: "removed", path }; } function resolveClaudeSettingsPath(opts: { - readonly scope: ClaudeScope - readonly projectRoot?: string -}): { readonly ok: true; readonly path: string } | { readonly ok: false; readonly message: string; readonly path?: string } { + readonly scope: ClaudeScope; + readonly projectRoot?: string; +}): + | { readonly ok: true; readonly path: string } + | { readonly ok: false; readonly message: string; readonly path?: string } { if (opts.scope === "project" && !opts.projectRoot) { - return { ok: false, message: "Missing project root for project-scoped Claude hooks." } + return { + ok: false, + message: "Missing project root for project-scoped Claude hooks.", + }; } - const root = opts.scope === "user" ? resolveHomeDir() : opts.projectRoot + const root = opts.scope === "user" ? resolveHomeDir() : opts.projectRoot; if (!root) { - return { ok: false, message: "HOME is not set; cannot resolve Claude settings path." } + return { + ok: false, + message: "HOME is not set; cannot resolve Claude settings path.", + }; } return { ok: true, path: - opts.scope === "user" ? - resolve(root, ".claude", "settings.json") - : resolve(root, ".claude", "settings.local.json") - } + opts.scope === "user" + ? resolve(root, ".claude", "settings.json") + : resolve(root, ".claude", "settings.local.json"), + }; } async function readSettingsFile(opts: { - readonly path: string -}): Promise<{ readonly ok: true; readonly value: Record } | { readonly ok: false; readonly message: string }> { - const text = await readTextFile(opts.path) - if (!text) return { ok: true, value: {} } + readonly path: string; +}): Promise< + | { readonly ok: true; readonly value: Record } + | { readonly ok: false; readonly message: string } +> { + const text = await readTextFile(opts.path); + if (!text) { + return { ok: true, value: {} }; + } try { - const parsed: unknown = JSON.parse(text) + const parsed: unknown = JSON.parse(text); if (!isRecord(parsed)) { - return { ok: false, message: "Expected JSON object at config root." } + return { ok: false, message: "Expected JSON object at config root." }; } - return { ok: true, value: parsed } + return { ok: true, value: parsed }; } catch (error: unknown) { - const message = error instanceof Error ? error.message : "Invalid JSON" - return { ok: false, message: `Failed to parse Claude settings JSON: ${message}` } + const message = error instanceof Error ? error.message : "Invalid JSON"; + return { + ok: false, + message: `Failed to parse Claude settings JSON: ${message}`, + }; } } function upsertHooks(opts: { - readonly settings: Record - readonly command: string + readonly settings: Record; + readonly command: string; }): boolean { - const hooks = resolveHooksMap(opts.settings) - let changed = false + const hooks = resolveHooksMap(opts.settings); + let changed = false; for (const event of HOOK_EVENTS) { - const eventHooks = resolveEventHooks({ hooks, event }) - if (eventHasCommand({ eventHooks, command: opts.command })) continue - eventHooks.push(createHook({ command: opts.command })) - hooks[event] = eventHooks - changed = true + const eventHooks = resolveEventHooks({ hooks, event }); + if (eventHasCommand({ eventHooks, command: opts.command })) { + continue; + } + eventHooks.push(createHook({ command: opts.command })); + hooks[event] = eventHooks; + changed = true; } - if (changed) opts.settings["hooks"] = hooks - return changed + if (changed) { + opts.settings.hooks = hooks; + } + return changed; } function hasHooks(opts: { - readonly settings: Record - readonly command: string + readonly settings: Record; + readonly command: string; }): boolean { - const hooks = resolveHooksMap(opts.settings) - return HOOK_EVENTS.every(event => { - const eventHooks = resolveEventHooks({ hooks, event }) - return eventHasCommand({ eventHooks, command: opts.command }) - }) + const hooks = resolveHooksMap(opts.settings); + return HOOK_EVENTS.every((event) => { + const eventHooks = resolveEventHooks({ hooks, event }); + return eventHasCommand({ eventHooks, command: opts.command }); + }); } function removeHooks(opts: { - readonly settings: Record - readonly command: string + readonly settings: Record; + readonly command: string; }): boolean { - const hooks = resolveHooksMap(opts.settings) - let changed = false + const hooks = resolveHooksMap(opts.settings); + let changed = false; for (const event of HOOK_EVENTS) { - const eventHooks = resolveEventHooks({ hooks, event }) - const filtered = eventHooks.filter(hook => !hookHasCommand({ hook, command: opts.command })) + const eventHooks = resolveEventHooks({ hooks, event }); + const filtered = eventHooks.filter( + (hook) => !hookHasCommand({ hook, command: opts.command }) + ); if (filtered.length !== eventHooks.length) { - hooks[event] = filtered - changed = true + hooks[event] = filtered; + changed = true; } } - if (changed) opts.settings["hooks"] = hooks - return changed + if (changed) { + opts.settings.hooks = hooks; + } + return changed; } -function resolveHooksMap(settings: Record): Record { - const raw = settings["hooks"] - if (isRecord(raw)) return { ...raw } - return {} +function resolveHooksMap( + settings: Record +): Record { + const raw = settings.hooks; + if (isRecord(raw)) { + return { ...raw }; + } + return {}; } function resolveEventHooks(opts: { - readonly hooks: Record - readonly event: string + readonly hooks: Record; + readonly event: string; }): unknown[] { - const raw = opts.hooks[opts.event] - return Array.isArray(raw) ? [...raw] : [] + const raw = opts.hooks[opts.event]; + return Array.isArray(raw) ? [...raw] : []; } function eventHasCommand(opts: { - readonly eventHooks: readonly unknown[] - readonly command: string + readonly eventHooks: readonly unknown[]; + readonly command: string; }): boolean { - return opts.eventHooks.some(hook => hookHasCommand({ hook, command: opts.command })) + return opts.eventHooks.some((hook) => + hookHasCommand({ hook, command: opts.command }) + ); } function hookHasCommand(opts: { - readonly hook: unknown - readonly command: string + readonly hook: unknown; + readonly command: string; }): boolean { - if (!isRecord(opts.hook)) return false - const hooksRaw = opts.hook["hooks"] - if (!Array.isArray(hooksRaw)) return false - - return hooksRaw.some(entry => { - if (!isRecord(entry)) return false - return entry["command"] === opts.command - }) + if (!isRecord(opts.hook)) { + return false; + } + const hooksRaw = opts.hook.hooks; + if (!Array.isArray(hooksRaw)) { + return false; + } + + return hooksRaw.some((entry) => { + if (!isRecord(entry)) { + return false; + } + return entry.command === opts.command; + }); } -function createHook(opts: { readonly command: string }): Record { +function createHook(opts: { + readonly command: string; +}): Record { return { matcher: "", hooks: [ { type: "command", - command: opts.command - } - ] - } + command: opts.command, + }, + ], + }; } function resolveHomeDir(): string | null { - const home = (process.env.HOME ?? "").trim() - return home.length > 0 ? home : null + const home = (process.env.HOME ?? "").trim(); + return home.length > 0 ? home : null; } diff --git a/src/agents/codex-skill.ts b/src/agents/codex-skill.ts index 4d718a1f..051bfbe0 100644 --- a/src/agents/codex-skill.ts +++ b/src/agents/codex-skill.ts @@ -1,103 +1,112 @@ -import { dirname, resolve } from "node:path" -import { rm } from "node:fs/promises" +import { rm } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; -import { ensureDir, pathExists, readTextFile, writeTextFileIfChanged } from "../lib/fs.ts" +import { + ensureDir, + pathExists, + readTextFile, + writeTextFileIfChanged, +} from "../lib/fs.ts"; -export type CodexSkillScope = "project" | "user" +export type CodexSkillScope = "project" | "user"; export type CodexSkillResult = { - readonly scope: CodexSkillScope - readonly status: "created" | "updated" | "noop" | "removed" | "missing" | "error" - readonly path: string - readonly message?: string -} - -const SKILL_NAME = "hack-cli" -const SKILL_FILENAME = "SKILL.md" -const SKILL_DIR = ".codex/skills" + readonly scope: CodexSkillScope; + readonly status: + | "created" + | "updated" + | "noop" + | "removed" + | "missing" + | "error"; + readonly path: string; + readonly message?: string; +}; + +const SKILL_NAME = "hack-cli"; +const SKILL_FILENAME = "SKILL.md"; +const SKILL_DIR = ".codex/skills"; +const HACK_CLI_MARKER_REGEX = /name:\s*hack-cli\b/i; /** * Install or update the Codex skill for hack CLI usage. */ export async function installCodexSkill(opts: { - readonly scope: CodexSkillScope - readonly projectRoot?: string + readonly scope: CodexSkillScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveCodexSkillPath(opts) + const resolved = resolveCodexSkillPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? SKILL_FILENAME, - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path - await ensureDir(dirname(path)) - const existed = await pathExists(path) - const result = await writeTextFileIfChanged(path, renderCodexSkill()) + const path = resolved.path; + await ensureDir(dirname(path)); + const existed = await pathExists(path); + const result = await writeTextFileIfChanged(path, renderCodexSkill()); - return { - scope: opts.scope, - status: result.changed ? (existed ? "updated" : "created") : "noop", - path - } + const status = resolveInstallStatus({ changed: result.changed, existed }); + return { scope: opts.scope, status, path }; } /** * Check whether the Codex skill is installed. */ export async function checkCodexSkill(opts: { - readonly scope: CodexSkillScope - readonly projectRoot?: string + readonly scope: CodexSkillScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveCodexSkillPath(opts) + const resolved = resolveCodexSkillPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? SKILL_FILENAME, - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path - const content = await readTextFile(path) + const path = resolved.path; + const content = await readTextFile(path); if (!content) { - return { scope: opts.scope, status: "missing", path } + return { scope: opts.scope, status: "missing", path }; } - const hasMarker = /name:\s*hack-cli\b/i.test(content) - return { scope: opts.scope, status: hasMarker ? "noop" : "error", path } + const hasMarker = HACK_CLI_MARKER_REGEX.test(content); + return { scope: opts.scope, status: hasMarker ? "noop" : "error", path }; } /** * Remove the Codex skill for hack CLI usage. */ export async function removeCodexSkill(opts: { - readonly scope: CodexSkillScope - readonly projectRoot?: string + readonly scope: CodexSkillScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveCodexSkillPath(opts) + const resolved = resolveCodexSkillPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? SKILL_FILENAME, - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path - const skillDir = resolve(path, "..") + const path = resolved.path; + const skillDir = resolve(path, ".."); if (!(await pathExists(path))) { - return { scope: opts.scope, status: "missing", path } + return { scope: opts.scope, status: "missing", path }; } - await rm(skillDir, { recursive: true, force: true }) - return { scope: opts.scope, status: "removed", path } + await rm(skillDir, { recursive: true, force: true }); + return { scope: opts.scope, status: "removed", path }; } /** @@ -161,32 +170,50 @@ export function renderCodexSkill(): string { "- Init prompt: `hack agent init` (use --client cursor|claude|codex to open)", "- Init patterns: `hack agent patterns`", "- MCP (no shell only): `hack setup mcp`", - "" - ] + "", + ]; - return lines.join("\n") + return lines.join("\n"); } function resolveCodexSkillPath(opts: { - readonly scope: CodexSkillScope - readonly projectRoot?: string -}): { readonly ok: true; readonly path: string } | { readonly ok: false; readonly message: string; readonly path?: string } { + readonly scope: CodexSkillScope; + readonly projectRoot?: string; +}): + | { readonly ok: true; readonly path: string } + | { readonly ok: false; readonly message: string; readonly path?: string } { if (opts.scope === "project" && !opts.projectRoot) { - return { ok: false, message: "Missing project root for project-scoped Codex skill." } + return { + ok: false, + message: "Missing project root for project-scoped Codex skill.", + }; } - const root = opts.scope === "user" ? resolveHomeDir() : opts.projectRoot + const root = opts.scope === "user" ? resolveHomeDir() : opts.projectRoot; if (!root) { - return { ok: false, message: "HOME is not set; cannot resolve Codex skill path." } + return { + ok: false, + message: "HOME is not set; cannot resolve Codex skill path.", + }; } return { ok: true, - path: resolve(root, SKILL_DIR, SKILL_NAME, SKILL_FILENAME) - } + path: resolve(root, SKILL_DIR, SKILL_NAME, SKILL_FILENAME), + }; } function resolveHomeDir(): string | null { - const home = (process.env.HOME ?? "").trim() - return home.length > 0 ? home : null + const home = (process.env.HOME ?? "").trim(); + return home.length > 0 ? home : null; +} + +function resolveInstallStatus(opts: { + readonly changed: boolean; + readonly existed: boolean; +}): "created" | "updated" | "noop" { + if (!opts.changed) { + return "noop"; + } + return opts.existed ? "updated" : "created"; } diff --git a/src/agents/cursor.ts b/src/agents/cursor.ts index e68fc405..d26f9f98 100644 --- a/src/agents/cursor.ts +++ b/src/agents/cursor.ts @@ -1,72 +1,80 @@ -import { dirname, resolve } from "node:path" -import { unlink } from "node:fs/promises" +import { unlink } from "node:fs/promises"; +import { dirname, resolve } from "node:path"; -import { ensureDir, pathExists, readTextFile, writeTextFileIfChanged } from "../lib/fs.ts" +import { + ensureDir, + pathExists, + readTextFile, + writeTextFileIfChanged, +} from "../lib/fs.ts"; -export type CursorScope = "project" | "user" +export type CursorScope = "project" | "user"; export type CursorRulesResult = { - readonly scope: CursorScope - readonly status: "created" | "updated" | "noop" | "removed" | "missing" | "error" - readonly path: string - readonly message?: string -} - -const RULES_FILENAME = "hack.mdc" -const RULES_DIR = ".cursor/rules" -const MARKER_START = "# BEGIN HACK INTEGRATION" -const MARKER_END = "# END HACK INTEGRATION" + readonly scope: CursorScope; + readonly status: + | "created" + | "updated" + | "noop" + | "removed" + | "missing" + | "error"; + readonly path: string; + readonly message?: string; +}; + +const RULES_FILENAME = "hack.mdc"; +const RULES_DIR = ".cursor/rules"; +const MARKER_START = "# BEGIN HACK INTEGRATION"; +const MARKER_END = "# END HACK INTEGRATION"; /** * Install or update Cursor rules for hack CLI usage. */ export async function installCursorRules(opts: { - readonly scope: CursorScope - readonly projectRoot?: string + readonly scope: CursorScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveCursorRulesPath(opts) + const resolved = resolveCursorRulesPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? RULES_FILENAME, - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path - const existed = await pathExists(path) - await ensureDir(dirname(path)) - const result = await writeTextFileIfChanged(path, renderCursorRules()) + const path = resolved.path; + const existed = await pathExists(path); + await ensureDir(dirname(path)); + const result = await writeTextFileIfChanged(path, renderCursorRules()); - return { - scope: opts.scope, - status: result.changed ? (existed ? "updated" : "created") : "noop", - path - } + const status = resolveInstallStatus({ changed: result.changed, existed }); + return { scope: opts.scope, status, path }; } /** * Check whether Cursor rules are installed. */ export async function checkCursorRules(opts: { - readonly scope: CursorScope - readonly projectRoot?: string + readonly scope: CursorScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveCursorRulesPath(opts) + const resolved = resolveCursorRulesPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? RULES_FILENAME, - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path - const content = await readTextFile(path) + const path = resolved.path; + const content = await readTextFile(path); if (!content) { - return { scope: opts.scope, status: "missing", path } + return { scope: opts.scope, status: "missing", path }; } if (!content.includes(MARKER_START)) { @@ -74,37 +82,37 @@ export async function checkCursorRules(opts: { scope: opts.scope, status: "error", path, - message: "Rules file exists but is missing hack integration markers." - } + message: "Rules file exists but is missing hack integration markers.", + }; } - return { scope: opts.scope, status: "noop", path } + return { scope: opts.scope, status: "noop", path }; } /** * Remove Cursor rules for hack CLI usage. */ export async function removeCursorRules(opts: { - readonly scope: CursorScope - readonly projectRoot?: string + readonly scope: CursorScope; + readonly projectRoot?: string; }): Promise { - const resolved = resolveCursorRulesPath(opts) + const resolved = resolveCursorRulesPath(opts); if (!resolved.ok) { return { scope: opts.scope, status: "error", path: resolved.path ?? RULES_FILENAME, - message: resolved.message - } + message: resolved.message, + }; } - const path = resolved.path + const path = resolved.path; if (!(await pathExists(path))) { - return { scope: opts.scope, status: "missing", path } + return { scope: opts.scope, status: "missing", path }; } - await unlink(path) - return { scope: opts.scope, status: "removed", path } + await unlink(path); + return { scope: opts.scope, status: "removed", path }; } /** @@ -142,29 +150,47 @@ export function renderCursorRules(): string { "- Install only if no shell access: `hack setup mcp`", "", MARKER_END, - "" - ] + "", + ]; - return lines.join("\n") + return lines.join("\n"); } function resolveCursorRulesPath(opts: { - readonly scope: CursorScope - readonly projectRoot?: string -}): { readonly ok: true; readonly path: string } | { readonly ok: false; readonly message: string; readonly path?: string } { + readonly scope: CursorScope; + readonly projectRoot?: string; +}): + | { readonly ok: true; readonly path: string } + | { readonly ok: false; readonly message: string; readonly path?: string } { if (opts.scope === "project" && !opts.projectRoot) { - return { ok: false, message: "Missing project root for project-scoped Cursor rules." } + return { + ok: false, + message: "Missing project root for project-scoped Cursor rules.", + }; } - const root = opts.scope === "user" ? resolveHomeDir() : opts.projectRoot + const root = opts.scope === "user" ? resolveHomeDir() : opts.projectRoot; if (!root) { - return { ok: false, message: "HOME is not set; cannot resolve user rules path." } + return { + ok: false, + message: "HOME is not set; cannot resolve user rules path.", + }; } - return { ok: true, path: resolve(root, RULES_DIR, RULES_FILENAME) } + return { ok: true, path: resolve(root, RULES_DIR, RULES_FILENAME) }; } function resolveHomeDir(): string | null { - const home = (process.env.HOME ?? "").trim() - return home.length > 0 ? home : null + const home = (process.env.HOME ?? "").trim(); + return home.length > 0 ? home : null; +} + +function resolveInstallStatus(opts: { + readonly changed: boolean; + readonly existed: boolean; +}): "created" | "updated" | "noop" { + if (!opts.changed) { + return "noop"; + } + return opts.existed ? "updated" : "created"; } diff --git a/src/agents/init-assistant.ts b/src/agents/init-assistant.ts index 0b504b4d..206d069e 100644 --- a/src/agents/init-assistant.ts +++ b/src/agents/init-assistant.ts @@ -1,66 +1,69 @@ -import { relative, resolve } from "node:path" -import { Glob, YAML } from "bun" - -import { discoverRepo } from "../init/discovery.ts" -import { readTextFile, pathExists } from "../lib/fs.ts" -import { isRecord } from "../lib/guards.ts" -import { findProjectContext } from "../lib/project.ts" - -import type { DiscoveredPackage, ServiceCandidate } from "../init/discovery.ts" -import type { ProjectContext } from "../lib/project.ts" +import { relative, resolve } from "node:path"; +import { Glob, YAML } from "bun"; +import type { DiscoveredPackage, ServiceCandidate } from "../init/discovery.ts"; +import { discoverRepo } from "../init/discovery.ts"; +import { pathExists, readTextFile } from "../lib/fs.ts"; +import { isRecord } from "../lib/guards.ts"; +import type { ProjectContext } from "../lib/project.ts"; +import { findProjectContext } from "../lib/project.ts"; export type ComposeSignal = { - readonly path: string - readonly services: readonly string[] -} + readonly path: string; + readonly services: readonly string[]; +}; export type ScriptSignal = { - readonly packageId: string - readonly packageRelativeDir: string - readonly packageName: string | null - readonly scriptName: string - readonly scriptCommand: string -} + readonly packageId: string; + readonly packageRelativeDir: string; + readonly packageName: string | null; + readonly scriptName: string; + readonly scriptCommand: string; +}; export type InitAssistantReport = { - readonly repoRoot: string - readonly projectContext: ProjectContext | null - readonly packageCount: number - readonly isMonorepo: boolean - readonly workspacePatterns: readonly string[] - readonly discoverySignals: readonly string[] - readonly packageManagers: readonly string[] - readonly envFiles: readonly string[] - readonly composeFiles: readonly ComposeSignal[] - readonly dockerfiles: readonly string[] - readonly dbSignals: readonly string[] - readonly candidates: readonly ServiceCandidate[] - readonly setupScripts: readonly ScriptSignal[] -} + readonly repoRoot: string; + readonly projectContext: ProjectContext | null; + readonly packageCount: number; + readonly isMonorepo: boolean; + readonly workspacePatterns: readonly string[]; + readonly discoverySignals: readonly string[]; + readonly packageManagers: readonly string[]; + readonly envFiles: readonly string[]; + readonly composeFiles: readonly ComposeSignal[]; + readonly dockerfiles: readonly string[]; + readonly dbSignals: readonly string[]; + readonly candidates: readonly ServiceCandidate[]; + readonly setupScripts: readonly ScriptSignal[]; +}; /** * Build a report describing repo signals for agent-assisted init. */ export async function buildInitAssistantReport(opts: { - readonly repoRoot: string + readonly repoRoot: string; }): Promise { - const projectContext = await findProjectContext(opts.repoRoot) - const discovery = await discoverRepo(opts.repoRoot) + const projectContext = await findProjectContext(opts.repoRoot); + const discovery = await discoverRepo(opts.repoRoot); - const packageManagers = await detectPackageManagers({ repoRoot: opts.repoRoot }) - const envFiles = await detectEnvFiles({ repoRoot: opts.repoRoot }) - const composeFiles = await detectComposeFiles({ repoRoot: opts.repoRoot, projectContext }) + const packageManagers = await detectPackageManagers({ + repoRoot: opts.repoRoot, + }); + const envFiles = await detectEnvFiles({ repoRoot: opts.repoRoot }); + const composeFiles = await detectComposeFiles({ + repoRoot: opts.repoRoot, + projectContext, + }); const dockerfiles = await scanGlobs({ repoRoot: opts.repoRoot, patterns: DOCKERFILE_PATTERNS, - limit: 12 - }) + limit: 12, + }); const dbSignals = await scanGlobs({ repoRoot: opts.repoRoot, patterns: DB_PATTERNS, - limit: 12 - }) - const setupScripts = collectSetupScripts({ packages: discovery.packages }) + limit: 12, + }); + const setupScripts = collectSetupScripts({ packages: discovery.packages }); return { repoRoot: opts.repoRoot, @@ -75,87 +78,96 @@ export async function buildInitAssistantReport(opts: { dockerfiles, dbSignals, candidates: discovery.candidates, - setupScripts - } + setupScripts, + }; } /** * Render the init assistant prompt based on repo signals. */ export function renderInitAssistantPrompt(opts: { - readonly report: InitAssistantReport + readonly report: InitAssistantReport; }): string { - const lines: string[] = [] + const lines: string[] = []; - lines.push("# hack agent init") - lines.push("") + lines.push("# hack agent init"); + lines.push(""); lines.push( [ "You are helping a user bootstrap hack in this repo.", - "Prefer hack CLI; ask before making assumptions." + "Prefer hack CLI; ask before making assumptions.", ].join(" ") - ) - lines.push("") - lines.push("Repo context:") - lines.push(`- Root: ${opts.report.repoRoot}`) - lines.push(`- Hack config: ${formatHackContext({ report: opts.report })}`) + ); + lines.push(""); + lines.push("Repo context:"); + lines.push(`- Root: ${opts.report.repoRoot}`); + lines.push(`- Hack config: ${formatHackContext({ report: opts.report })}`); lines.push( `- Packages: ${opts.report.packageCount} (${opts.report.isMonorepo ? "monorepo" : "single"})` - ) + ); if (opts.report.workspacePatterns.length > 0) { - lines.push(`- Workspaces: ${opts.report.workspacePatterns.join(", ")}`) + lines.push(`- Workspaces: ${opts.report.workspacePatterns.join(", ")}`); } if (opts.report.discoverySignals.length > 0) { - lines.push(`- Signals: ${opts.report.discoverySignals.join(", ")}`) + lines.push(`- Signals: ${opts.report.discoverySignals.join(", ")}`); } - lines.push("") - lines.push("Detected files:") - lines.push(formatField({ label: "Package managers", values: opts.report.packageManagers })) - lines.push(formatField({ label: "Env files", values: opts.report.envFiles })) + lines.push(""); + lines.push("Detected files:"); + lines.push( + formatField({ + label: "Package managers", + values: opts.report.packageManagers, + }) + ); + lines.push(formatField({ label: "Env files", values: opts.report.envFiles })); lines.push( formatField({ label: "Compose files", - values: formatComposeFiles({ values: opts.report.composeFiles }) + values: formatComposeFiles({ values: opts.report.composeFiles }), }) - ) - lines.push(formatField({ label: "Dockerfiles", values: opts.report.dockerfiles })) - lines.push(formatField({ label: "DB signals", values: opts.report.dbSignals })) - lines.push("") - lines.push("Dev scripts (service candidates):") + ); + lines.push( + formatField({ label: "Dockerfiles", values: opts.report.dockerfiles }) + ); + lines.push( + formatField({ label: "DB signals", values: opts.report.dbSignals }) + ); + lines.push(""); + lines.push("Dev scripts (service candidates):"); if (opts.report.candidates.length === 0) { - lines.push("- none detected") + lines.push("- none detected"); } else { for (const candidate of opts.report.candidates) { - lines.push(`- ${formatCandidate({ candidate })}`) + lines.push(`- ${formatCandidate({ candidate })}`); } } - lines.push("") - lines.push("Setup scripts (migrations/seeds/etc):") + lines.push(""); + lines.push("Setup scripts (migrations/seeds/etc):"); if (opts.report.setupScripts.length === 0) { - lines.push("- none detected") + lines.push("- none detected"); } else { for (const script of opts.report.setupScripts) { - lines.push(`- ${formatScriptSignal({ signal: script })}`) + lines.push(`- ${formatScriptSignal({ signal: script })}`); } } - lines.push("") - lines.push("Suggested flow:") + lines.push(""); + lines.push("Suggested flow:"); for (const step of buildSuggestedSteps({ report: opts.report })) { - lines.push(`- ${step}`) + lines.push(`- ${step}`); } - lines.push("") - lines.push("Questions to confirm:") + lines.push(""); + lines.push("Questions to confirm:"); for (const question of buildSuggestedQuestions({ report: opts.report })) { - lines.push(`- ${question}`) + lines.push(`- ${question}`); } - lines.push("") - lines.push("Need dependency/ops patterns? Run `hack agent patterns`.") - lines.push("") + lines.push(""); + lines.push("Need dependency/ops patterns? Run `hack agent patterns`."); + lines.push(""); - return lines.join("\n") + return lines.join("\n"); } -const DOCKERFILE_PATTERNS = ["**/Dockerfile", "**/Dockerfile.*"] as const +const DOCKERFILE_PATTERNS = ["**/Dockerfile", "**/Dockerfile.*"] as const; const DB_PATTERNS = [ "**/prisma/schema.prisma", "**/drizzle.config.*", @@ -163,23 +175,23 @@ const DB_PATTERNS = [ "**/migrations/*.sql", "**/migrations/**/*.sql", "**/db/schema.sql", - "**/schema.sql" -] as const + "**/schema.sql", +] as const; const PACKAGE_MANAGER_FILES = [ "bun.lockb", "pnpm-lock.yaml", "yarn.lock", - "package-lock.json" -] as const + "package-lock.json", +] as const; const ENV_FILES = [ ".env", ".env.local", ".env.example", ".env.sample", - ".env.template" -] as const + ".env.template", +] as const; const IGNORE_PREFIXES = [ "node_modules/", @@ -191,247 +203,335 @@ const IGNORE_PREFIXES = [ ".output/", ".cache/", "coverage/", - ".hack/" -] as const + ".hack/", +] as const; const COMPOSE_PATTERNS = [ "**/docker-compose.yml", "**/docker-compose.yaml", "**/compose.yml", - "**/compose.yaml" -] as const + "**/compose.yaml", +] as const; -async function detectPackageManagers(opts: { readonly repoRoot: string }): Promise { - const found: string[] = [] +async function detectPackageManagers(opts: { + readonly repoRoot: string; +}): Promise { + const found: string[] = []; for (const filename of PACKAGE_MANAGER_FILES) { - const path = resolve(opts.repoRoot, filename) - if (await pathExists(path)) found.push(filename) + const path = resolve(opts.repoRoot, filename); + if (await pathExists(path)) { + found.push(filename); + } } - return found + return found; } -async function detectEnvFiles(opts: { readonly repoRoot: string }): Promise { - const found: string[] = [] +async function detectEnvFiles(opts: { + readonly repoRoot: string; +}): Promise { + const found: string[] = []; for (const filename of ENV_FILES) { - const path = resolve(opts.repoRoot, filename) - if (await pathExists(path)) found.push(filename) + const path = resolve(opts.repoRoot, filename); + if (await pathExists(path)) { + found.push(filename); + } } - return found + return found; } async function detectComposeFiles(opts: { - readonly repoRoot: string - readonly projectContext: ProjectContext | null + readonly repoRoot: string; + readonly projectContext: ProjectContext | null; }): Promise { - const seen = new Set() - const out: ComposeSignal[] = [] + const seen = new Set(); + const out: ComposeSignal[] = []; if (opts.projectContext) { - const rel = normalizePath({ path: relative(opts.repoRoot, opts.projectContext.composeFile) }) - const services = await readComposeServices({ absolutePath: opts.projectContext.composeFile }) - seen.add(rel) - out.push({ path: rel, services }) + const rel = normalizePath({ + path: relative(opts.repoRoot, opts.projectContext.composeFile), + }); + const services = await readComposeServices({ + absolutePath: opts.projectContext.composeFile, + }); + seen.add(rel); + out.push({ path: rel, services }); } const discovered = await scanGlobs({ repoRoot: opts.repoRoot, patterns: COMPOSE_PATTERNS, - limit: 12 - }) + limit: 12, + }); for (const rel of discovered) { - if (seen.has(rel)) continue - const abs = resolve(opts.repoRoot, rel) - const services = await readComposeServices({ absolutePath: abs }) - out.push({ path: rel, services }) - seen.add(rel) + if (seen.has(rel)) { + continue; + } + const abs = resolve(opts.repoRoot, rel); + const services = await readComposeServices({ absolutePath: abs }); + out.push({ path: rel, services }); + seen.add(rel); } - return out + return out; } -async function readComposeServices(opts: { readonly absolutePath: string }): Promise { - const text = await readTextFile(opts.absolutePath) - if (!text) return [] +async function readComposeServices(opts: { + readonly absolutePath: string; +}): Promise { + const text = await readTextFile(opts.absolutePath); + if (!text) { + return []; + } - let parsed: unknown + let parsed: unknown; try { - parsed = YAML.parse(text) as unknown + parsed = YAML.parse(text) as unknown; } catch { - return [] + return []; } - if (!isRecord(parsed)) return [] - const servicesRaw = parsed["services"] - if (!isRecord(servicesRaw)) return [] + if (!isRecord(parsed)) { + return []; + } + const servicesRaw = parsed.services; + if (!isRecord(servicesRaw)) { + return []; + } - return Object.keys(servicesRaw).sort() + return Object.keys(servicesRaw).sort(); } async function scanGlobs(opts: { - readonly repoRoot: string - readonly patterns: readonly string[] - readonly limit: number + readonly repoRoot: string; + readonly patterns: readonly string[]; + readonly limit: number; }): Promise { - const found = new Set() + const found = new Set(); for (const pattern of opts.patterns) { - if (found.size >= opts.limit) break - - const glob = new Glob(pattern) - for await (const rel of glob.scan({ cwd: opts.repoRoot, onlyFiles: true, dot: false })) { - const normalized = normalizePath({ path: rel }) - if (shouldIgnorePath({ relPath: normalized })) continue - found.add(normalized) - if (found.size >= opts.limit) break + if (found.size >= opts.limit) { + break; + } + + const glob = new Glob(pattern); + for await (const rel of glob.scan({ + cwd: opts.repoRoot, + onlyFiles: true, + dot: false, + })) { + const normalized = normalizePath({ path: rel }); + if (shouldIgnorePath({ relPath: normalized })) { + continue; + } + found.add(normalized); + if (found.size >= opts.limit) { + break; + } } } - return [...found].sort() + return [...found].sort(); } function shouldIgnorePath(opts: { readonly relPath: string }): boolean { - const normalized = normalizePath({ path: opts.relPath }) + const normalized = normalizePath({ path: opts.relPath }); return IGNORE_PREFIXES.some( - prefix => normalized.startsWith(prefix) || normalized.includes(`/${prefix}`) - ) + (prefix) => + normalized.startsWith(prefix) || normalized.includes(`/${prefix}`) + ); } function normalizePath(opts: { readonly path: string }): string { - return opts.path.replaceAll("\\", "/") + return opts.path.replaceAll("\\", "/"); } function collectSetupScripts(opts: { - readonly packages: readonly DiscoveredPackage[] + readonly packages: readonly DiscoveredPackage[]; }): ScriptSignal[] { - const results: ScriptSignal[] = [] + const results: ScriptSignal[] = []; for (const pkg of opts.packages) { for (const [scriptName, scriptCommand] of pkg.scripts.entries()) { - if (!isSetupScript({ scriptName, scriptCommand })) continue + if (!isSetupScript({ scriptName, scriptCommand })) { + continue; + } results.push({ packageId: pkg.id, packageRelativeDir: pkg.relativeDir, packageName: pkg.packageName, scriptName, - scriptCommand - }) + scriptCommand, + }); } } - return results + return results; } function isSetupScript(opts: { - readonly scriptName: string - readonly scriptCommand: string + readonly scriptName: string; + readonly scriptCommand: string; }): boolean { - const name = opts.scriptName.toLowerCase() - const cmd = opts.scriptCommand.toLowerCase() + const name = opts.scriptName.toLowerCase(); + const cmd = opts.scriptCommand.toLowerCase(); - if (name === "db" || name.startsWith("db:") || name.startsWith("db-")) return true - if (name.includes("migrate") || name.includes("migration")) return true - if (name.includes("seed")) return true - if (name.includes("prisma") || name.includes("drizzle")) return true - if (name.includes("typeorm") || name.includes("knex")) return true - if (name.includes("flyway")) return true + if (name === "db" || name.startsWith("db:") || name.startsWith("db-")) { + return true; + } + if (name.includes("migrate") || name.includes("migration")) { + return true; + } + if (name.includes("seed")) { + return true; + } + if (name.includes("prisma") || name.includes("drizzle")) { + return true; + } + if (name.includes("typeorm") || name.includes("knex")) { + return true; + } + if (name.includes("flyway")) { + return true; + } - if (cmd.includes("prisma") || cmd.includes("drizzle")) return true - if (cmd.includes("typeorm") || cmd.includes("knex")) return true - if (cmd.includes("flyway") || cmd.includes("alembic")) return true + if (cmd.includes("prisma") || cmd.includes("drizzle")) { + return true; + } + if (cmd.includes("typeorm") || cmd.includes("knex")) { + return true; + } + if (cmd.includes("flyway") || cmd.includes("alembic")) { + return true; + } - return false + return false; } -function formatHackContext(opts: { readonly report: InitAssistantReport }): string { - if (!opts.report.projectContext) return "not found" +function formatHackContext(opts: { + readonly report: InitAssistantReport; +}): string { + if (!opts.report.projectContext) { + return "not found"; + } const relDir = normalizePath({ - path: relative(opts.report.repoRoot, opts.report.projectContext.projectDir) - }) + path: relative(opts.report.repoRoot, opts.report.projectContext.projectDir), + }); const relCompose = normalizePath({ - path: relative(opts.report.repoRoot, opts.report.projectContext.composeFile) - }) - return `${relDir} (compose: ${relCompose})` + path: relative( + opts.report.repoRoot, + opts.report.projectContext.composeFile + ), + }); + return `${relDir} (compose: ${relCompose})`; } function formatField(opts: { - readonly label: string - readonly values: readonly string[] | string + readonly label: string; + readonly values: readonly string[] | string; }): string { - const content = Array.isArray(opts.values) ? formatList({ values: opts.values }) : opts.values - return `- ${opts.label}: ${content}` + const content = Array.isArray(opts.values) + ? formatList({ values: opts.values }) + : opts.values; + return `- ${opts.label}: ${content}`; } function formatList(opts: { readonly values: readonly string[] }): string { - if (opts.values.length === 0) return "none detected" - return opts.values.join(", ") + if (opts.values.length === 0) { + return "none detected"; + } + return opts.values.join(", "); } -function formatComposeFiles(opts: { readonly values: readonly ComposeSignal[] }): string[] { - if (opts.values.length === 0) return [] - return opts.values.map(entry => { - if (entry.services.length === 0) return entry.path - return `${entry.path} (services: ${entry.services.join(", ")})` - }) +function formatComposeFiles(opts: { + readonly values: readonly ComposeSignal[]; +}): string[] { + if (opts.values.length === 0) { + return []; + } + return opts.values.map((entry) => { + if (entry.services.length === 0) { + return entry.path; + } + return `${entry.path} (services: ${entry.services.join(", ")})`; + }); } -function formatCandidate(opts: { readonly candidate: ServiceCandidate }): string { +function formatCandidate(opts: { + readonly candidate: ServiceCandidate; +}): string { const location = - opts.candidate.packageRelativeDir === "." ? "root" : opts.candidate.packageRelativeDir - const pkgLabel = - opts.candidate.packageName ? `${location} (${opts.candidate.packageName})` : location - return `${pkgLabel}: ${opts.candidate.scriptName} -> ${opts.candidate.scriptCommand}` + opts.candidate.packageRelativeDir === "." + ? "root" + : opts.candidate.packageRelativeDir; + const pkgLabel = opts.candidate.packageName + ? `${location} (${opts.candidate.packageName})` + : location; + return `${pkgLabel}: ${opts.candidate.scriptName} -> ${opts.candidate.scriptCommand}`; } function formatScriptSignal(opts: { readonly signal: ScriptSignal }): string { - const location = opts.signal.packageRelativeDir === "." ? "root" : opts.signal.packageRelativeDir - const pkgLabel = opts.signal.packageName ? `${location} (${opts.signal.packageName})` : location - return `${pkgLabel}: ${opts.signal.scriptName} -> ${opts.signal.scriptCommand}` + const location = + opts.signal.packageRelativeDir === "." + ? "root" + : opts.signal.packageRelativeDir; + const pkgLabel = opts.signal.packageName + ? `${location} (${opts.signal.packageName})` + : location; + return `${pkgLabel}: ${opts.signal.scriptName} -> ${opts.signal.scriptCommand}`; } -function buildSuggestedSteps(opts: { readonly report: InitAssistantReport }): string[] { +function buildSuggestedSteps(opts: { + readonly report: InitAssistantReport; +}): string[] { const steps: string[] = [ - "Read README/docs to confirm local dev entrypoints and requirements." - ] + "Read README/docs to confirm local dev entrypoints and requirements.", + ]; if (opts.report.projectContext) { - steps.push("Review existing .hack config and update services/ports if needed.") + steps.push( + "Review existing .hack config and update services/ports if needed." + ); } else { const autoHint = - opts.report.candidates.length > 0 ? - "Run `hack init` (consider `--auto` since dev scripts were detected)." - : "Run `hack init` and choose manual mode if scripts are unclear." - steps.push(autoHint) + opts.report.candidates.length > 0 + ? "Run `hack init` (consider `--auto` since dev scripts were detected)." + : "Run `hack init` and choose manual mode if scripts are unclear."; + steps.push(autoHint); } - steps.push("Ensure compose includes app + dependencies (db/cache/queue) and correct ports.") + steps.push( + "Ensure compose includes app + dependencies (db/cache/queue) and correct ports." + ); if (opts.report.setupScripts.length > 0) { - steps.push("Run setup scripts (migrations/seeds) after services are up.") + steps.push("Run setup scripts (migrations/seeds) after services are up."); } - steps.push("Start services: `hack up --detach`.") - steps.push("Verify: `hack ps`, `hack open --json`, `hack logs --pretty`.") + steps.push("Start services: `hack up --detach`."); + steps.push("Verify: `hack ps`, `hack open --json`, `hack logs --pretty`."); - return steps + return steps; } -function buildSuggestedQuestions(opts: { readonly report: InitAssistantReport }): string[] { +function buildSuggestedQuestions(opts: { + readonly report: InitAssistantReport; +}): string[] { const questions: string[] = [ "Which service should be exposed on DEV_HOST?", "Are there extra services (db/cache/queue) that must be included?", "Which env vars/secrets are required for dev?", - "Any one-time setup steps before running the app?" - ] + "Any one-time setup steps before running the app?", + ]; if (opts.report.candidates.length === 0) { - questions.push("Which command starts the main app locally?") + questions.push("Which command starts the main app locally?"); } - return questions + return questions; } diff --git a/src/agents/init-patterns.ts b/src/agents/init-patterns.ts index 542e9874..9d376b74 100644 --- a/src/agents/init-patterns.ts +++ b/src/agents/init-patterns.ts @@ -68,8 +68,8 @@ export function renderAgentInitPatterns(): string { "- What services are required for local dev?", "- Which command starts the app?", "- Any one-time setup steps (migrations, seeds, downloads)?", - "" - ] + "", + ]; - return lines.join("\n") + return lines.join("\n"); } diff --git a/src/agents/primer.ts b/src/agents/primer.ts index 1975d944..e58b8f96 100644 --- a/src/agents/primer.ts +++ b/src/agents/primer.ts @@ -34,8 +34,8 @@ export function renderAgentPrimer(): string { "", "MCP:", "- Use MCP only when no shell access. Install via `hack setup mcp`.", - "" - ] + "", + ]; - return lines.join("\n") + return lines.join("\n"); } diff --git a/src/backends/log-backend.ts b/src/backends/log-backend.ts index a6c70e87..e873e196 100644 --- a/src/backends/log-backend.ts +++ b/src/backends/log-backend.ts @@ -1,48 +1,51 @@ -import { dockerComposeLogsJson, dockerComposeLogsPretty } from "../ui/docker-logs.ts" -import { canReachLoki, lokiLogs } from "../ui/loki-logs.ts" -import { run } from "../lib/shell.ts" +import { run } from "../lib/shell.ts"; +import { + dockerComposeLogsJson, + dockerComposeLogsPretty, +} from "../ui/docker-logs.ts"; +import type { LogStreamContext } from "../ui/log-stream.ts"; +import { canReachLoki, lokiLogs } from "../ui/loki-logs.ts"; -import type { LogStreamContext } from "../ui/log-stream.ts" - -export type LogBackendName = "compose" | "loki" -export type LogOutputFormat = "plain" | "pretty" | "json" +export type LogBackendName = "compose" | "loki"; +export type LogOutputFormat = "plain" | "pretty" | "json"; export interface ComposeLogOptions { - readonly composeFile: string - readonly cwd: string - readonly follow: boolean - readonly tail: number - readonly service?: string - readonly projectName?: string - readonly composeProject?: string - readonly profiles?: readonly string[] - readonly format: LogOutputFormat - readonly streamContext?: LogStreamContext + readonly composeFile: string; + readonly cwd: string; + readonly follow: boolean; + readonly tail: number; + readonly service?: string; + readonly projectName?: string; + readonly composeProject?: string; + readonly profiles?: readonly string[]; + readonly format: LogOutputFormat; + readonly streamContext?: LogStreamContext; } export interface LokiLogOptions { - readonly baseUrl: string - readonly query: string - readonly follow: boolean - readonly tail: number - readonly format: LogOutputFormat - readonly showProjectPrefix: boolean - readonly start?: Date - readonly end?: Date - readonly streamContext?: LogStreamContext + readonly baseUrl: string; + readonly query: string; + readonly follow: boolean; + readonly tail: number; + readonly format: LogOutputFormat; + readonly showProjectPrefix: boolean; + readonly start?: Date; + readonly end?: Date; + readonly streamContext?: LogStreamContext; } export interface LogBackend { - readonly name: LogBackendName - run(opts: Options): Promise + readonly name: LogBackendName; + run(opts: Options): Promise; } export interface LogBackendAvailability { - isAvailable(opts: { readonly baseUrl: string }): Promise + isAvailable(opts: { readonly baseUrl: string }): Promise; } -export type ComposeLogBackend = LogBackend -export type LokiLogBackend = LogBackend & LogBackendAvailability +export type ComposeLogBackend = LogBackend; +export type LokiLogBackend = LogBackend & + LogBackendAvailability; export const composeLogBackend: ComposeLogBackend = { name: "compose", @@ -57,8 +60,8 @@ export const composeLogBackend: ComposeLogBackend = { projectName: opts.projectName, composeProject: opts.composeProject, profiles: opts.profiles, - streamContext: opts.streamContext - }) + streamContext: opts.streamContext, + }); } if (opts.format === "pretty") { @@ -70,8 +73,8 @@ export const composeLogBackend: ComposeLogBackend = { service: opts.service, projectName: opts.projectName, composeProject: opts.composeProject, - profiles: opts.profiles - }) + profiles: opts.profiles, + }); } const cmd = [ @@ -80,22 +83,24 @@ export const composeLogBackend: ComposeLogBackend = { ...(opts.composeProject ? ["-p", opts.composeProject] : []), "-f", opts.composeFile, - ...(opts.profiles ? opts.profiles.flatMap(profile => ["--profile", profile] as const) : []), + ...(opts.profiles + ? opts.profiles.flatMap((profile) => ["--profile", profile] as const) + : []), "logs", ...(opts.follow ? ["-f"] : []), "--tail", String(opts.tail), - ...(opts.service ? [opts.service] : []) - ] + ...(opts.service ? [opts.service] : []), + ]; - return await run(cmd, { cwd: opts.cwd }) - } -} + return await run(cmd, { cwd: opts.cwd }); + }, +}; export const lokiLogBackend: LokiLogBackend = { name: "loki", async isAvailable({ baseUrl }) { - return await canReachLoki({ baseUrl }) + return await canReachLoki({ baseUrl }); }, async run(opts) { return await lokiLogs({ @@ -108,7 +113,7 @@ export const lokiLogBackend: LokiLogBackend = { showProjectPrefix: opts.showProjectPrefix, streamContext: opts.streamContext, start: opts.start, - end: opts.end - }) - } -} + end: opts.end, + }); + }, +}; diff --git a/src/backends/runtime-backend.ts b/src/backends/runtime-backend.ts index 23a9f1d3..1a9a4790 100644 --- a/src/backends/runtime-backend.ts +++ b/src/backends/runtime-backend.ts @@ -1,27 +1,27 @@ -import { exec, run } from "../lib/shell.ts" -import { createStructuredLogGrouper } from "../ui/log-group.ts" -import { readLinesFromStream } from "../ui/lines.ts" +import { exec, run } from "../lib/shell.ts"; +import { readLinesFromStream } from "../ui/lines.ts"; +import { createStructuredLogGrouper } from "../ui/log-group.ts"; -export type RuntimeBackendName = "compose" +export type RuntimeBackendName = "compose"; export interface RuntimeBackend { - readonly name: RuntimeBackendName - up(opts: RuntimeUpOptions): Promise - down(opts: RuntimeDownOptions): Promise - psJson(opts: RuntimePsOptions): ReturnType - ps(opts: RuntimePsOptions): Promise - run(opts: RuntimeRunOptions): Promise + readonly name: RuntimeBackendName; + up(opts: RuntimeUpOptions): Promise; + down(opts: RuntimeDownOptions): Promise; + psJson(opts: RuntimePsOptions): ReturnType; + ps(opts: RuntimePsOptions): Promise; + run(opts: RuntimeRunOptions): Promise; } export interface RuntimeBaseOptions { - readonly composeFiles: readonly string[] - readonly composeProject?: string | null - readonly profiles?: readonly string[] - readonly cwd: string + readonly composeFiles: readonly string[]; + readonly composeProject?: string | null; + readonly profiles?: readonly string[]; + readonly cwd: string; } export interface RuntimeUpOptions extends RuntimeBaseOptions { - readonly detach: boolean + readonly detach: boolean; } export interface RuntimeDownOptions extends RuntimeBaseOptions {} @@ -29,9 +29,9 @@ export interface RuntimeDownOptions extends RuntimeBaseOptions {} export interface RuntimePsOptions extends RuntimeBaseOptions {} export interface RuntimeRunOptions extends RuntimeBaseOptions { - readonly service: string - readonly workdir?: string - readonly cmdArgs: readonly string[] + readonly service: string; + readonly workdir?: string; + readonly cmdArgs: readonly string[]; } function buildComposeArgs(opts: RuntimeBaseOptions): string[] { @@ -39,62 +39,68 @@ function buildComposeArgs(opts: RuntimeBaseOptions): string[] { "docker", "compose", ...(opts.composeProject ? ["-p", opts.composeProject] : []), - ...opts.composeFiles.flatMap(file => ["-f", file] as const), - ...(opts.profiles ? opts.profiles.flatMap(profile => ["--profile", profile] as const) : []) - ] + ...opts.composeFiles.flatMap((file) => ["-f", file] as const), + ...(opts.profiles + ? opts.profiles.flatMap((profile) => ["--profile", profile] as const) + : []), + ]; } export const composeRuntimeBackend: RuntimeBackend = { name: "compose", async up(opts) { - const cmd = [...buildComposeArgs(opts), "up", ...(opts.detach ? ["-d"] : [])] + const cmd = [ + ...buildComposeArgs(opts), + "up", + ...(opts.detach ? ["-d"] : []), + ]; if (opts.detach) { - return await run(cmd, { cwd: opts.cwd }) + return await run(cmd, { cwd: opts.cwd }); } const proc = Bun.spawn(cmd, { cwd: opts.cwd, stdin: "inherit", stdout: "pipe", - stderr: "pipe" - }) + stderr: "pipe", + }); const stdoutGrouper = createStructuredLogGrouper({ - write: text => process.stdout.write(text) - }) + write: (text) => process.stdout.write(text), + }); const stderrGrouper = createStructuredLogGrouper({ - write: text => process.stderr.write(text) - }) + write: (text) => process.stderr.write(text), + }); const stdoutTask = (async () => { for await (const line of readLinesFromStream(proc.stdout)) { - stdoutGrouper.handleLine(line) + stdoutGrouper.handleLine(line); } - })() + })(); const stderrTask = (async () => { for await (const line of readLinesFromStream(proc.stderr)) { - stderrGrouper.handleLine(line) + stderrGrouper.handleLine(line); } - })() + })(); - const exitCode = await proc.exited - await Promise.all([stdoutTask, stderrTask]) - stdoutGrouper.flush() - stderrGrouper.flush() - return exitCode + const exitCode = await proc.exited; + await Promise.all([stdoutTask, stderrTask]); + stdoutGrouper.flush(); + stderrGrouper.flush(); + return exitCode; }, async down(opts) { - const cmd = [...buildComposeArgs(opts), "down"] - return await run(cmd, { cwd: opts.cwd }) + const cmd = [...buildComposeArgs(opts), "down"]; + return await run(cmd, { cwd: opts.cwd }); }, async psJson(opts) { - const cmd = [...buildComposeArgs(opts), "ps", "--format", "json"] - return await exec(cmd, { cwd: opts.cwd, stdin: "ignore" }) + const cmd = [...buildComposeArgs(opts), "ps", "--format", "json"]; + return await exec(cmd, { cwd: opts.cwd, stdin: "ignore" }); }, async ps(opts) { - const cmd = [...buildComposeArgs(opts), "ps"] - return await run(cmd, { cwd: opts.cwd }) + const cmd = [...buildComposeArgs(opts), "ps"]; + return await run(cmd, { cwd: opts.cwd }); }, async run(opts) { const cmd = [ @@ -103,8 +109,8 @@ export const composeRuntimeBackend: RuntimeBackend = { "--rm", ...(opts.workdir && opts.workdir.length > 0 ? ["-w", opts.workdir] : []), opts.service, - ...(opts.cmdArgs.length > 0 ? opts.cmdArgs : []) - ] - return await run(cmd, { cwd: opts.cwd, stdin: "inherit" }) - } -} + ...(opts.cmdArgs.length > 0 ? opts.cmdArgs : []), + ]; + return await run(cmd, { cwd: opts.cwd, stdin: "inherit" }); + }, +}; diff --git a/src/cli/args.ts b/src/cli/args.ts index 0237ee4b..5037593f 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -1,86 +1,101 @@ export interface ParsedArgs { - readonly positionals: readonly string[] - readonly flags: ReadonlyMap + readonly positionals: readonly string[]; + readonly flags: ReadonlyMap; } export function parseArgs(argv: readonly string[]): ParsedArgs { - const positionals: string[] = [] - const flags = new Map() + const positionals: string[] = []; + const flags = new Map(); - let i = 0 - let parsingFlags = true + let i = 0; + let parsingFlags = true; while (i < argv.length) { - const token = argv[i] ?? "" - i += 1 + const token = argv[i] ?? ""; + i += 1; if (!parsingFlags) { - positionals.push(token) - continue + positionals.push(token); + continue; } if (token === "--") { - parsingFlags = false - continue + parsingFlags = false; + continue; } if (token.startsWith("--")) { - const eqIdx = token.indexOf("=") + const eqIdx = token.indexOf("="); if (eqIdx !== -1) { - const key = token.slice(0, eqIdx) - const value = token.slice(eqIdx + 1) - flags.set(key, value) - continue + const key = token.slice(0, eqIdx); + const value = token.slice(eqIdx + 1); + flags.set(key, value); + continue; } - const key = token - const next = argv[i] + const key = token; + const next = argv[i]; if (next && !next.startsWith("-")) { - flags.set(key, next) - i += 1 + flags.set(key, next); + i += 1; } else { - flags.set(key, true) + flags.set(key, true); } - continue + continue; } if (token.startsWith("-") && token.length > 1) { // Support combined short flags, e.g. -fd - const shortFlags = token.slice(1).split("") + const shortFlags = token.slice(1).split(""); for (const sf of shortFlags) { - flags.set(`-${sf}`, true) + flags.set(`-${sf}`, true); } - continue + continue; } - positionals.push(token) + positionals.push(token); } - return { positionals, flags } + return { positionals, flags }; } -export function getFlagBoolean(args: ParsedArgs, names: readonly string[]): boolean { +export function getFlagBoolean( + args: ParsedArgs, + names: readonly string[] +): boolean { for (const name of names) { - const value = args.flags.get(name) - if (value === true) return true + const value = args.flags.get(name); + if (value === true) { + return true; + } if (typeof value === "string") { - return value === "true" || value === "1" || value === "yes" + return value === "true" || value === "1" || value === "yes"; } } - return false + return false; } -export function getFlagString(args: ParsedArgs, names: readonly string[]): string | undefined { +export function getFlagString( + args: ParsedArgs, + names: readonly string[] +): string | undefined { for (const name of names) { - const value = args.flags.get(name) - if (typeof value === "string") return value + const value = args.flags.get(name); + if (typeof value === "string") { + return value; + } } - return undefined + return undefined; } -export function getFlagInt(args: ParsedArgs, names: readonly string[]): number | undefined { - const raw = getFlagString(args, names) - if (!raw) return undefined - const n = Number.parseInt(raw, 10) - return Number.isFinite(n) ? n : undefined +export function getFlagInt( + args: ParsedArgs, + names: readonly string[] +): number | undefined { + const raw = getFlagString(args, names); + if (!raw) { + return undefined; + } + const n = Number.parseInt(raw, 10); + return Number.isFinite(n) ? n : undefined; } diff --git a/src/cli/command.ts b/src/cli/command.ts index 2b9f67f9..1739d46f 100644 --- a/src/cli/command.ts +++ b/src/cli/command.ts @@ -1,6 +1,9 @@ -import { parseArgs as bunParseArgs } from "util" +import { parseArgs as bunParseArgs } from "node:util"; -import { isRecord, isStringArray } from "../lib/guards.ts" +import { isRecord, isStringArray } from "../lib/guards.ts"; + +const LONG_OPTION_PREFIX_REGEX = /^--/; +const SHORT_OPTION_PREFIX_REGEX = /^-/; export type CliGroup = | "Global" @@ -10,81 +13,91 @@ export type CliGroup = | "Diagnostics" | "Secrets" | "Fun" - | "Internal" + | "Internal"; -export type OptionType = "boolean" | "string" | "number" +export type OptionType = "boolean" | "string" | "number"; export interface OptionSpec { - readonly name: Name - readonly type: OptionType - readonly long: `--${string}` - readonly short?: `-${string}` - readonly valueHint?: string // e.g. "", "" - readonly description: string - readonly defaultValue?: string + readonly name: Name; + readonly type: OptionType; + readonly long: `--${string}`; + readonly short?: `-${string}`; + readonly valueHint?: string; // e.g. "", "" + readonly description: string; + readonly defaultValue?: string; } export interface PositionalSpec { - readonly name: Name - readonly required?: boolean - readonly multiple?: boolean - readonly description?: string + readonly name: Name; + readonly required?: boolean; + readonly multiple?: boolean; + readonly description?: string; } export interface CliContext { - readonly cwd: string - readonly cli: CliSpec + readonly cwd: string; + readonly cli: CliSpec; } -export type OptionValue = - T extends "boolean" ? boolean - : T extends "number" ? number | undefined - : string | undefined +export type OptionValue = T extends "boolean" + ? boolean + : T extends "number" + ? number | undefined + : string | undefined; export type OptionsValues = Prettify< { - readonly [O in Opts[number] as O["name"]]: OptionValue + readonly [O in Opts[number] as O["name"]]: OptionValue; } & {} -> - -type PosValueFromSpec = - S extends { multiple: true } ? { readonly [K in S["name"]]: string[] } - : S extends { required: true } ? { readonly [K in S["name"]]: string } - : { readonly [K in S["name"]]: string | undefined } - -type UnionToIntersection = - (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never +>; + +type PosValueFromSpec = S extends { multiple: true } + ? { readonly [K in S["name"]]: string[] } + : S extends { required: true } + ? { readonly [K in S["name"]]: string } + : { readonly [K in S["name"]]: string | undefined }; + +type UnionToIntersection = ( + U extends unknown + ? (k: U) => void + : never +) extends (k: infer I) => void + ? I + : never; export type PositionalsValues = Prettify< - (Pos[number] extends never ? {} : UnionToIntersection>) & {} -> + (Pos[number] extends never + ? Record + : UnionToIntersection>) & + Record +>; export type CommandArgs< Opts extends readonly OptionSpec[], - Pos extends readonly PositionalSpec[] + Pos extends readonly PositionalSpec[], > = { - readonly options: OptionsValues - readonly positionals: PositionalsValues + readonly options: OptionsValues; + readonly positionals: PositionalsValues; readonly raw: { - readonly argv: readonly string[] - readonly positionals: readonly string[] - } -} + readonly argv: readonly string[]; + readonly positionals: readonly string[]; + }; +}; export interface CommandSpec< Name extends string = string, Opts extends readonly OptionSpec[] = readonly [], Pos extends readonly PositionalSpec[] = readonly [], - Subs extends readonly AnyCommandSpec[] = readonly [] + Subs extends readonly AnyCommandSpec[] = readonly [], > { - readonly name: Name - readonly summary: string - readonly group: CliGroup - readonly description?: string - readonly options: Opts - readonly positionals: Pos - readonly subcommands: Subs - readonly expandInRootHelp?: boolean + readonly name: Name; + readonly summary: string; + readonly group: CliGroup; + readonly description?: string; + readonly options: Opts; + readonly positionals: Pos; + readonly subcommands: Subs; + readonly expandInRootHelp?: boolean; } export type AnyCommandSpec = CommandSpec< @@ -92,52 +105,55 @@ export type AnyCommandSpec = CommandSpec< readonly OptionSpec[], readonly PositionalSpec[], readonly AnyCommandSpec[] -> +>; export interface CliSpec { - readonly name: string - readonly version: string - readonly summary: string - readonly commands: readonly AnyCommandSpec[] - readonly globalOptions: readonly OptionSpec[] + readonly name: string; + readonly version: string; + readonly summary: string; + readonly commands: readonly AnyCommandSpec[]; + readonly globalOptions: readonly OptionSpec[]; } export function defineOption(opt: O): O { - return opt + return opt; } export function defineCommand(cmd: C): C { - return cmd + return cmd; } export function defineCli(cli: C): C { - return cli + return cli; } export type CommandHandlerFor = (input: { - readonly ctx: CliContext - readonly args: CommandArgs -}) => Promise + readonly ctx: CliContext; + readonly args: CommandArgs; +}) => Promise; export type CommandWithHandler = C & { - readonly handler: CommandHandlerFor -} + readonly handler: CommandHandlerFor; +}; export function withHandler( cmd: C, handler: CommandHandlerFor ): CommandWithHandler { - return { ...cmd, handler } + return { ...cmd, handler }; } export function hasHandler(cmd: AnyCommandSpec): cmd is AnyCommandSpec & { readonly handler: (input: { - readonly ctx: CliContext - readonly args: CommandArgs - }) => Promise + readonly ctx: CliContext; + readonly args: CommandArgs< + readonly OptionSpec[], + readonly PositionalSpec[] + >; + }) => Promise; } { - const maybe = cmd as unknown as { handler?: unknown } - return typeof maybe.handler === "function" + const maybe = cmd as unknown as { handler?: unknown }; + return typeof maybe.handler === "function"; } const BUILTIN_HELP_OPTION = defineOption({ @@ -145,51 +161,56 @@ const BUILTIN_HELP_OPTION = defineOption({ type: "boolean", long: "--help", short: "-h", - description: "Show help" -} as const) + description: "Show help", +} as const); const BUILTIN_VERSION_OPTION = defineOption({ name: "version", type: "boolean", long: "--version", short: "-v", - description: "Show version" -} as const) + description: "Show version", +} as const); export function builtinOptions(): readonly OptionSpec[] { - return [BUILTIN_HELP_OPTION, BUILTIN_VERSION_OPTION] + return [BUILTIN_HELP_OPTION, BUILTIN_VERSION_OPTION]; } export interface ResolvedCommand { - readonly command: AnyCommandSpec | null - readonly path: readonly AnyCommandSpec[] - readonly remainingPositionals: readonly string[] + readonly command: AnyCommandSpec | null; + readonly path: readonly AnyCommandSpec[]; + readonly remainingPositionals: readonly string[]; } -export function resolveCommand(cli: CliSpec, positionals: readonly string[]): ResolvedCommand { - const path: AnyCommandSpec[] = [] - let subcommands: readonly AnyCommandSpec[] = cli.commands - let idx = 0 +export function resolveCommand( + cli: CliSpec, + positionals: readonly string[] +): ResolvedCommand { + const path: AnyCommandSpec[] = []; + let subcommands: readonly AnyCommandSpec[] = cli.commands; + let idx = 0; while (idx < positionals.length) { - const token = positionals[idx] ?? "" - const next = subcommands.find(c => c.name === token) - if (!next) break - path.push(next) - subcommands = next.subcommands - idx += 1 + const token = positionals[idx] ?? ""; + const next = subcommands.find((c) => c.name === token); + if (!next) { + break; + } + path.push(next); + subcommands = next.subcommands; + idx += 1; } return { - command: path.length > 0 ? (path[path.length - 1] ?? null) : null, + command: path.length > 0 ? (path.at(-1) ?? null) : null, path, - remainingPositionals: positionals.slice(idx) - } + remainingPositionals: positionals.slice(idx), + }; } export interface ParsedCliInvocation { - readonly values: Record - readonly positionals: readonly string[] + readonly values: Record; + readonly positionals: readonly string[]; } export function parseCliArgv( @@ -197,118 +218,136 @@ export function parseCliArgv( argv: readonly string[], opts?: { readonly allowUnknownOptions?: boolean } ): ParsedCliInvocation { - const normalizedArgv = normalizeArgvForDefaults(cli, argv) - const options = buildUnionParseOptions(cli) + const normalizedArgv = normalizeArgvForDefaults(cli, argv); + const options = buildUnionParseOptions(cli); - let parsed: unknown + let parsed: unknown; try { parsed = bunParseArgs({ args: [...normalizedArgv], options, strict: opts?.allowUnknownOptions !== true, - allowPositionals: true - }) + allowPositionals: true, + }); } catch (error: unknown) { - const message = error instanceof Error ? error.message : "Invalid arguments" - throw new CliUsageError(message) + const message = + error instanceof Error ? error.message : "Invalid arguments"; + throw new CliUsageError(message); } - const valuesUnknown: unknown = (parsed as unknown as { values: unknown }).values - const posUnknown: unknown = (parsed as unknown as { positionals: unknown }).positionals + const valuesUnknown: unknown = (parsed as unknown as { values: unknown }) + .values; + const posUnknown: unknown = (parsed as unknown as { positionals: unknown }) + .positionals; if (!isRecord(valuesUnknown)) { - return { values: {}, positionals: [] } + return { values: {}, positionals: [] }; } if (!isStringArray(posUnknown)) { - return { values: valuesUnknown, positionals: [] } + return { values: valuesUnknown, positionals: [] }; } - return { values: valuesUnknown, positionals: posUnknown } + return { values: valuesUnknown, positionals: posUnknown }; } -function normalizeArgvForDefaults(cli: CliSpec, argv: readonly string[]): string[] { - const defaultable = new Map() +function normalizeArgvForDefaults( + cli: CliSpec, + argv: readonly string[] +): string[] { + const defaultable = new Map(); for (const opt of [...builtinOptions(), ...collectAllOptions(cli)]) { - if (opt.type === "boolean") continue - if (!opt.defaultValue) continue - defaultable.set(opt.long, opt) + if (opt.type === "boolean") { + continue; + } + if (!opt.defaultValue) { + continue; + } + defaultable.set(opt.long, opt); } - const out: string[] = [] + const out: string[] = []; for (let i = 0; i < argv.length; i += 1) { - const token = argv[i] ?? "" + const token = argv[i] ?? ""; if (!token.startsWith("--")) { - out.push(token) - continue + out.push(token); + continue; } - const eqIdx = token.indexOf("=") + const eqIdx = token.indexOf("="); if (eqIdx !== -1) { - out.push(token) - continue + out.push(token); + continue; } - const opt = defaultable.get(token) + const opt = defaultable.get(token); if (!opt) { - out.push(token) - continue + out.push(token); + continue; } - const next = argv[i + 1] + const next = argv[i + 1]; if (next === undefined || next.startsWith("-")) { - out.push(`${token}=${opt.defaultValue}`) - continue + out.push(`${token}=${opt.defaultValue}`); + continue; } if (opt.type === "number") { - const n = Number(next) + const n = Number(next); if (!Number.isFinite(n)) { - out.push(`${token}=${opt.defaultValue}`) - continue + out.push(`${token}=${opt.defaultValue}`); + continue; } } - out.push(token) + out.push(token); } - return out + return out; } function buildUnionParseOptions( cli: CliSpec ): Record { - const out: Record = {} + const out: Record = + {}; for (const opt of [...builtinOptions(), ...collectAllOptions(cli)]) { - const longName = opt.long.replace(/^--/, "") - const short = opt.short ? opt.short.replace(/^-/, "") : null + const longName = opt.long.replace(LONG_OPTION_PREFIX_REGEX, ""); + const short = opt.short + ? opt.short.replace(SHORT_OPTION_PREFIX_REGEX, "") + : null; out[longName] = - short === null ? - { type: opt.type === "boolean" ? "boolean" : "string" } - : { type: opt.type === "boolean" ? "boolean" : "string", short } + short === null + ? { type: opt.type === "boolean" ? "boolean" : "string" } + : { type: opt.type === "boolean" ? "boolean" : "string", short }; } - return out + return out; } function collectAllOptions(cli: CliSpec): readonly OptionSpec[] { - const out: OptionSpec[] = [...cli.globalOptions] - walkCommands(cli.commands, cmd => { - out.push(...cmd.options) - }) - return out + const out: OptionSpec[] = [...cli.globalOptions]; + walkCommands(cli.commands, (cmd) => { + out.push(...cmd.options); + }); + return out; } export function collectUnionOptionNames(cli: CliSpec): ReadonlySet { - const set = new Set() + const set = new Set(); for (const opt of [...builtinOptions(), ...collectAllOptions(cli)]) { - set.add(opt.long.replace(/^--/, "")) + set.add(opt.long.replace(LONG_OPTION_PREFIX_REGEX, "")); } - return set + return set; } -function walkCommands(cmds: readonly AnyCommandSpec[], visit: (cmd: AnyCommandSpec) => void): void { +function walkCommands( + cmds: readonly AnyCommandSpec[], + visit: (cmd: AnyCommandSpec) => void +): void { for (const c of cmds) { - visit(c) - if (c.subcommands.length > 0) walkCommands(c.subcommands, visit) + visit(c); + if (c.subcommands.length > 0) { + walkCommands(c.subcommands, visit); + } } } @@ -316,100 +355,109 @@ export function collectAllowedOptionNames( cli: CliSpec, command: AnyCommandSpec | null ): ReadonlySet { - const allowed = new Set() - for (const opt of builtinOptions()) allowed.add(opt.long.replace(/^--/, "")) - for (const opt of cli.globalOptions) allowed.add(opt.long.replace(/^--/, "")) - if (command) for (const opt of command.options) allowed.add(opt.long.replace(/^--/, "")) - return allowed + const allowed = new Set(); + for (const opt of builtinOptions()) { + allowed.add(opt.long.replace(LONG_OPTION_PREFIX_REGEX, "")); + } + for (const opt of cli.globalOptions) { + allowed.add(opt.long.replace(LONG_OPTION_PREFIX_REGEX, "")); + } + if (command) { + for (const opt of command.options) { + allowed.add(opt.long.replace(LONG_OPTION_PREFIX_REGEX, "")); + } + } + return allowed; } export function parseOptionsForCommand( opts: Opts, values: Record ): OptionsValues { - const out: Record = {} + const out: Record = {}; for (const opt of opts) { - const key = opt.long.replace(/^--/, "") - const raw = values[key] + const key = opt.long.replace(LONG_OPTION_PREFIX_REGEX, ""); + const raw = values[key]; if (opt.type === "boolean") { - out[opt.name] = raw === true - continue + out[opt.name] = raw === true; + continue; } if (opt.type === "string") { - out[opt.name] = typeof raw === "string" ? raw : undefined - continue + out[opt.name] = typeof raw === "string" ? raw : undefined; + continue; } // number if (typeof raw !== "string") { - out[opt.name] = undefined - continue + out[opt.name] = undefined; + continue; } - const n = Number(raw) - out[opt.name] = Number.isFinite(n) ? n : undefined + const n = Number(raw); + out[opt.name] = Number.isFinite(n) ? n : undefined; } - return out as OptionsValues + return out as OptionsValues; } export class CliUsageError extends Error { - public constructor(message: string) { - super(message) - this.name = "CliUsageError" + constructor(message: string) { + super(message); + this.name = "CliUsageError"; } } -export function parsePositionalsForCommand( - posSpecs: Pos, - remaining: readonly string[] -): PositionalsValues { - const out: Record = {} - let idx = 0 +export function parsePositionalsForCommand< + Pos extends readonly PositionalSpec[], +>(posSpecs: Pos, remaining: readonly string[]): PositionalsValues { + const out: Record = {}; + let idx = 0; for (const spec of posSpecs) { if (spec.multiple) { - out[spec.name] = remaining.slice(idx) - idx = remaining.length - continue + out[spec.name] = remaining.slice(idx); + idx = remaining.length; + continue; } - const value = remaining[idx] + const value = remaining[idx]; if (value === undefined) { if (spec.required) { - throw new CliUsageError(`Missing required argument: ${spec.name}`) + throw new CliUsageError(`Missing required argument: ${spec.name}`); } - out[spec.name] = undefined - continue + out[spec.name] = undefined; + continue; } - out[spec.name] = value - idx += 1 + out[spec.name] = value; + idx += 1; } if (idx < remaining.length) { - const extra = remaining.slice(idx).join(" ") - throw new CliUsageError(`Unexpected arguments: ${extra}`) + const extra = remaining.slice(idx).join(" "); + throw new CliUsageError(`Unexpected arguments: ${extra}`); } - return out as PositionalsValues + return out as PositionalsValues; } export function renderArgsFromPositionals( pos: readonly PositionalSpec[] | undefined ): string | undefined { - if (!pos || pos.length === 0) return undefined - const parts: string[] = [] + if (!pos || pos.length === 0) { + return undefined; + } + const parts: string[] = []; for (const p of pos) { - const name = p.multiple ? `${p.name}...` : p.name - parts.push(p.required ? `<${name}>` : `[${name}]`) + const name = p.multiple ? `${p.name}...` : p.name; + parts.push(p.required ? `<${name}>` : `[${name}]`); } - return parts.join(" ") + return parts.join(" "); } -export type Prettify = { [K in keyof T]: T[K] } & {} +export type Prettify = { [K in keyof T]: T[K] } & {}; diff --git a/src/cli/help.ts b/src/cli/help.ts index 6fe5461d..f58e6435 100644 --- a/src/cli/help.ts +++ b/src/cli/help.ts @@ -1,159 +1,192 @@ -import { builtinOptions, renderArgsFromPositionals, resolveCommand } from "./command.ts" -import { renderHackBanner } from "../lib/hack-banner.ts" -import { gumFormat, isGumAvailable } from "../ui/gum.ts" - -import type { AnyCommandSpec, CliGroup, CliSpec, OptionSpec } from "./command.ts" - -export function renderHelpForPath(cli: CliSpec, positionals: readonly string[]): string { - const resolved = resolveCommand(cli, positionals) - const matchedNames = resolved.path.map(c => c.name) - return resolved.command ? - renderCommandHelp(cli, resolved.command, matchedNames) - : renderRootHelp(cli) +import { renderHackBanner } from "../lib/hack-banner.ts"; +import { gumFormat, isGumAvailable } from "../ui/gum.ts"; +import type { + AnyCommandSpec, + CliGroup, + CliSpec, + OptionSpec, +} from "./command.ts"; +import { + builtinOptions, + renderArgsFromPositionals, + resolveCommand, +} from "./command.ts"; + +export function renderHelpForPath( + cli: CliSpec, + positionals: readonly string[] +): string { + const resolved = resolveCommand(cli, positionals); + const matchedNames = resolved.path.map((c) => c.name); + return resolved.command + ? renderCommandHelp(cli, resolved.command, matchedNames) + : renderRootHelp(cli); } -export function renderHelpMarkdownForPath(cli: CliSpec, positionals: readonly string[]): string { - const resolved = resolveCommand(cli, positionals) - const matchedNames = resolved.path.map(c => c.name) - return resolved.command ? - renderCommandHelpMarkdown(cli, resolved.command, matchedNames) - : renderRootHelpMarkdown(cli) +export function renderHelpMarkdownForPath( + cli: CliSpec, + positionals: readonly string[] +): string { + const resolved = resolveCommand(cli, positionals); + const matchedNames = resolved.path.map((c) => c.name); + return resolved.command + ? renderCommandHelpMarkdown(cli, resolved.command, matchedNames) + : renderRootHelpMarkdown(cli); } export async function printHelpForPath( cli: CliSpec, positionals: readonly string[] ): Promise { - const banner = await renderHackBanner({ trimEmpty: true }) - const markdown = renderHelpMarkdownForPath(cli, positionals) + const banner = await renderHackBanner({ trimEmpty: true }); + const markdown = renderHelpMarkdownForPath(cli, positionals); const markdownWithBanner = - banner.length > 0 ? `\`\`\`text\n${banner}\n\`\`\`\n\n${markdown}` : markdown + banner.length > 0 + ? `\`\`\`text\n${banner}\n\`\`\`\n\n${markdown}` + : markdown; if (isPrettyHelpEnabled()) { - const res = await gumFormat({ type: "markdown", input: markdownWithBanner }) + const res = await gumFormat({ + type: "markdown", + input: markdownWithBanner, + }); if (res.ok) { - writeStdout(res.value) - return + writeStdout(res.value); + return; } } - const plain = renderHelpForPath(cli, positionals) - const plainWithBanner = banner.length > 0 ? `${banner}\n\n${plain}` : plain - writeStdout(plainWithBanner) + const plain = renderHelpForPath(cli, positionals); + const plainWithBanner = banner.length > 0 ? `${banner}\n\n${plain}` : plain; + writeStdout(plainWithBanner); } function isPrettyHelpEnabled(): boolean { - if (!process.stdout.isTTY) return false - return isGumAvailable() + if (!process.stdout.isTTY) { + return false; + } + return isGumAvailable(); } function writeStdout(text: string): void { - process.stdout.write(text.endsWith("\n") ? text : `${text}\n`) + process.stdout.write(text.endsWith("\n") ? text : `${text}\n`); } function renderRootHelp(cli: CliSpec): string { - const lines: string[] = [] + const lines: string[] = []; - lines.push(`${cli.name} v${cli.version} — ${cli.summary}`) - lines.push("") - lines.push("Usage:") - lines.push(` ${cli.name} [options]`) - lines.push("") + lines.push(`${cli.name} v${cli.version} — ${cli.summary}`); + lines.push(""); + lines.push("Usage:"); + lines.push(` ${cli.name} [options]`); + lines.push(""); - const grouped = groupRootEntries(cli) + const grouped = groupRootEntries(cli); for (const group of groupsInOrder()) { - const entries = grouped.get(group) - if (!entries || entries.length === 0) continue - lines.push(`${groupLabel(group)}:`) - lines.push(...renderEntryLines(entries)) - lines.push("") + const entries = grouped.get(group); + if (!entries || entries.length === 0) { + continue; + } + lines.push(`${groupLabel(group)}:`); + lines.push(...renderEntryLines(entries)); + lines.push(""); } - const rootOptions = dedupeOptions([...builtinOptions(), ...cli.globalOptions]) + const rootOptions = dedupeOptions([ + ...builtinOptions(), + ...cli.globalOptions, + ]); if (rootOptions.length > 0) { - lines.push("Global options:") - lines.push(...renderOptionLines(rootOptions)) - lines.push("") + lines.push("Global options:"); + lines.push(...renderOptionLines(rootOptions)); + lines.push(""); } - lines.push("Tip:") - lines.push(" Use `--help` after any command to see command-specific help.") - lines.push("") + lines.push("Tip:"); + lines.push(" Use `--help` after any command to see command-specific help."); + lines.push(""); - return lines.join("\n") + return lines.join("\n"); } function renderRootHelpMarkdown(cli: CliSpec): string { - const lines: string[] = [] - - lines.push(`## ${cli.name} v${cli.version}`) - lines.push("") - lines.push(mdEscape(cli.summary)) - lines.push("") - lines.push("### Usage") - lines.push("") - lines.push("```bash") - lines.push(`${cli.name} [options]`) - lines.push("```") - lines.push("") - - const grouped = groupRootEntries(cli) + const lines: string[] = []; + + lines.push(`## ${cli.name} v${cli.version}`); + lines.push(""); + lines.push(mdEscape(cli.summary)); + lines.push(""); + lines.push("### Usage"); + lines.push(""); + lines.push("```bash"); + lines.push(`${cli.name} [options]`); + lines.push("```"); + lines.push(""); + + const grouped = groupRootEntries(cli); for (const group of groupsInOrder()) { - const entries = grouped.get(group) - if (!entries || entries.length === 0) continue - lines.push(`### ${groupLabel(group)}`) - lines.push("") - lines.push(...renderEntriesTableMarkdown(entries)) - lines.push("") + const entries = grouped.get(group); + if (!entries || entries.length === 0) { + continue; + } + lines.push(`### ${groupLabel(group)}`); + lines.push(""); + lines.push(...renderEntriesTableMarkdown(entries)); + lines.push(""); } - const rootOptions = dedupeOptions([...builtinOptions(), ...cli.globalOptions]) + const rootOptions = dedupeOptions([ + ...builtinOptions(), + ...cli.globalOptions, + ]); if (rootOptions.length > 0) { - lines.push("### Global options") - lines.push("") - lines.push(...renderOptionsTableMarkdown(rootOptions)) - lines.push("") + lines.push("### Global options"); + lines.push(""); + lines.push(...renderOptionsTableMarkdown(rootOptions)); + lines.push(""); } - lines.push("> Tip: Use `--help` after any command to see command-specific help.") - lines.push("") + lines.push( + "> Tip: Use `--help` after any command to see command-specific help." + ); + lines.push(""); - return lines.join("\n") + return lines.join("\n"); } type RootEntry = { - readonly group: CliGroup - readonly invocation: string - readonly summary: string -} + readonly group: CliGroup; + readonly invocation: string; + readonly summary: string; +}; function groupRootEntries(cli: CliSpec): Map { - const map = new Map() + const map = new Map(); const push = (group: CliGroup, entry: RootEntry) => { - const arr = map.get(group) ?? [] - arr.push(entry) - map.set(group, arr) - } + const arr = map.get(group) ?? []; + arr.push(entry); + map.set(group, arr); + }; for (const cmd of cli.commands) { if (cmd.expandInRootHelp && cmd.subcommands.length > 0) { for (const sub of cmd.subcommands) { - const invocation = buildInvocation(cli.name, [cmd.name, sub.name], sub) - push(cmd.group, { group: cmd.group, invocation, summary: sub.summary }) + const invocation = buildInvocation(cli.name, [cmd.name, sub.name], sub); + push(cmd.group, { group: cmd.group, invocation, summary: sub.summary }); } - continue + continue; } - const invocation = buildInvocation(cli.name, [cmd.name], cmd) - push(cmd.group, { group: cmd.group, invocation, summary: cmd.summary }) + const invocation = buildInvocation(cli.name, [cmd.name], cmd); + push(cmd.group, { group: cmd.group, invocation, summary: cmd.summary }); } for (const [group, entries] of map.entries()) { map.set( group, [...entries].sort((a, b) => a.invocation.localeCompare(b.invocation)) - ) + ); } - return map + return map; } function renderCommandHelp( @@ -161,39 +194,43 @@ function renderCommandHelp( command: AnyCommandSpec, matchedPath: readonly string[] ): string { - const lines: string[] = [] + const lines: string[] = []; - const invocation = buildInvocation(cli.name, matchedPath, command) - lines.push(`${invocation} — ${command.summary}`) - lines.push("") - lines.push("Usage:") - lines.push(` ${invocation} [options]`) - lines.push("") + const invocation = buildInvocation(cli.name, matchedPath, command); + lines.push(`${invocation} — ${command.summary}`); + lines.push(""); + lines.push("Usage:"); + lines.push(` ${invocation} [options]`); + lines.push(""); if (command.description) { - lines.push(command.description) - lines.push("") + lines.push(command.description); + lines.push(""); } if (command.subcommands.length > 0) { - lines.push("Subcommands:") - const entries = command.subcommands.map(sub => ({ + lines.push("Subcommands:"); + const entries = command.subcommands.map((sub) => ({ group: command.group, invocation: buildInvocation(cli.name, [...matchedPath, sub.name], sub), - summary: sub.summary - })) - lines.push(...renderEntryLines(entries)) - lines.push("") + summary: sub.summary, + })); + lines.push(...renderEntryLines(entries)); + lines.push(""); } - const options = dedupeOptions([...command.options, ...cli.globalOptions, ...builtinOptions()]) + const options = dedupeOptions([ + ...command.options, + ...cli.globalOptions, + ...builtinOptions(), + ]); if (options.length > 0) { - lines.push("Options:") - lines.push(...renderOptionLines(options)) - lines.push("") + lines.push("Options:"); + lines.push(...renderOptionLines(options)); + lines.push(""); } - return lines.join("\n") + return lines.join("\n"); } function renderCommandHelpMarkdown( @@ -201,141 +238,167 @@ function renderCommandHelpMarkdown( command: AnyCommandSpec, matchedPath: readonly string[] ): string { - const lines: string[] = [] + const lines: string[] = []; - const invocation = buildInvocation(cli.name, matchedPath, command) - lines.push(`## ${mdCode(invocation)}`) - lines.push("") - lines.push(mdEscape(command.summary)) - lines.push("") + const invocation = buildInvocation(cli.name, matchedPath, command); + lines.push(`## ${mdCode(invocation)}`); + lines.push(""); + lines.push(mdEscape(command.summary)); + lines.push(""); - lines.push("### Usage") - lines.push("") - lines.push("```bash") - lines.push(`${invocation} [options]`) - lines.push("```") - lines.push("") + lines.push("### Usage"); + lines.push(""); + lines.push("```bash"); + lines.push(`${invocation} [options]`); + lines.push("```"); + lines.push(""); if (command.description) { - lines.push(mdEscape(command.description)) - lines.push("") + lines.push(mdEscape(command.description)); + lines.push(""); } if (command.positionals.length > 0) { - lines.push("### Arguments") - lines.push("") - lines.push(...renderPositionalsMarkdown(command.positionals)) - lines.push("") + lines.push("### Arguments"); + lines.push(""); + lines.push(...renderPositionalsMarkdown(command.positionals)); + lines.push(""); } if (command.subcommands.length > 0) { - lines.push("### Subcommands") - lines.push("") - const entries = command.subcommands.map(sub => ({ + lines.push("### Subcommands"); + lines.push(""); + const entries = command.subcommands.map((sub) => ({ group: command.group, invocation: buildInvocation(cli.name, [...matchedPath, sub.name], sub), - summary: sub.summary - })) - lines.push(...renderEntriesTableMarkdown(entries)) - lines.push("") + summary: sub.summary, + })); + lines.push(...renderEntriesTableMarkdown(entries)); + lines.push(""); } - const options = dedupeOptions([...command.options, ...cli.globalOptions, ...builtinOptions()]) + const options = dedupeOptions([ + ...command.options, + ...cli.globalOptions, + ...builtinOptions(), + ]); if (options.length > 0) { - lines.push("### Options") - lines.push("") - lines.push(...renderOptionsTableMarkdown(options)) - lines.push("") + lines.push("### Options"); + lines.push(""); + lines.push(...renderOptionsTableMarkdown(options)); + lines.push(""); } - return lines.join("\n") + return lines.join("\n"); } -function buildInvocation(cliName: string, path: readonly string[], cmd: AnyCommandSpec): string { - const args = renderArgsFromPositionals(cmd.positionals) - const base = [cliName, ...path].join(" ") - return args ? `${base} ${args}` : base +function buildInvocation( + cliName: string, + path: readonly string[], + cmd: AnyCommandSpec +): string { + const args = renderArgsFromPositionals(cmd.positionals); + const base = [cliName, ...path].join(" "); + return args ? `${base} ${args}` : base; } function renderEntryLines(entries: readonly RootEntry[]): string[] { - const width = Math.max(...entries.map(e => e.invocation.length), 0) - return entries.map(e => ` ${padRight(e.invocation, width + 2)}${e.summary}`) + const width = Math.max(...entries.map((e) => e.invocation.length), 0); + return entries.map( + (e) => ` ${padRight(e.invocation, width + 2)}${e.summary}` + ); } function renderOptionLines(options: readonly OptionSpec[]): string[] { - const formatted = options.map(formatOption) - const width = Math.max(...formatted.map(f => f.left.length), 0) - return formatted.map(({ left, right }) => ` ${padRight(left, width + 2)}${right}`) + const formatted = options.map(formatOption); + const width = Math.max(...formatted.map((f) => f.left.length), 0); + return formatted.map( + ({ left, right }) => ` ${padRight(left, width + 2)}${right}` + ); } function renderEntriesTableMarkdown(entries: readonly RootEntry[]): string[] { - const lines: string[] = [] - lines.push("| Command | Summary |") - lines.push("| --- | --- |") + const lines: string[] = []; + lines.push("| Command | Summary |"); + lines.push("| --- | --- |"); for (const e of entries) { - lines.push(`| ${mdCode(e.invocation)} | ${mdEscape(e.summary)} |`) + lines.push(`| ${mdCode(e.invocation)} | ${mdEscape(e.summary)} |`); } - return lines + return lines; } function renderOptionsTableMarkdown(options: readonly OptionSpec[]): string[] { - const lines: string[] = [] - lines.push("| Option | Description |") - lines.push("| --- | --- |") + const lines: string[] = []; + lines.push("| Option | Description |"); + lines.push("| --- | --- |"); for (const o of options) { - const { left, right } = formatOption(o) - lines.push(`| ${mdCode(left)} | ${mdEscape(right)} |`) + const { left, right } = formatOption(o); + lines.push(`| ${mdCode(left)} | ${mdEscape(right)} |`); } - return lines + return lines; } function renderPositionalsMarkdown( positionals: readonly { - readonly name: string - readonly description?: string + readonly name: string; + readonly description?: string; }[] ): string[] { - const lines: string[] = [] - lines.push("| Arg | Description |") - lines.push("| --- | --- |") + const lines: string[] = []; + lines.push("| Arg | Description |"); + lines.push("| --- | --- |"); for (const p of positionals) { - lines.push(`| ${mdCode(p.name)} | ${mdEscape(p.description ?? "")} |`) + lines.push(`| ${mdCode(p.name)} | ${mdEscape(p.description ?? "")} |`); } - return lines + return lines; } function formatOption(o: OptionSpec): { - readonly left: string - readonly right: string + readonly left: string; + readonly right: string; } { - const parts: string[] = [] - parts.push(o.long) - if (o.short) parts.push(o.short) - - const hint = o.type === "boolean" ? "" : ` ${o.valueHint ?? ""}` - const left = `${parts.join(", ")}${hint}` - const right = o.defaultValue ? `${o.description} (default: ${o.defaultValue})` : o.description - return { left, right } + const parts: string[] = []; + parts.push(o.long); + if (o.short) { + parts.push(o.short); + } + + const hint = o.type === "boolean" ? "" : ` ${o.valueHint ?? ""}`; + const left = `${parts.join(", ")}${hint}`; + const right = o.defaultValue + ? `${o.description} (default: ${o.defaultValue})` + : o.description; + return { left, right }; } function dedupeOptions(options: readonly OptionSpec[]): OptionSpec[] { - const seen = new Set() - const out: OptionSpec[] = [] + const seen = new Set(); + const out: OptionSpec[] = []; for (const o of options) { - const key = `${o.long}|${o.short ?? ""}` - if (seen.has(key)) continue - seen.add(key) - out.push(o) + const key = `${o.long}|${o.short ?? ""}`; + if (seen.has(key)) { + continue; + } + seen.add(key); + out.push(o); } - return out + return out; } function padRight(text: string, width: number): string { - return text.length >= width ? text : text + " ".repeat(width - text.length) + return text.length >= width ? text : text + " ".repeat(width - text.length); } function groupsInOrder(): readonly CliGroup[] { - return ["Global", "Project", "Extensions", "Agents", "Diagnostics", "Secrets", "Fun"] as const + return [ + "Global", + "Project", + "Extensions", + "Agents", + "Diagnostics", + "Secrets", + "Fun", + ] as const; } function groupLabel(group: CliGroup): string { @@ -348,15 +411,15 @@ function groupLabel(group: CliGroup): string { Diagnostics: "Diagnostics", Secrets: "Secrets", Fun: "Fun", - Internal: "Internal" + Internal: "Internal", } satisfies Record - )[group] + )[group]; } function mdCode(text: string): string { - return `\`${text}\`` + return `\`${text}\``; } function mdEscape(text: string): string { - return text.replaceAll("|", "\\|") + return text.replaceAll("|", "\\|"); } diff --git a/src/cli/options.ts b/src/cli/options.ts index 94e1b513..52b4853a 100644 --- a/src/cli/options.ts +++ b/src/cli/options.ts @@ -1,4 +1,4 @@ -import { defineOption } from "./command.ts" +import { defineOption } from "./command.ts"; export const optPath = defineOption({ name: "path", @@ -6,39 +6,42 @@ export const optPath = defineOption({ long: "--path", short: "-p", valueHint: "", - description: "Run a project command against a repo path (overrides cwd search)" -} as const) + description: + "Run a project command against a repo path (overrides cwd search)", +} as const); export const optProject = defineOption({ name: "project", type: "string", long: "--project", valueHint: "", - description: "Target a registered project by name (from ~/.hack/projects.json)" -} as const) + description: + "Target a registered project by name (from ~/.hack/projects.json)", +} as const); export const optBranch = defineOption({ name: "branch", type: "string", long: "--branch", valueHint: "", - description: "Run against a branch-specific instance (compose name + hostnames)" -} as const) + description: + "Run against a branch-specific instance (compose name + hostnames)", +} as const); export const optFollow = defineOption({ name: "follow", type: "boolean", long: "--follow", short: "-f", - description: "Follow logs (default for `hack logs`)" -} as const) + description: "Follow logs (default for `hack logs`)", +} as const); export const optNoFollow = defineOption({ name: "noFollow", type: "boolean", long: "--no-follow", - description: "Print logs and exit (do not follow)" -} as const) + description: "Print logs and exit (do not follow)", +} as const); export const optTail = defineOption({ name: "tail", @@ -46,51 +49,51 @@ export const optTail = defineOption({ long: "--tail", valueHint: "", description: "Tail last N log lines", - defaultValue: "200" -} as const) + defaultValue: "200", +} as const); export const optProfile = defineOption({ name: "profile", type: "string", long: "--profile", valueHint: "", - description: "Enable one or more compose profiles (comma-separated)" -} as const) + description: "Enable one or more compose profiles (comma-separated)", +} as const); export const optDetach = defineOption({ name: "detach", type: "boolean", long: "--detach", short: "-d", - description: "Run in background (docker compose up -d)" -} as const) + description: "Run in background (docker compose up -d)", +} as const); export const optPretty = defineOption({ name: "pretty", type: "boolean", long: "--pretty", - description: "Pretty-print logs (best-effort JSON parsing + formatting)" -} as const) + description: "Pretty-print logs (best-effort JSON parsing + formatting)", +} as const); export const optJson = defineOption({ name: "json", type: "boolean", long: "--json", - description: "Output JSON (machine-readable)" -} as const) + description: "Output JSON (machine-readable)", +} as const); export const optSince = defineOption({ name: "since", type: "string", long: "--since", valueHint: "