@hoox-sh/hoox-shared 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,7 +16,13 @@ var __export = (target, all) => {
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/path-utils.ts
19
- import { existsSync } from "fs";
19
+ import {
20
+ existsSync,
21
+ mkdirSync,
22
+ readFileSync,
23
+ writeFileSync,
24
+ chmodSync
25
+ } from "fs";
20
26
  import { homedir } from "os";
21
27
  import { dirname, join, resolve } from "path";
22
28
  function createHooxPath(path) {
@@ -42,7 +48,55 @@ function isHooxSetupRoot(dir) {
42
48
  return false;
43
49
  try {
44
50
  const root = resolve(dir);
45
- return existsSync(join(root, "wrangler.jsonc")) && existsSync(join(root, "packages", "cli", "package.json"));
51
+ if (!existsSync(join(root, "packages", "cli", "package.json"))) {
52
+ return false;
53
+ }
54
+ return existsSync(join(root, "wrangler.jsonc")) || existsSync(join(root, "wrangler.jsonc.example")) || existsSync(join(root, "workers")) || existsSync(join(root, ".gitmodules"));
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+ function getRememberedMonorepoPath() {
60
+ return resolveHooxPath("config/monorepo.json");
61
+ }
62
+ function getRememberedMonorepoRoot() {
63
+ try {
64
+ const path = getRememberedMonorepoPath();
65
+ if (!existsSync(path))
66
+ return null;
67
+ const raw = readFileSync(path, "utf-8");
68
+ const data = JSON.parse(raw);
69
+ if (!data.root || typeof data.root !== "string")
70
+ return null;
71
+ const resolved = resolve(data.root);
72
+ return isHooxSetupRoot(resolved) ? resolved : null;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function rememberMonorepoRoot(root) {
78
+ try {
79
+ const resolved = resolve(root);
80
+ if (!isHooxSetupRoot(resolved))
81
+ return false;
82
+ const configDir = getHooxConfigDir();
83
+ mkdirSync(configDir, { recursive: true, mode: 448 });
84
+ try {
85
+ chmodSync(configDir, 448);
86
+ } catch {}
87
+ const payload = {
88
+ root: resolved,
89
+ updatedAt: new Date().toISOString()
90
+ };
91
+ const path = getRememberedMonorepoPath();
92
+ writeFileSync(path, JSON.stringify(payload, null, 2) + `
93
+ `, {
94
+ mode: 384
95
+ });
96
+ try {
97
+ chmodSync(path, 384);
98
+ } catch {}
99
+ return true;
46
100
  } catch {
47
101
  return false;
48
102
  }
@@ -62,6 +116,7 @@ function resolveHooxRuntimeRoot(options) {
62
116
  const env = options?.env ?? process.env;
63
117
  const cwd = resolve(options?.cwd ?? process.cwd());
64
118
  const globalRepo = getHooxRepoPath();
119
+ const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
65
120
  const envRepo = env.HOOX_REPO?.trim();
66
121
  if (envRepo) {
67
122
  const resolved = resolve(envRepo);
@@ -72,6 +127,7 @@ function resolveHooxRuntimeRoot(options) {
72
127
  checked: {
73
128
  env: resolved,
74
129
  cwd: findHooxSetupRoot(cwd),
130
+ remembered,
75
131
  global: globalRepo
76
132
  }
77
133
  };
@@ -82,6 +138,7 @@ function resolveHooxRuntimeRoot(options) {
82
138
  checked: {
83
139
  env: resolved,
84
140
  cwd: findHooxSetupRoot(cwd),
141
+ remembered,
85
142
  global: globalRepo
86
143
  }
87
144
  };
@@ -91,20 +148,27 @@ function resolveHooxRuntimeRoot(options) {
91
148
  return {
92
149
  root: local,
93
150
  source: "cwd",
94
- checked: { cwd: local, global: globalRepo }
151
+ checked: { cwd: local, remembered, global: globalRepo }
152
+ };
153
+ }
154
+ if (remembered) {
155
+ return {
156
+ root: remembered,
157
+ source: "remembered",
158
+ checked: { cwd: null, remembered, global: globalRepo }
95
159
  };
96
160
  }
97
161
  if (isHooxSetupRoot(globalRepo)) {
98
162
  return {
99
163
  root: globalRepo,
100
164
  source: "global",
101
- checked: { cwd: null, global: globalRepo }
165
+ checked: { cwd: null, remembered: null, global: globalRepo }
102
166
  };
103
167
  }
104
168
  return {
105
169
  root: null,
106
170
  source: "none",
107
- checked: { cwd: null, global: globalRepo }
171
+ checked: { cwd: null, remembered: null, global: globalRepo }
108
172
  };
109
173
  }
110
174
  function getTuiEntryCandidates(runtimeRoot) {
@@ -174,9 +238,12 @@ function getHooxStatePath() {
174
238
  export {
175
239
  resolveHooxRuntimeRoot,
176
240
  resolveHooxPath,
241
+ rememberMonorepoRoot,
177
242
  isWithinHooxHome,
178
243
  isHooxSetupRoot,
179
244
  getTuiEntryCandidates,
245
+ getRememberedMonorepoRoot,
246
+ getRememberedMonorepoPath,
180
247
  getRelativeHooxPath,
181
248
  getHooxWranglerPath,
182
249
  getHooxStatePath,
package/dist/session.js CHANGED
@@ -16,7 +16,13 @@ var __export = (target, all) => {
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/path-utils.ts
19
- import { existsSync } from "fs";
19
+ import {
20
+ existsSync,
21
+ mkdirSync,
22
+ readFileSync,
23
+ writeFileSync,
24
+ chmodSync
25
+ } from "fs";
20
26
  import { homedir } from "os";
21
27
  import { dirname, join, resolve } from "path";
22
28
  function createHooxPath(path) {
@@ -42,7 +48,55 @@ function isHooxSetupRoot(dir) {
42
48
  return false;
43
49
  try {
44
50
  const root = resolve(dir);
45
- return existsSync(join(root, "wrangler.jsonc")) && existsSync(join(root, "packages", "cli", "package.json"));
51
+ if (!existsSync(join(root, "packages", "cli", "package.json"))) {
52
+ return false;
53
+ }
54
+ return existsSync(join(root, "wrangler.jsonc")) || existsSync(join(root, "wrangler.jsonc.example")) || existsSync(join(root, "workers")) || existsSync(join(root, ".gitmodules"));
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+ function getRememberedMonorepoPath() {
60
+ return resolveHooxPath("config/monorepo.json");
61
+ }
62
+ function getRememberedMonorepoRoot() {
63
+ try {
64
+ const path = getRememberedMonorepoPath();
65
+ if (!existsSync(path))
66
+ return null;
67
+ const raw = readFileSync(path, "utf-8");
68
+ const data = JSON.parse(raw);
69
+ if (!data.root || typeof data.root !== "string")
70
+ return null;
71
+ const resolved = resolve(data.root);
72
+ return isHooxSetupRoot(resolved) ? resolved : null;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function rememberMonorepoRoot(root) {
78
+ try {
79
+ const resolved = resolve(root);
80
+ if (!isHooxSetupRoot(resolved))
81
+ return false;
82
+ const configDir = getHooxConfigDir();
83
+ mkdirSync(configDir, { recursive: true, mode: 448 });
84
+ try {
85
+ chmodSync(configDir, 448);
86
+ } catch {}
87
+ const payload = {
88
+ root: resolved,
89
+ updatedAt: new Date().toISOString()
90
+ };
91
+ const path = getRememberedMonorepoPath();
92
+ writeFileSync(path, JSON.stringify(payload, null, 2) + `
93
+ `, {
94
+ mode: 384
95
+ });
96
+ try {
97
+ chmodSync(path, 384);
98
+ } catch {}
99
+ return true;
46
100
  } catch {
47
101
  return false;
48
102
  }
@@ -62,6 +116,7 @@ function resolveHooxRuntimeRoot(options) {
62
116
  const env = options?.env ?? process.env;
63
117
  const cwd = resolve(options?.cwd ?? process.cwd());
64
118
  const globalRepo = getHooxRepoPath();
119
+ const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
65
120
  const envRepo = env.HOOX_REPO?.trim();
66
121
  if (envRepo) {
67
122
  const resolved = resolve(envRepo);
@@ -72,6 +127,7 @@ function resolveHooxRuntimeRoot(options) {
72
127
  checked: {
73
128
  env: resolved,
74
129
  cwd: findHooxSetupRoot(cwd),
130
+ remembered,
75
131
  global: globalRepo
76
132
  }
77
133
  };
@@ -82,6 +138,7 @@ function resolveHooxRuntimeRoot(options) {
82
138
  checked: {
83
139
  env: resolved,
84
140
  cwd: findHooxSetupRoot(cwd),
141
+ remembered,
85
142
  global: globalRepo
86
143
  }
87
144
  };
@@ -91,20 +148,27 @@ function resolveHooxRuntimeRoot(options) {
91
148
  return {
92
149
  root: local,
93
150
  source: "cwd",
94
- checked: { cwd: local, global: globalRepo }
151
+ checked: { cwd: local, remembered, global: globalRepo }
152
+ };
153
+ }
154
+ if (remembered) {
155
+ return {
156
+ root: remembered,
157
+ source: "remembered",
158
+ checked: { cwd: null, remembered, global: globalRepo }
95
159
  };
96
160
  }
97
161
  if (isHooxSetupRoot(globalRepo)) {
98
162
  return {
99
163
  root: globalRepo,
100
164
  source: "global",
101
- checked: { cwd: null, global: globalRepo }
165
+ checked: { cwd: null, remembered: null, global: globalRepo }
102
166
  };
103
167
  }
104
168
  return {
105
169
  root: null,
106
170
  source: "none",
107
- checked: { cwd: null, global: globalRepo }
171
+ checked: { cwd: null, remembered: null, global: globalRepo }
108
172
  };
109
173
  }
110
174
  function getTuiEntryCandidates(runtimeRoot) {
@@ -3,6 +3,8 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import type { ViewId, LogFilter, NotificationPreferences } from "../types";
6
+ /** TUI prefs file — isolated from operator config.json (which may hold apiToken). */
7
+ export declare function getTuiPreferencesPath(): string;
6
8
  export interface ConfigState {
7
9
  theme: "dark" | "light";
8
10
  refreshIntervalMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAoF3E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,SAAS,CAAC;IACtB,aAAa,EAAE,uBAAuB,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,UAAU,aAAa;IACrB,+DAA+D;IAC/D,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACtD,8CAA8C;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,yCAAyC;IACzC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8CAA8C;IAC9C,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI,CAAC;CACtE;AAiBD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;eAtClB,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;;eApB7D,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;EA+ErE,CAAC"}
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAM3E,qFAAqF;AACrF,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AA0ID,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,SAAS,CAAC;IACtB,aAAa,EAAE,uBAAuB,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,UAAU,aAAa;IACrB,+DAA+D;IAC/D,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACtD,8CAA8C;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,yCAAyC;IACzC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8CAA8C;IAC9C,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI,CAAC;CACtE;AAiBD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;eAtClB,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;;eApB7D,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;EA+ErE,CAAC"}
@@ -131,37 +131,287 @@ function validateConfig(config) {
131
131
  return errors;
132
132
  }
133
133
 
134
+ // src/path-utils.ts
135
+ import {
136
+ existsSync as existsSync2,
137
+ mkdirSync as mkdirSync2,
138
+ readFileSync as readFileSync2,
139
+ writeFileSync as writeFileSync2,
140
+ chmodSync as chmodSync2
141
+ } from "fs";
142
+ import { homedir as homedir2 } from "os";
143
+ import { dirname, join as join2, resolve } from "path";
144
+ function createHooxPath(path) {
145
+ return path;
146
+ }
147
+ function getHooxHome() {
148
+ try {
149
+ const override = process.env.HOOX_HOME?.trim();
150
+ if (override) {
151
+ return createHooxPath(resolve(override));
152
+ }
153
+ const home = homedir2();
154
+ if (!home || home.length === 0) {
155
+ return createHooxPath(resolve(process.cwd(), ".hoox"));
156
+ }
157
+ return createHooxPath(join2(home, ".hoox"));
158
+ } catch {
159
+ return createHooxPath(resolve(process.cwd(), ".hoox"));
160
+ }
161
+ }
162
+ function isHooxSetupRoot(dir) {
163
+ if (!dir)
164
+ return false;
165
+ try {
166
+ const root = resolve(dir);
167
+ if (!existsSync2(join2(root, "packages", "cli", "package.json"))) {
168
+ return false;
169
+ }
170
+ return existsSync2(join2(root, "wrangler.jsonc")) || existsSync2(join2(root, "wrangler.jsonc.example")) || existsSync2(join2(root, "workers")) || existsSync2(join2(root, ".gitmodules"));
171
+ } catch {
172
+ return false;
173
+ }
174
+ }
175
+ function getRememberedMonorepoPath() {
176
+ return resolveHooxPath("config/monorepo.json");
177
+ }
178
+ function getRememberedMonorepoRoot() {
179
+ try {
180
+ const path = getRememberedMonorepoPath();
181
+ if (!existsSync2(path))
182
+ return null;
183
+ const raw = readFileSync2(path, "utf-8");
184
+ const data = JSON.parse(raw);
185
+ if (!data.root || typeof data.root !== "string")
186
+ return null;
187
+ const resolved = resolve(data.root);
188
+ return isHooxSetupRoot(resolved) ? resolved : null;
189
+ } catch {
190
+ return null;
191
+ }
192
+ }
193
+ function rememberMonorepoRoot(root) {
194
+ try {
195
+ const resolved = resolve(root);
196
+ if (!isHooxSetupRoot(resolved))
197
+ return false;
198
+ const configDir = getHooxConfigDir();
199
+ mkdirSync2(configDir, { recursive: true, mode: 448 });
200
+ try {
201
+ chmodSync2(configDir, 448);
202
+ } catch {}
203
+ const payload = {
204
+ root: resolved,
205
+ updatedAt: new Date().toISOString()
206
+ };
207
+ const path = getRememberedMonorepoPath();
208
+ writeFileSync2(path, JSON.stringify(payload, null, 2) + `
209
+ `, {
210
+ mode: 384
211
+ });
212
+ try {
213
+ chmodSync2(path, 384);
214
+ } catch {}
215
+ return true;
216
+ } catch {
217
+ return false;
218
+ }
219
+ }
220
+ function findHooxSetupRoot(startDir = process.cwd()) {
221
+ let dir = resolve(startDir);
222
+ for (;; ) {
223
+ if (isHooxSetupRoot(dir))
224
+ return dir;
225
+ const parent = dirname(dir);
226
+ if (parent === dir)
227
+ return null;
228
+ dir = parent;
229
+ }
230
+ }
231
+ function resolveHooxRuntimeRoot(options) {
232
+ const env = options?.env ?? process.env;
233
+ const cwd = resolve(options?.cwd ?? process.cwd());
234
+ const globalRepo = getHooxRepoPath();
235
+ const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
236
+ const envRepo = env.HOOX_REPO?.trim();
237
+ if (envRepo) {
238
+ const resolved = resolve(envRepo);
239
+ if (isHooxSetupRoot(resolved)) {
240
+ return {
241
+ root: resolved,
242
+ source: "env",
243
+ checked: {
244
+ env: resolved,
245
+ cwd: findHooxSetupRoot(cwd),
246
+ remembered,
247
+ global: globalRepo
248
+ }
249
+ };
250
+ }
251
+ return {
252
+ root: null,
253
+ source: "env",
254
+ checked: {
255
+ env: resolved,
256
+ cwd: findHooxSetupRoot(cwd),
257
+ remembered,
258
+ global: globalRepo
259
+ }
260
+ };
261
+ }
262
+ const local = findHooxSetupRoot(cwd);
263
+ if (local) {
264
+ return {
265
+ root: local,
266
+ source: "cwd",
267
+ checked: { cwd: local, remembered, global: globalRepo }
268
+ };
269
+ }
270
+ if (remembered) {
271
+ return {
272
+ root: remembered,
273
+ source: "remembered",
274
+ checked: { cwd: null, remembered, global: globalRepo }
275
+ };
276
+ }
277
+ if (isHooxSetupRoot(globalRepo)) {
278
+ return {
279
+ root: globalRepo,
280
+ source: "global",
281
+ checked: { cwd: null, remembered: null, global: globalRepo }
282
+ };
283
+ }
284
+ return {
285
+ root: null,
286
+ source: "none",
287
+ checked: { cwd: null, remembered: null, global: globalRepo }
288
+ };
289
+ }
290
+ function getTuiEntryCandidates(runtimeRoot) {
291
+ const root = resolve(runtimeRoot);
292
+ return [
293
+ join2(root, "packages", "tui", "src", "main.tsx"),
294
+ join2(root, "packages", "tui", "dist", "main.js"),
295
+ join2(root, "packages", "tui", "src", "main.ts")
296
+ ];
297
+ }
298
+ function resolveHooxPath(relativePath) {
299
+ if (!relativePath || typeof relativePath !== "string") {
300
+ throw new Error("relativePath must be a non-empty string");
301
+ }
302
+ if (relativePath.includes("..")) {
303
+ throw new Error(`Path traversal detected in relativePath: "${relativePath}"`);
304
+ }
305
+ const normalizedPath = relativePath.replace(/\\/g, "/");
306
+ const hooxHome = getHooxHome();
307
+ const fullPath = join2(hooxHome, normalizedPath);
308
+ const resolvedPath = resolve(fullPath);
309
+ const resolvedHome = resolve(hooxHome);
310
+ if (!resolvedPath.startsWith(resolvedHome)) {
311
+ throw new Error(`Resolved path "${resolvedPath}" is outside Hoox home directory`);
312
+ }
313
+ return createHooxPath(resolvedPath);
314
+ }
315
+ function isWithinHooxHome(path) {
316
+ try {
317
+ const hooxHome = getHooxHome();
318
+ const resolvedPath = resolve(path);
319
+ const resolvedHome = resolve(hooxHome);
320
+ return resolvedPath.startsWith(resolvedHome);
321
+ } catch {
322
+ return false;
323
+ }
324
+ }
325
+ function getRelativeHooxPath(absolutePath) {
326
+ try {
327
+ if (!isWithinHooxHome(absolutePath)) {
328
+ return null;
329
+ }
330
+ const hooxHome = getHooxHome();
331
+ const resolvedPath = resolve(absolutePath);
332
+ const resolvedHome = resolve(hooxHome);
333
+ const relativePath = resolvedPath.slice(resolvedHome.length);
334
+ return relativePath.startsWith("/") || relativePath.startsWith("\\") ? relativePath.slice(1) : relativePath;
335
+ } catch {
336
+ return null;
337
+ }
338
+ }
339
+ function getHooxRepoPath() {
340
+ return resolveHooxPath("repo");
341
+ }
342
+ function getHooxConfigDir() {
343
+ return resolveHooxPath("config");
344
+ }
345
+ function getHooxDataDir() {
346
+ return resolveHooxPath("data");
347
+ }
348
+ function getHooxWranglerPath() {
349
+ return resolveHooxPath("config/wrangler.jsonc");
350
+ }
351
+ function getHooxStatePath() {
352
+ return resolveHooxPath("data/state.json");
353
+ }
354
+
134
355
  // src/stores/config-store.ts
135
356
  import { create } from "zustand";
136
357
  import { immer } from "zustand/middleware/immer";
137
358
  import { persist, createJSONStorage } from "zustand/middleware";
138
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
139
- import { homedir as homedir2 } from "os";
140
- import { join as join2 } from "path";
359
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
360
+ import { join as join3 } from "path";
361
+ function getTuiPreferencesPath() {
362
+ return join3(getHooxHome(), ".tui-state", "preferences.json");
363
+ }
364
+ function getLegacyConfigJsonPath() {
365
+ return join3(getHooxHome(), "config.json");
366
+ }
367
+ function extractZustandPrefsPayload(raw) {
368
+ try {
369
+ const parsed = JSON.parse(raw);
370
+ if (parsed && typeof parsed === "object" && parsed.state && typeof parsed.state === "object" && !Array.isArray(parsed.state) && (("theme" in parsed.state) || ("refreshIntervalMs" in parsed.state)) && !("apiToken" in parsed)) {
371
+ return raw;
372
+ }
373
+ } catch {}
374
+ return null;
375
+ }
141
376
  var bunConfigStorage = {
142
377
  getItem: async (_name) => {
143
378
  try {
144
- const file = Bun.file(join2(homedir2(), ".hoox", "config.json"));
145
- const exists = await file.exists();
146
- if (!exists)
147
- return null;
148
- return await file.text();
379
+ const prefsPath = getTuiPreferencesPath();
380
+ const prefsFile = Bun.file(prefsPath);
381
+ if (await prefsFile.exists()) {
382
+ return await prefsFile.text();
383
+ }
384
+ const legacyPath = getLegacyConfigJsonPath();
385
+ if (existsSync3(legacyPath)) {
386
+ const legacyRaw = readFileSync3(legacyPath, "utf-8");
387
+ const envelope = extractZustandPrefsPayload(legacyRaw);
388
+ if (envelope) {
389
+ await bunConfigStorage.setItem(_name, envelope);
390
+ return envelope;
391
+ }
392
+ }
393
+ return null;
149
394
  } catch {
150
395
  return null;
151
396
  }
152
397
  },
153
398
  setItem: async (_name, value) => {
154
- const dir = join2(homedir2(), ".hoox");
155
- if (!existsSync2(dir)) {
156
- mkdirSync2(dir, { recursive: true, mode: HOOX_DIR_MODE });
399
+ const home = getHooxHome();
400
+ const stateDir = join3(home, ".tui-state");
401
+ if (!existsSync3(home)) {
402
+ mkdirSync3(home, { recursive: true, mode: HOOX_DIR_MODE });
403
+ }
404
+ if (!existsSync3(stateDir)) {
405
+ mkdirSync3(stateDir, { recursive: true, mode: HOOX_DIR_MODE });
157
406
  }
158
407
  try {
159
- chmodSync2(dir, HOOX_DIR_MODE);
408
+ chmodSync3(home, HOOX_DIR_MODE);
409
+ chmodSync3(stateDir, HOOX_DIR_MODE);
160
410
  } catch {}
161
- const filePath = join2(dir, "config.json");
411
+ const filePath = getTuiPreferencesPath();
162
412
  await Bun.write(filePath, value);
163
413
  try {
164
- chmodSync2(filePath, HOOX_CONFIG_FILE_MODE);
414
+ chmodSync3(filePath, HOOX_CONFIG_FILE_MODE);
165
415
  } catch {}
166
416
  },
167
417
  removeItem: async (_name) => {}
@@ -233,7 +483,7 @@ var useConfigStore = create()(persist(immer((set) => ({
233
483
  state.notifications[channel] = !state.notifications[channel];
234
484
  })
235
485
  })), {
236
- name: "hoox-config",
486
+ name: "hoox-tui-prefs",
237
487
  storage: createJSONStorage(() => bunConfigStorage),
238
488
  partialize: (state) => ({
239
489
  theme: state.theme,
@@ -251,5 +501,6 @@ var useConfigStore = create()(persist(immer((set) => ({
251
501
  })
252
502
  }));
253
503
  export {
254
- useConfigStore
504
+ useConfigStore,
505
+ getTuiPreferencesPath
255
506
  };
@@ -41,6 +41,12 @@ interface ServiceActions {
41
41
  stopStreams: () => void;
42
42
  addAlert: (alert: Alert) => void;
43
43
  addAlerts: (alerts: Alert[]) => void;
44
+ /** Mark a single alert as acknowledged (UI triage). */
45
+ acknowledgeAlert: (id: string) => void;
46
+ /** Remove a single alert from the ring buffer. */
47
+ dismissAlert: (id: string) => void;
48
+ /** Clear the local log ring buffer (TUI display only). */
49
+ clearLogs: () => void;
44
50
  setConnectionStatus: (status: ConnectionStatus) => void;
45
51
  selectWorker: (id: string | null) => void;
46
52
  setWorkers: (workers: WorkerInfo[]) => void;
@@ -154,6 +160,9 @@ export declare const useServiceStore: import("zustand").UseBoundStore<Omit<impor
154
160
  stopStreams: () => void;
155
161
  addAlert: (alert: Alert) => void;
156
162
  addAlerts: (alerts: Alert[]) => void;
163
+ acknowledgeAlert: (id: string) => void;
164
+ dismissAlert: (id: string) => void;
165
+ clearLogs: () => void;
157
166
  setConnectionStatus: (status: ConnectionStatus) => void;
158
167
  selectWorker: (id: string | null) => void;
159
168
  setWorkers: (workers: WorkerInfo[]) => void;
@@ -247,6 +256,9 @@ export declare const useServiceStore: import("zustand").UseBoundStore<Omit<impor
247
256
  stopStreams: () => void;
248
257
  addAlert: (alert: Alert) => void;
249
258
  addAlerts: (alerts: Alert[]) => void;
259
+ acknowledgeAlert: (id: string) => void;
260
+ dismissAlert: (id: string) => void;
261
+ clearLogs: () => void;
250
262
  setConnectionStatus: (status: ConnectionStatus) => void;
251
263
  selectWorker: (id: string | null) => void;
252
264
  setWorkers: (workers: WorkerInfo[]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"service-store.d.ts","sourceRoot":"","sources":["../../src/stores/service-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service-store.d.ts","sourceRoot":"","sources":["../../src/stores/service-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+BH,OAAO,KAAK,EACV,UAAU,EACV,KAAK,EACL,KAAK,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,UAAU,CAAC;AAwClB,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,WAAW,EAAE,KAAK,EAAE,CAAC;IACrB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,sDAAsD;IACtD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAID,UAAU,cAAc;IACtB,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;;OAGG;IACH,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IACrC,uDAAuD;IACvD,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kDAAkD;IAClD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,0DAA0D;IAC1D,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,UAAU,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC5C,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACjC,UAAU,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAG7C,6DAA6D;IAC7D,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,gEAAgE;IAChE,uBAAuB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,0DAA0D;IAC1D,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,kDAAkD;IAClD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/D;;;;OAIG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CACtD;AA8ED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA3JR,gBAAgB;qBACrB,MAAM;0BACD,MAAM,GAAG,IAAI;oBAInB,MAAM;mBAEP,MAAM,GAAG,IAAI;;;;;;;;;;6BASH,MAAM;wBAEX,MAAM;wBAEN,MAAM,GAAG,IAAI;sBAMf,MAAM,OAAO,CAAC,IAAI,CAAC;sBACnB,MAAM,OAAO,CAAC,IAAI,CAAC;oBACrB,MAAM,OAAO,CAAC,IAAI,CAAC;qBAKlB,MAAM,IAAI;kBACb,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;mBACrB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI;0BAElB,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI;sBAExB,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI;mBAEvB,MAAM,IAAI;6BACA,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI;sBACzC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI;oBAC7B,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI;mBAChC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;iBACxB,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI;oBACpB,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;iCAInB,MAAM,IAAI;iCAEV,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI;sBAEzC,MAAM,IAAI;oBAEZ,MAAM,IAAI;6BAMD,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI;oBAMlD,MAAM,IAAI;0BAMJ,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA5ElC,gBAAgB;qBACrB,MAAM;0BACD,MAAM,GAAG,IAAI;oBAInB,MAAM;mBAEP,MAAM,GAAG,IAAI;;;;;;;;;;6BASH,MAAM;wBAEX,MAAM;wBAEN,MAAM,GAAG,IAAI;sBAMf,MAAM,OAAO,CAAC,IAAI,CAAC;sBACnB,MAAM,OAAO,CAAC,IAAI,CAAC;oBACrB,MAAM,OAAO,CAAC,IAAI,CAAC;qBAKlB,MAAM,IAAI;kBACb,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;mBACrB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI;0BAElB,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI;sBAExB,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI;mBAEvB,MAAM,IAAI;6BACA,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI;sBACzC,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI;oBAC7B,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI;mBAChC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;iBACxB,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI;oBACpB,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;iCAInB,MAAM,IAAI;iCAEV,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI;sBAEzC,MAAM,IAAI;oBAEZ,MAAM,IAAI;6BAMD,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI;oBAMlD,MAAM,IAAI;0BAMJ,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI;;EAkbrD,CAAC"}