@mandujs/core 0.53.0 → 0.53.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/package.json +38 -2
  2. package/src/a11y/run-audit.ts +6 -6
  3. package/src/brain/adapters/oauth-flow.ts +1 -1
  4. package/src/brain/architecture/analyzer.ts +0 -2
  5. package/src/brain/credentials.ts +2 -2
  6. package/src/bundler/__tests__/build-runner.ts +13 -1
  7. package/src/bundler/__tests__/extended-watch.test.ts +3 -2
  8. package/src/bundler/__tests__/fast-refresh.test.ts +10 -12
  9. package/src/bundler/build.test.ts +30 -33
  10. package/src/bundler/build.ts +2 -1
  11. package/src/bundler/dev.ts +23 -22
  12. package/src/bundler/prerender.ts +63 -0
  13. package/src/bundler/safe-build.test.ts +2 -1
  14. package/src/bundler/types.ts +5 -3
  15. package/src/change/history.ts +1 -1
  16. package/src/change/snapshot.ts +18 -9
  17. package/src/client/Link.tsx +9 -9
  18. package/src/client/globals.ts +3 -2
  19. package/src/client/hooks.ts +0 -4
  20. package/src/client/hydrate.ts +1 -1
  21. package/src/client/router.ts +12 -12
  22. package/src/client/rpc.ts +1 -1
  23. package/src/client/use-fetch.ts +6 -6
  24. package/src/client/use-sse.ts +5 -5
  25. package/src/config/mcp-status.ts +0 -1
  26. package/src/config/validate.ts +1 -1
  27. package/src/config/watcher.ts +1 -1
  28. package/src/content/collection.ts +8 -12
  29. package/src/content/content-layer.ts +5 -5
  30. package/src/content/data-store.ts +2 -2
  31. package/src/content/loader-context.ts +0 -1
  32. package/src/content/loaders/file.ts +1 -1
  33. package/src/content/loaders/glob.ts +4 -4
  34. package/src/content/loaders/types.ts +1 -1
  35. package/src/content/meta-store.ts +1 -1
  36. package/src/content/types.ts +1 -1
  37. package/src/contract/define.ts +11 -12
  38. package/src/contract/index.ts +3 -3
  39. package/src/contract/protection.ts +2 -2
  40. package/src/contract/types.ts +1 -1
  41. package/src/contract/validator.ts +0 -1
  42. package/src/db/__tests__/db.test.ts +4 -7
  43. package/src/db/migrations/index.ts +3 -0
  44. package/src/db/migrations/lock.ts +11 -11
  45. package/src/deploy/cache.ts +1 -0
  46. package/src/design/extract.ts +2 -1
  47. package/src/design/patch.ts +0 -1
  48. package/src/devtools/ai/mcp-connector.ts +24 -24
  49. package/src/devtools/client/components/kitchen-root.tsx +1 -1
  50. package/src/devtools/client/components/panel/errors-panel.tsx +1 -1
  51. package/src/devtools/client/state-manager.ts +1 -1
  52. package/src/devtools/init.ts +2 -3
  53. package/src/devtools/server/source-context.ts +1 -1
  54. package/src/devtools/worker/redaction-worker.ts +8 -4
  55. package/src/devtools/worker/worker-manager.ts +4 -3
  56. package/src/error/classifier.ts +1 -1
  57. package/src/error/domains.ts +1 -1
  58. package/src/filling/sse.ts +5 -5
  59. package/src/generator/generate.ts +2 -2
  60. package/src/guard/analyzer.ts +1 -1
  61. package/src/guard/ast-analyzer.ts +7 -7
  62. package/src/guard/auto-correct.ts +2 -2
  63. package/src/guard/config-guard.ts +0 -2
  64. package/src/guard/contract-guard.ts +1 -1
  65. package/src/guard/decision-memory.ts +2 -2
  66. package/src/guard/design-inline-class.ts +2 -1
  67. package/src/guard/graph.ts +1 -1
  68. package/src/guard/healing.ts +36 -41
  69. package/src/guard/negotiation.ts +3 -3
  70. package/src/guard/reporter.ts +1 -4
  71. package/src/guard/semantic-slots.ts +2 -2
  72. package/src/guard/suggestions.ts +2 -2
  73. package/src/guard/watcher.ts +5 -4
  74. package/src/index.ts +5 -5
  75. package/src/intent/index.ts +1 -1
  76. package/src/kitchen/api/contract-api.ts +1 -1
  77. package/src/kitchen/api/file-api.ts +3 -3
  78. package/src/kitchen/kitchen-handler.ts +29 -21
  79. package/src/lockfile/validate.ts +0 -1
  80. package/src/openapi/generator.ts +2 -1
  81. package/src/openapi/openapi.test.ts +43 -14
  82. package/src/perf/user-marks.ts +1 -1
  83. package/src/plugins/registry.ts +1 -2
  84. package/src/plugins/types.ts +1 -1
  85. package/src/resource/ddl/diff.ts +0 -1
  86. package/src/resource/generator.ts +1 -1
  87. package/src/resource/generators/contract.ts +1 -1
  88. package/src/resource/schema.ts +2 -1
  89. package/src/router/fs-routes.ts +6 -6
  90. package/src/router/fs-scanner.ts +1 -1
  91. package/src/runtime/env.ts +1 -1
  92. package/src/runtime/image-handler.ts +2 -1
  93. package/src/runtime/middleware.ts +2 -1
  94. package/src/runtime/server.ts +67 -60
  95. package/src/runtime/ssr.ts +3 -3
  96. package/src/runtime/streaming-ssr.ts +25 -27
  97. package/src/scheduler/validate.ts +1 -1
  98. package/src/seo/integration/ssr.ts +2 -3
  99. package/src/seo/render/opengraph.ts +1 -1
  100. package/src/seo/resolve/index.ts +0 -4
  101. package/src/slot/corrector.ts +1 -1
  102. package/src/slot/validator.ts +4 -4
  103. package/src/watcher/reporter.ts +1 -1
  104. package/src/watcher/watcher.ts +19 -19
@@ -7,10 +7,6 @@ import { useState, useEffect, useCallback, useMemo, useSyncExternalStore } from
7
7
  import {
8
8
  subscribe,
9
9
  getRouterState,
10
- getCurrentRoute,
11
- getLoaderData,
12
- getActionData,
13
- getNavigationState,
14
10
  navigate,
15
11
  submitAction,
16
12
  type RouteInfo,
@@ -110,7 +110,7 @@ function noopDispose(): Disposer {
110
110
  */
111
111
  function scheduleLoad(hydrate: () => void): Disposer {
112
112
  let cancelled = false;
113
- Promise.resolve().then(() => {
113
+ void Promise.resolve().then(() => {
114
114
  if (!cancelled) hydrate();
115
115
  });
116
116
  return () => {
@@ -3,7 +3,7 @@
3
3
  * SPA 스타일 네비게이션을 위한 클라이언트 라우터
4
4
  */
5
5
 
6
- import type { ReactNode } from "react";
6
+
7
7
  import { startTransition } from "react";
8
8
  import {
9
9
  getManduData,
@@ -404,12 +404,12 @@ export async function navigate(
404
404
  function handlePopState(event: PopStateEvent): void {
405
405
  const state = event.state;
406
406
 
407
- if (state?.routeId) {
408
- // Mandu로 방문한 페이지 - 데이터 다시 fetch
409
- navigate(window.location.pathname + window.location.search, {
410
- replace: true,
411
- scroll: false,
412
- });
407
+ if (state?.routeId) {
408
+ // Mandu로 방문한 페이지 - 데이터 다시 fetch
409
+ void navigate(window.location.pathname + window.location.search, {
410
+ replace: true,
411
+ scroll: false,
412
+ });
413
413
  } else {
414
414
  // SPA 네비게이션 이력이 아닌 페이지 — 현재 라우터 상태 유지
415
415
  // (getManduRoute()는 SSR 초기값이라 SPA 네비게이션 후에는 stale)
@@ -576,10 +576,10 @@ function handleLinkClick(event: MouseEvent): void {
576
576
  // All clear — prevent the default full-page navigation and hand off
577
577
  // to the client-side router. `href` preserves the user's original
578
578
  // string (relative paths, fragments, query strings) so the router
579
- // can normalize as needed.
580
- event.preventDefault();
581
- navigate(href);
582
- }
579
+ // can normalize as needed.
580
+ event.preventDefault();
581
+ void navigate(href);
582
+ }
583
583
 
584
584
  // ========== Prefetch ==========
585
585
 
@@ -702,7 +702,7 @@ export async function submitAction(
702
702
  actionData: nextActionData,
703
703
  loaderData: result._revalidated ? result.loaderData as unknown : undefined,
704
704
  };
705
- } catch (error) {
705
+ } catch {
706
706
  if (controller.signal.aborted) return { ok: false };
707
707
 
708
708
  setRouterStateInternal({
package/src/client/rpc.ts CHANGED
@@ -50,7 +50,7 @@ export interface RpcClientOptions {
50
50
  * const { id } = await api.post({ body: { title: "New" } });
51
51
  * ```
52
52
  */
53
- export function createClient<TContract = unknown>(
53
+ export function createClient<_TContract = unknown>(
54
54
  path: string,
55
55
  options?: RpcClientOptions
56
56
  ): RpcMethods {
@@ -228,12 +228,12 @@ export function useFetch<T = unknown>(
228
228
  }
229
229
  }, [url, method, stableQuery, stableHeaders, stableBody, cacheTime, cacheKey, transform]);
230
230
 
231
- useEffect(() => {
232
- if (!immediate) return;
233
- if (data && dedupe) return;
234
- fetchData();
235
- return () => { abortRef.current?.abort(); };
236
- }, [fetchData, immediate, dedupe]);
231
+ useEffect(() => {
232
+ if (!immediate) return;
233
+ if (data && dedupe) return;
234
+ void fetchData();
235
+ return () => { abortRef.current?.abort(); };
236
+ }, [fetchData, immediate, dedupe]);
237
237
 
238
238
  const mutate = useCallback((updater: T | ((prev: T | null) => T)) => {
239
239
  setData(prev => typeof updater === "function" ? (updater as (prev: T | null) => T)(prev) : updater);
@@ -210,7 +210,7 @@ export function useSSE(options: UseSSEOptions = {}): UseSSEReturn {
210
210
  }
211
211
 
212
212
  // Start reading in a properly-yielding async loop
213
- (async () => {
213
+ void (async () => {
214
214
  const reader = body.getReader();
215
215
  const decoder = new TextDecoder();
216
216
 
@@ -218,7 +218,7 @@ export function useSSE(options: UseSSEOptions = {}): UseSSEReturn {
218
218
  while (true) {
219
219
  // Check for abort
220
220
  if (controller.signal.aborted) {
221
- reader.cancel();
221
+ await reader.cancel();
222
222
  break;
223
223
  }
224
224
 
@@ -227,7 +227,7 @@ export function useSSE(options: UseSSEOptions = {}): UseSSEReturn {
227
227
 
228
228
  // Check for abort again (may have been aborted during read)
229
229
  if (controller.signal.aborted) {
230
- reader.cancel();
230
+ await reader.cancel();
231
231
  break;
232
232
  }
233
233
 
@@ -342,7 +342,7 @@ export async function readStreamWithYield(
342
342
  try {
343
343
  while (true) {
344
344
  if (signal?.aborted) {
345
- reader.cancel();
345
+ await reader.cancel();
346
346
  break;
347
347
  }
348
348
 
@@ -350,7 +350,7 @@ export async function readStreamWithYield(
350
350
  if (done) break;
351
351
 
352
352
  if (signal?.aborted) {
353
- reader.cancel();
353
+ await reader.cancel();
354
354
  break;
355
355
  }
356
356
 
@@ -7,7 +7,6 @@
7
7
  */
8
8
 
9
9
  import {
10
- MCP_SERVER_STATUS,
11
10
  type McpServerStatusMetadata,
12
11
  } from "./symbols.js";
13
12
 
@@ -15,7 +15,7 @@ import { isGuardRuleLike, type GuardRule as CustomGuardRule } from "../guard/def
15
15
  * Creates a schema that warns about unknown keys instead of failing
16
16
  * This provides the benefits of .strict() while maintaining compatibility
17
17
  */
18
- function strictWithWarnings<T extends z.ZodRawShape>(
18
+ function _strictWithWarnings<T extends z.ZodRawShape>(
19
19
  schema: z.ZodObject<T>,
20
20
  schemaName: string
21
21
  ): z.ZodEffects<z.ZodObject<T>> {
@@ -150,7 +150,7 @@ export async function watchConfig(
150
150
 
151
151
  debounceTimer = setTimeout(() => {
152
152
  debounceTimer = null;
153
- doReload(changedPath);
153
+ void doReload(changedPath);
154
154
  }, debounceMs);
155
155
  };
156
156
 
@@ -607,9 +607,8 @@ interface RenderedMarkdown {
607
607
  * remark/rehype plugin chain; when any piece is missing, falls back
608
608
  * to returning a `<pre>` shell so the caller gets a stable API.
609
609
  *
610
- * We go through `Function("return import(...)")` instead of a direct
611
- * dynamic `import()` so TS doesn't resolve the optional modules
612
- * during typecheck — they are NOT in `@mandujs/core` deps by design.
610
+ * We use a variable dynamic import so TS doesn't resolve the optional
611
+ * modules during typecheck they are NOT in `@mandujs/core` deps by design.
613
612
  *
614
613
  * The `options.remarkPlugins` / `options.rehypePlugins` arrays let
615
614
  * docs sites add `rehype-slug`, `rehype-autolink-headings`, `shiki`,
@@ -621,15 +620,12 @@ async function renderMarkdownSafe(
621
620
  ): Promise<RenderedMarkdown> {
622
621
  const { remarkPlugins = [], rehypePlugins = [], silent = false } = options;
623
622
 
624
- // Passing the module specifier through a Function-wrapped dynamic
625
- // import keeps TypeScript from erroring on optional peer deps; if
626
- // any module is missing we fall through to the raw-markdown path.
627
- const tryImport = async (id: string): Promise<unknown> => {
628
- try {
629
- return await (Function("x", "return import(x)") as (x: string) => Promise<unknown>)(id);
630
- } catch {
631
- return null;
632
- }
623
+ const tryImport = async (id: string): Promise<unknown> => {
624
+ try {
625
+ return await import(id);
626
+ } catch {
627
+ return null;
628
+ }
633
629
  };
634
630
 
635
631
  const unified = (await tryImport("unified")) as
@@ -253,11 +253,11 @@ export class ContentLayer {
253
253
  /**
254
254
  * 리소스 정리
255
255
  */
256
- dispose(): void {
257
- this.dataStore.dispose();
258
- this.watcher?.close();
259
- }
260
- }
256
+ dispose(): void {
257
+ this.dataStore.dispose();
258
+ void this.watcher?.close();
259
+ }
260
+ }
261
261
 
262
262
  /**
263
263
  * ContentLayer 팩토리
@@ -131,7 +131,7 @@ export class ContentDataStore {
131
131
  }
132
132
 
133
133
  this.saveTimer = setTimeout(() => {
134
- this.save();
134
+ void this.save();
135
135
  }, this.options.saveDebounce);
136
136
  }
137
137
  }
@@ -217,7 +217,7 @@ export class ContentDataStore {
217
217
 
218
218
  // 남은 변경사항 저장
219
219
  if (this.dirty && this.options.filePath) {
220
- this.save();
220
+ void this.save();
221
221
  }
222
222
  }
223
223
 
@@ -13,7 +13,6 @@ import type {
13
13
  ContentWatcher,
14
14
  ParseDataOptions,
15
15
  RenderedContent,
16
- ValidationError as ContentValidationError,
17
16
  } from "./types";
18
17
  import { ValidationError } from "./types";
19
18
  import { generateDigest } from "./digest";
@@ -98,7 +98,7 @@ export function file(options: FileLoaderOptions): Loader {
98
98
  name: "file",
99
99
 
100
100
  async load(context: LoaderContext): Promise<void> {
101
- const { store, config, logger, parseData, generateDigest } = context;
101
+ const { store, config, logger, parseData, generateDigest: _generateDigest } = context;
102
102
 
103
103
  // 절대 경로 계산
104
104
  const absolutePath = path.isAbsolute(filePath)
@@ -12,9 +12,9 @@
12
12
 
13
13
  import type { Loader, GlobLoaderOptions, ParsedMarkdown } from "./types";
14
14
  import type { LoaderContext, DataEntry } from "../types";
15
- import { LoaderError, ParseError } from "../types";
15
+ import { ParseError } from "../types";
16
16
  import { generateFileDigest, combineDigests } from "../digest";
17
- import { inferParser, MARKDOWN_EXTENSIONS } from "./types";
17
+ import { inferParser } from "./types";
18
18
  import * as fs from "fs";
19
19
  import * as path from "path";
20
20
 
@@ -108,7 +108,7 @@ export function glob(options: GlobLoaderOptions): Loader {
108
108
  name: "glob",
109
109
 
110
110
  async load(context: LoaderContext): Promise<void> {
111
- const { store, config, logger, parseData, renderMarkdown, watcher } = context;
111
+ const { store, config, logger, parseData: _parseData, renderMarkdown: _renderMarkdown, watcher } = context;
112
112
 
113
113
  // 기본 디렉토리
114
114
  const baseDir = base
@@ -181,7 +181,7 @@ async function processFile(
181
181
  context: LoaderContext,
182
182
  filePath: string,
183
183
  id: string,
184
- baseDir: string
184
+ _baseDir: string
185
185
  ): Promise<void> {
186
186
  const { store, parseData, renderMarkdown, logger } = context;
187
187
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import type { ZodSchema } from "zod";
8
- import type { LoaderContext, DataEntry, RenderedContent } from "../types";
8
+ import type { LoaderContext, RenderedContent } from "../types";
9
9
 
10
10
  /**
11
11
  * 로더 인터페이스
@@ -102,7 +102,7 @@ export class ContentMetaStore {
102
102
  */
103
103
  private autoSave(): void {
104
104
  if (this.options.autoSave && this.options.filePath) {
105
- this.save();
105
+ void this.save();
106
106
  }
107
107
  }
108
108
 
@@ -110,7 +110,7 @@ export interface LoaderContext {
110
110
  /**
111
111
  * parseData 옵션
112
112
  */
113
- export interface ParseDataOptions<T> {
113
+ export interface ParseDataOptions<_T> {
114
114
  /** 엔트리 ID */
115
115
  id: string;
116
116
  /** 원본 데이터 */
@@ -27,16 +27,15 @@
27
27
  * ```
28
28
  */
29
29
 
30
- import { z, type ZodType, type ZodObject, type ZodRawShape } from 'zod';
31
- import {
32
- getZodTypeName,
33
- getZodInnerType,
34
- getZodArrayElementType,
35
- getZodObjectShape,
36
- getZodEnumValues,
37
- getZodChecks,
38
- isZodRequired,
39
- } from './zod-utils';
30
+ import type { ZodType } from 'zod';
31
+ import {
32
+ getZodTypeName,
33
+ getZodInnerType,
34
+ getZodArrayElementType,
35
+ getZodObjectShape,
36
+ getZodEnumValues,
37
+ isZodRequired,
38
+ } from './zod-utils';
40
39
 
41
40
  // ============================================================================
42
41
  // Types
@@ -167,7 +166,7 @@ export function generateApiHandler<T extends ContractDefinition>(
167
166
  throw new Error(`Endpoint "${String(endpointName)}" not found in contract`);
168
167
  }
169
168
 
170
- const { method, path, input, output, description } = endpoint;
169
+ const { method, path, input, description } = endpoint;
171
170
 
172
171
  return `
173
172
  import { Mandu } from '@mandujs/core';
@@ -345,7 +344,7 @@ export function generateOpenAPISpec<T extends ContractDefinition>(
345
344
  const paths: Record<string, Record<string, unknown>> = {};
346
345
 
347
346
  for (const [name, endpoint] of Object.entries(contract.__endpoints)) {
348
- const { method, path, input, output, description, tags, errors } = endpoint;
347
+ const { method, path, input, description, tags, errors } = endpoint;
349
348
 
350
349
  if (!paths[path]) {
351
350
  paths[path] = {};
@@ -37,10 +37,10 @@ export {
37
37
  type RpcWireError,
38
38
  } from "./rpc";
39
39
 
40
- import type { ContractDefinition, ContractInstance, ContractSchema } from "./schema";
41
- import type { ContractHandlers, RouteDefinition } from "./handler";
40
+ import type { ContractDefinition, ContractInstance } from "./schema";
41
+
42
42
  import { defineHandler, defineRoute } from "./handler";
43
- import { createClient, contractFetch, type ClientOptions } from "./client";
43
+ import { createClient, contractFetch } from "./client";
44
44
  import { createClientContract } from "./client-safe";
45
45
 
46
46
  /**
@@ -102,7 +102,7 @@ export function extractProtectedFields(
102
102
  }
103
103
  // 민감 필드도 보호 대상
104
104
  else if (isSensitiveField(value)) {
105
- const meta = getMetadata(value, SENSITIVE_FIELD) as SensitiveFieldMetadata | undefined;
105
+ const _meta = getMetadata(value, SENSITIVE_FIELD) as SensitiveFieldMetadata | undefined;
106
106
  fields.push({
107
107
  path: currentPath,
108
108
  reason: "Sensitive field - redacted in logs",
@@ -187,7 +187,7 @@ export function extractContractProtectedFields(
187
187
  /**
188
188
  * 객체에서 경로로 값 가져오기
189
189
  */
190
- function getValueByPath(obj: unknown, path: string): unknown {
190
+ function _getValueByPath(obj: unknown, path: string): unknown {
191
191
  const parts = path.split(".");
192
192
  let current: unknown = obj;
193
193
 
@@ -14,7 +14,7 @@ import type {
14
14
  /**
15
15
  * Extract inferred type from Zod schema
16
16
  */
17
- type InferZod<T> = T extends z.ZodTypeAny ? z.infer<T> : never;
17
+ type _InferZod<T> = T extends z.ZodTypeAny ? z.infer<T> : never;
18
18
 
19
19
  /**
20
20
  * Extract inferred type from response schema (supports ResponseSchemaWithExamples)
@@ -19,7 +19,6 @@ import type {
19
19
  ContractValidationError,
20
20
  ContractValidationIssue,
21
21
  MethodRequestSchema,
22
- ContractNormalizeMode,
23
22
  ResponseSchemaWithExamples,
24
23
  } from "./schema";
25
24
  import {
@@ -107,13 +107,10 @@ function createFakeCtor(): { Ctor: BunSqlCtor; state: FakeState } {
107
107
  return Object.assign(call, methods);
108
108
  }
109
109
 
110
- class FakeBunSql {
111
- constructor(config: Record<string, unknown>) {
112
- state.ctorCalls.push(config);
113
- // Return the callable instance — NOT a class instance. Returning a
114
- // non-this value from a constructor replaces the default return.
115
- return makeFakeSqlInstance(false) as FakeBunSql;
116
- }
110
+ function FakeBunSql(config: Record<string, unknown>) {
111
+ state.ctorCalls.push(config);
112
+ // Return the callable instance — NOT the default constructed object.
113
+ return makeFakeSqlInstance(false);
117
114
  }
118
115
 
119
116
  return {
@@ -0,0 +1,3 @@
1
+ export * from "./history-table";
2
+ export * from "./lock";
3
+ export * from "./runner";
@@ -102,11 +102,11 @@ async function acquirePgAdvisoryLock(
102
102
  // hash-function reproduction.
103
103
  await db`SELECT pg_advisory_lock(hashtext(${lockId})::bigint)`;
104
104
 
105
- let released = false;
105
+ let _released = false;
106
106
  return {
107
107
  async release(): Promise<void> {
108
- if (released) return;
109
- released = true;
108
+ if (_released) return;
109
+ _released = true;
110
110
  try {
111
111
  await db`SELECT pg_advisory_unlock(hashtext(${lockId})::bigint)`;
112
112
  } catch (err) {
@@ -147,11 +147,11 @@ async function acquireMysqlLock(
147
147
  );
148
148
  }
149
149
 
150
- let released = false;
150
+ let _released = false;
151
151
  return {
152
152
  async release(): Promise<void> {
153
- if (released) return;
154
- released = true;
153
+ if (_released) return;
154
+ _released = true;
155
155
  try {
156
156
  await db`SELECT RELEASE_LOCK(${lockId})`;
157
157
  } catch (err) {
@@ -229,11 +229,11 @@ async function acquireSqliteImmediate(
229
229
  // Wait for the previous holder to release.
230
230
  await previous;
231
231
 
232
- let released = false;
232
+ let _released = false;
233
233
  return {
234
234
  async release(): Promise<void> {
235
- if (released) return;
236
- released = true;
235
+ if (_released) return;
236
+ _released = true;
237
237
  release();
238
238
  // If no one queued behind us, drop the entry so the registry
239
239
  // doesn't grow unbounded across many apply() cycles.
@@ -245,10 +245,10 @@ async function acquireSqliteImmediate(
245
245
  }
246
246
 
247
247
  function makeNoopLock(): MigrationLock {
248
- let released = false;
248
+ let _released = false;
249
249
  return {
250
250
  async release(): Promise<void> {
251
- released = true;
251
+ _released = true;
252
252
  },
253
253
  };
254
254
  }
@@ -107,6 +107,7 @@ export async function loadDeployIntentCache(
107
107
  } catch (err) {
108
108
  throw new Error(
109
109
  `Deploy intent cache is not valid JSON (${file}): ${(err as Error).message}`,
110
+ { cause: err },
110
111
  );
111
112
  }
112
113
  return DeployIntentCache.parse(parsed);
@@ -1,3 +1,4 @@
1
+ import type * as __ManduNodeFsTypes0 from "node:fs";
1
2
  /**
2
3
  * DESIGN.md token extractor — scan project source for tokens that
3
4
  * should be promoted into DESIGN.md (Issue #245 M4 §3.5 internal loop).
@@ -155,7 +156,7 @@ const SOURCE_RX = /\.(?:tsx?|jsx?|mdx?|css)$/;
155
156
  async function collectFiles(root: string): Promise<string[]> {
156
157
  const out: string[] = [];
157
158
  async function walk(dir: string): Promise<void> {
158
- let entries: import("node:fs").Dirent[];
159
+ let entries: __ManduNodeFsTypes0.Dirent[];
159
160
  try {
160
161
  entries = await fs.readdir(dir, { withFileTypes: true });
161
162
  } catch {
@@ -23,7 +23,6 @@
23
23
  * limitation or fall back to a hand-edit.
24
24
  */
25
25
 
26
- import { parseDesignMd } from "./parser";
27
26
 
28
27
  export type PatchableSection =
29
28
  | "color-palette"
@@ -165,26 +165,26 @@ export class MCPConnector {
165
165
  try {
166
166
  this.ws = new WebSocket(url);
167
167
 
168
- this.ws.onopen = () => {
169
- clearTimeout(timeout);
170
- this.setStatus('connected');
171
- this.reconnectAttempts = 0;
172
- resolve();
173
- };
174
-
175
- this.ws.onclose = () => {
176
- this.handleDisconnect();
177
- };
178
-
179
- this.ws.onerror = (event) => {
180
- clearTimeout(timeout);
181
- this.handleConnectionError(new Error('WebSocket error'));
182
- reject(new Error('WebSocket connection failed'));
183
- };
184
-
185
- this.ws.onmessage = (event) => {
186
- this.handleMessage(event.data);
187
- };
168
+ this.ws.addEventListener('open', () => {
169
+ clearTimeout(timeout);
170
+ this.setStatus('connected');
171
+ this.reconnectAttempts = 0;
172
+ resolve();
173
+ });
174
+
175
+ this.ws.addEventListener('close', () => {
176
+ this.handleDisconnect();
177
+ });
178
+
179
+ this.ws.addEventListener('error', () => {
180
+ clearTimeout(timeout);
181
+ this.handleConnectionError(new Error('WebSocket error'));
182
+ reject(new Error('WebSocket connection failed'));
183
+ });
184
+
185
+ this.ws.addEventListener('message', (event) => {
186
+ this.handleMessage(event.data);
187
+ });
188
188
  } catch (error) {
189
189
  clearTimeout(timeout);
190
190
  this.handleConnectionError(
@@ -210,10 +210,10 @@ export class MCPConnector {
210
210
  }
211
211
 
212
212
  // 대기 중인 요청 모두 reject
213
- for (const [id, pending] of this.pendingRequests) {
214
- clearTimeout(pending.timeout);
215
- pending.reject(new Error('Connection closed'));
216
- }
213
+ for (const [, pending] of this.pendingRequests) {
214
+ clearTimeout(pending.timeout);
215
+ pending.reject(new Error('Connection closed'));
216
+ }
217
217
  this.pendingRequests.clear();
218
218
 
219
219
  this.setStatus('disconnected');
@@ -7,7 +7,7 @@
7
7
 
8
8
  import React, { useEffect, useState, useCallback, useMemo } from 'react';
9
9
  import { createRoot, type Root } from 'react-dom/client';
10
- import type { NormalizedError, DevToolsConfig, IslandSnapshot, NetworkRequest, DevToolsGuardViolation } from '../../types';
10
+ import type { NormalizedError, DevToolsConfig } from '../../types';
11
11
  import { generateCSSVariables, testIds, zIndex } from '../../design-tokens';
12
12
  import { getStateManager, type KitchenState } from '../state-manager';
13
13
  import { getOrCreateHook } from '../../hook';
@@ -159,7 +159,7 @@ export interface ErrorsPanelProps {
159
159
  export function ErrorsPanel({
160
160
  errors,
161
161
  onErrorClick,
162
- onErrorIgnore,
162
+ onErrorIgnore: _onErrorIgnore,
163
163
  onClearAll,
164
164
  }: ErrorsPanelProps): React.ReactElement {
165
165
  const formatTime = useCallback((timestamp: number): string => {
@@ -257,7 +257,7 @@ export class KitchenStateManager {
257
257
  }
258
258
  }
259
259
 
260
- setIslandHydrated(id: string, time: number): void {
260
+ setIslandHydrated(id: string, _time: number): void {
261
261
  this.updateIsland(id, {
262
262
  status: 'hydrated',
263
263
  hydrateEndTime: Date.now(),
@@ -17,10 +17,9 @@ import {
17
17
  initializePersistence,
18
18
  destroyPersistence,
19
19
  getStateManager,
20
- getPersistenceManager,
21
20
  } from './client';
22
21
  import { initializeWorkerManager, destroyWorkerManager } from './worker';
23
- import { getContextBuilder, resetContextBuilder, getMCPConnector, destroyMCPConnector } from './ai';
22
+ import { getContextBuilder, resetContextBuilder, destroyMCPConnector } from './ai';
24
23
 
25
24
  // ============================================================================
26
25
  // Types
@@ -134,7 +133,7 @@ export function initManduKitchen(config: DevToolsConfig = {}): KitchenInstance {
134
133
  });
135
134
 
136
135
  // 6. v1.1: AI Context Builder 초기화
137
- const contextBuilder = getContextBuilder({ config });
136
+ const _contextBuilder = getContextBuilder({ config });
138
137
 
139
138
  // 7. UI 마운트
140
139
  mountKitchen(config);