@tienne/gestalt 0.87.0 → 0.88.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.
Files changed (96) hide show
  1. package/CLAUDE.md +6 -2
  2. package/dist/bin/gestalt-hook.d.ts +5 -0
  3. package/dist/bin/gestalt-hook.d.ts.map +1 -0
  4. package/dist/bin/gestalt-hook.js +51 -0
  5. package/dist/bin/gestalt-hook.js.map +1 -0
  6. package/dist/package.json +4 -3
  7. package/dist/plugin/skills/blast-radius/SKILL.md +11 -1
  8. package/dist/plugin/skills/diff-radius/SKILL.md +11 -0
  9. package/dist/schemas/gestalt.schema.json +19 -0
  10. package/dist/src/code-graph/cochange.d.ts +40 -0
  11. package/dist/src/code-graph/cochange.d.ts.map +1 -1
  12. package/dist/src/code-graph/cochange.js +88 -3
  13. package/dist/src/code-graph/cochange.js.map +1 -1
  14. package/dist/src/code-graph/engine.d.ts +35 -1
  15. package/dist/src/code-graph/engine.d.ts.map +1 -1
  16. package/dist/src/code-graph/engine.js +300 -55
  17. package/dist/src/code-graph/engine.js.map +1 -1
  18. package/dist/src/code-graph/freshness.d.ts +39 -0
  19. package/dist/src/code-graph/freshness.d.ts.map +1 -0
  20. package/dist/src/code-graph/freshness.js +93 -0
  21. package/dist/src/code-graph/freshness.js.map +1 -0
  22. package/dist/src/code-graph/hooks/background.d.ts +18 -0
  23. package/dist/src/code-graph/hooks/background.d.ts.map +1 -0
  24. package/dist/src/code-graph/hooks/background.js +55 -0
  25. package/dist/src/code-graph/hooks/background.js.map +1 -0
  26. package/dist/src/code-graph/hooks/pointers.d.ts +66 -0
  27. package/dist/src/code-graph/hooks/pointers.d.ts.map +1 -0
  28. package/dist/src/code-graph/hooks/pointers.js +292 -0
  29. package/dist/src/code-graph/hooks/pointers.js.map +1 -0
  30. package/dist/src/code-graph/hooks/rank.d.ts +36 -0
  31. package/dist/src/code-graph/hooks/rank.d.ts.map +1 -0
  32. package/dist/src/code-graph/hooks/rank.js +212 -0
  33. package/dist/src/code-graph/hooks/rank.js.map +1 -0
  34. package/dist/src/code-graph/hooks/run.d.ts +37 -0
  35. package/dist/src/code-graph/hooks/run.d.ts.map +1 -0
  36. package/dist/src/code-graph/hooks/run.js +324 -0
  37. package/dist/src/code-graph/hooks/run.js.map +1 -0
  38. package/dist/src/code-graph/hooks/settings.d.ts +11 -0
  39. package/dist/src/code-graph/hooks/settings.d.ts.map +1 -0
  40. package/dist/src/code-graph/hooks/settings.js +25 -0
  41. package/dist/src/code-graph/hooks/settings.js.map +1 -0
  42. package/dist/src/code-graph/hooks/state.d.ts +20 -0
  43. package/dist/src/code-graph/hooks/state.d.ts.map +1 -0
  44. package/dist/src/code-graph/hooks/state.js +73 -0
  45. package/dist/src/code-graph/hooks/state.js.map +1 -0
  46. package/dist/src/code-graph/index.d.ts +6 -2
  47. package/dist/src/code-graph/index.d.ts.map +1 -1
  48. package/dist/src/code-graph/index.js +3 -1
  49. package/dist/src/code-graph/index.js.map +1 -1
  50. package/dist/src/code-graph/ko-text.d.ts +39 -0
  51. package/dist/src/code-graph/ko-text.d.ts.map +1 -0
  52. package/dist/src/code-graph/ko-text.js +223 -0
  53. package/dist/src/code-graph/ko-text.js.map +1 -0
  54. package/dist/src/code-graph/lock.d.ts +30 -0
  55. package/dist/src/code-graph/lock.d.ts.map +1 -0
  56. package/dist/src/code-graph/lock.js +140 -0
  57. package/dist/src/code-graph/lock.js.map +1 -0
  58. package/dist/src/code-graph/plugins/typescript-skeleton.d.ts +7 -0
  59. package/dist/src/code-graph/plugins/typescript-skeleton.d.ts.map +1 -0
  60. package/dist/src/code-graph/plugins/typescript-skeleton.js +157 -0
  61. package/dist/src/code-graph/plugins/typescript-skeleton.js.map +1 -0
  62. package/dist/src/code-graph/plugins/typescript.d.ts.map +1 -1
  63. package/dist/src/code-graph/plugins/typescript.js +58 -0
  64. package/dist/src/code-graph/plugins/typescript.js.map +1 -1
  65. package/dist/src/code-graph/storage.d.ts +85 -0
  66. package/dist/src/code-graph/storage.d.ts.map +1 -1
  67. package/dist/src/code-graph/storage.js +318 -3
  68. package/dist/src/code-graph/storage.js.map +1 -1
  69. package/dist/src/code-graph/types.d.ts +66 -0
  70. package/dist/src/code-graph/types.d.ts.map +1 -1
  71. package/dist/src/core/config.d.ts +33 -0
  72. package/dist/src/core/config.d.ts.map +1 -1
  73. package/dist/src/core/config.js +14 -0
  74. package/dist/src/core/config.js.map +1 -1
  75. package/dist/src/core/hooks-env.d.ts +9 -0
  76. package/dist/src/core/hooks-env.d.ts.map +1 -0
  77. package/dist/src/core/hooks-env.js +16 -0
  78. package/dist/src/core/hooks-env.js.map +1 -0
  79. package/dist/src/mcp/schemas.d.ts +9 -3
  80. package/dist/src/mcp/schemas.d.ts.map +1 -1
  81. package/dist/src/mcp/schemas.js +19 -2
  82. package/dist/src/mcp/schemas.js.map +1 -1
  83. package/dist/src/mcp/server.d.ts.map +1 -1
  84. package/dist/src/mcp/server.js +21 -3
  85. package/dist/src/mcp/server.js.map +1 -1
  86. package/dist/src/mcp/tools/code-graph-passthrough.d.ts +6 -1
  87. package/dist/src/mcp/tools/code-graph-passthrough.d.ts.map +1 -1
  88. package/dist/src/mcp/tools/code-graph-passthrough.js +95 -6
  89. package/dist/src/mcp/tools/code-graph-passthrough.js.map +1 -1
  90. package/package.json +4 -3
  91. package/plugin/.codex-plugin/plugin.json +1 -1
  92. package/plugin/.mcp.json +1 -1
  93. package/plugin/mcp.json +1 -1
  94. package/plugin/skills/blast-radius/SKILL.md +11 -1
  95. package/plugin/skills/diff-radius/SKILL.md +11 -0
  96. package/schemas/gestalt.schema.json +19 -0
@@ -1,5 +1,73 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { extname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import { log } from '../../core/log.js';
2
- import { codeGraphEngine } from '../../code-graph/index.js';
5
+ import { codeGraphEngine, MAX_INLINE_PARSE } from '../../code-graph/index.js';
6
+ import { detachedRefreshSpawner, requestRefresh, } from '../../code-graph/hooks/background.js';
7
+ /** 같은 레포에 재색인 프로세스를 연달아 띄우지 않는 간격. 띄운 쪽이 락을 잡기 전 틈을 메운다 */
8
+ const REINDEX_REQUEST_INTERVAL_MS = 30_000;
9
+ /**
10
+ * 재색인을 맡길 프로세스. 훅이 백그라운드 갱신에 쓰는 엔트리를 `reindex`로 띄운다.
11
+ * dist에서는 dist/bin/gestalt-hook.js, tsx로 띄운 개발 서버에서는 bin/gestalt-hook.ts다.
12
+ */
13
+ function defaultReindexSpawner() {
14
+ const self = fileURLToPath(import.meta.url);
15
+ const entry = fileURLToPath(new URL(`../../../bin/gestalt-hook${extname(self)}`, import.meta.url));
16
+ if (!existsSync(entry))
17
+ return undefined;
18
+ return detachedRefreshSpawner(entry, 'reindex', process.execArgv);
19
+ }
20
+ let reindexSpawner = null;
21
+ /** 테스트가 재색인 프로세스 대신 끼워 넣는 자리. undefined를 주면 기본으로 돌아간다 */
22
+ export function setReindexSpawner(spawner) {
23
+ reindexSpawner = spawner ?? null;
24
+ }
25
+ /**
26
+ * 질의 전에 그래프를 디스크에 맞춘다. 입력 refresh:false나 GESTALT_NO_REFRESH=1이면 끈다.
27
+ * 실패해도 질의는 막지 않는다. 이전 그래프로라도 답하는 게 아예 못 답하는 것보다 낫다.
28
+ *
29
+ * 다시 파싱할 파일이 MAX_INLINE_PARSE를 넘으면(업그레이드 직후 옛 DB, 큰 브랜치 전환)
30
+ * 이전 그래프로 바로 답하고 재색인은 다른 프로세스에 넘긴다. 큰 레포에서는 콜드 빌드만큼
31
+ * 걸려서 그 자리에서 돌리면 질의가 그만큼 멈춘다.
32
+ */
33
+ async function refreshBeforeQuery(input) {
34
+ if (input.refresh === false || process.env['GESTALT_NO_REFRESH'] === '1') {
35
+ return { status: 'skipped', reason: 'disabled', durationMs: 0 };
36
+ }
37
+ try {
38
+ const freshness = await codeGraphEngine.refresh(input.repoRoot, {
39
+ maxInlineParse: MAX_INLINE_PARSE,
40
+ });
41
+ if (freshness.status === 'stale' && freshness.reason === 'reindex_pending') {
42
+ requestReindex(input.repoRoot);
43
+ }
44
+ return freshness;
45
+ }
46
+ catch (e) {
47
+ const message = e instanceof Error ? e.message : String(e);
48
+ log('code-graph refresh failed:', message);
49
+ return {
50
+ status: 'stale',
51
+ reason: 'refresh_failed',
52
+ message: `최신화 실패로 이전 그래프 기준 (${message})`,
53
+ durationMs: 0,
54
+ };
55
+ }
56
+ }
57
+ function requestReindex(repoRoot) {
58
+ try {
59
+ if (reindexSpawner === null)
60
+ reindexSpawner = defaultReindexSpawner();
61
+ if (!reindexSpawner) {
62
+ log('code-graph reindex skipped: gestalt-hook entry not found');
63
+ return;
64
+ }
65
+ requestRefresh(repoRoot, reindexSpawner, REINDEX_REQUEST_INTERVAL_MS);
66
+ }
67
+ catch (e) {
68
+ log('code-graph reindex request failed:', e instanceof Error ? e.message : String(e));
69
+ }
70
+ }
3
71
  /**
4
72
  * 임계 파라미터는 co_change 액션만의 것이 아니다. blast_radius와 diff_radius도
5
73
  * 같은 신호를 쓰므로 여기서 갈라놓으면 튜닝이 조회에만 먹는다.
@@ -49,21 +117,23 @@ export async function handleCodeGraphPassthrough(input) {
49
117
  };
50
118
  }
51
119
  case 'blast_radius': {
120
+ const freshness = await refreshBeforeQuery(input);
52
121
  const result = codeGraphEngine.blastRadius(repoRoot, {
53
122
  changedFiles: input.changedFiles,
54
123
  base: input.base,
55
124
  maxDepth: input.maxDepth,
56
125
  coChange: coChangeTuning(input),
57
126
  });
58
- return result;
127
+ return { ...result, freshness };
59
128
  }
60
129
  case 'diff_radius': {
130
+ const freshness = await refreshBeforeQuery(input);
61
131
  const result = codeGraphEngine.diffRadius(repoRoot, {
62
132
  mode: input.diffMode,
63
133
  maxDepth: input.maxDepth,
64
134
  coChange: coChangeTuning(input),
65
135
  });
66
- return result;
136
+ return { ...result, freshness };
67
137
  }
68
138
  case 'query': {
69
139
  if (!input.pattern) {
@@ -72,19 +142,38 @@ export async function handleCodeGraphPassthrough(input) {
72
142
  if (!input.target) {
73
143
  return { error: 'target is required for query action' };
74
144
  }
145
+ const freshness = await refreshBeforeQuery(input);
75
146
  const result = codeGraphEngine.query(repoRoot, input.pattern, input.target);
76
- return { nodes: result.nodes, edges: result.edges };
147
+ return { nodes: result.nodes, edges: result.edges, freshness };
77
148
  }
78
149
  case 'stats': {
150
+ const freshness = await refreshBeforeQuery(input);
79
151
  const result = codeGraphEngine.stats(repoRoot);
80
- return result;
152
+ return { ...result, freshness };
81
153
  }
82
154
  case 'co_change': {
155
+ const freshness = await refreshBeforeQuery(input);
83
156
  const result = codeGraphEngine.coChange(repoRoot, {
84
157
  target: input.target,
85
158
  ...coChangeTuning(input),
86
159
  });
87
- return result;
160
+ return { ...result, freshness };
161
+ }
162
+ case 'skeleton': {
163
+ if (!input.filePath) {
164
+ return { error: 'filePath is required for skeleton action' };
165
+ }
166
+ const freshness = await refreshBeforeQuery(input);
167
+ const result = codeGraphEngine.skeleton(repoRoot, input.filePath);
168
+ // 서버가 text를 그대로 응답 본문으로 쓴다. 첫 줄이 줄인 크기여야 해서다
169
+ const stale = freshness.status === 'stale' ? `\n(${freshness.message})` : '';
170
+ return {
171
+ text: result.text.replace('\n', `${stale}\n`),
172
+ source: result.source,
173
+ originalChars: result.originalChars,
174
+ skeletonChars: result.skeletonChars,
175
+ freshness,
176
+ };
88
177
  }
89
178
  case 'db_exists': {
90
179
  const exists = codeGraphEngine.dbExists(repoRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"code-graph-passthrough.js","sourceRoot":"","sources":["../../../../src/mcp/tools/code-graph-passthrough.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"code-graph-passthrough.js","sourceRoot":"","sources":["../../../../src/mcp/tools/code-graph-passthrough.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tienne/gestalt",
3
- "version": "0.87.0",
3
+ "version": "0.88.0",
4
4
  "description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,7 +17,8 @@
17
17
  "node": ">=22.0.0"
18
18
  },
19
19
  "bin": {
20
- "gestalt": "./dist/bin/gestalt.js"
20
+ "gestalt": "./dist/bin/gestalt.js",
21
+ "gestalt-hook": "./dist/bin/gestalt-hook.js"
21
22
  },
22
23
  "files": [
23
24
  "dist",
@@ -28,7 +29,7 @@
28
29
  "scripts": {
29
30
  "dev": "tsx bin/gestalt.ts",
30
31
  "build": "tsc -p tsconfig.build.json",
31
- "postbuild": "rm -rf dist/plugin && mkdir -p dist/plugin && cp -r plugin/agents plugin/role-agents plugin/review-agents plugin/personas plugin/skills dist/plugin/ && cp -r schemas dist/ && cp package.json dist/ && chmod +x dist/bin/gestalt.js && pnpm run verify:plugin && pnpm run verify:rules && pnpm run verify:rule-overlap && pnpm run verify:output-style",
32
+ "postbuild": "rm -rf dist/plugin && mkdir -p dist/plugin && cp -r plugin/agents plugin/role-agents plugin/review-agents plugin/personas plugin/skills dist/plugin/ && cp -r schemas dist/ && cp package.json dist/ && chmod +x dist/bin/gestalt.js dist/bin/gestalt-hook.js && pnpm run verify:plugin && pnpm run verify:rules && pnpm run verify:rule-overlap && pnpm run verify:output-style",
32
33
  "verify:plugin": "tsx scripts/verify-plugin-assets.ts",
33
34
  "prepublishOnly": "pnpm build",
34
35
  "test": "vitest run",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gestalt",
3
- "version": "0.87.0",
3
+ "version": "0.88.0",
4
4
  "description": "Gestalt psychology-driven AI development harness. Transforms scattered requirements into structured, validated specifications through interactive interviews.",
5
5
  "author": {
6
6
  "name": "tienne"
package/plugin/.mcp.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "gestalt": {
4
4
  "command": "npx",
5
- "args": ["-y", "@tienne/gestalt@0.87.0", "serve"],
5
+ "args": ["-y", "@tienne/gestalt@0.88.0", "serve"],
6
6
  "startup_timeout_sec": 180,
7
7
  "tool_timeout_sec": 900
8
8
  }
package/plugin/mcp.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "gestalt": {
4
4
  "command": "npx",
5
- "args": ["-y", "@tienne/gestalt@0.87.0", "serve"],
5
+ "args": ["-y", "@tienne/gestalt@0.88.0", "serve"],
6
6
  "startup_timeout_sec": 180,
7
7
  "tool_timeout_sec": 900
8
8
  }
@@ -68,6 +68,7 @@ outputs:
68
68
  - coChangeTotalMatched
69
69
  - riskScore
70
70
  - summary
71
+ - freshness
71
72
  ---
72
73
 
73
74
  # Blast Radius Skill
@@ -84,6 +85,8 @@ outputs:
84
85
  /build-graph
85
86
  ```
86
87
 
88
+ 한 번 빌드해두면 그 뒤는 손대지 않아도 됩니다. 질의하기 전에 그래프를 작업 트리에 맞추므로 커밋 안 한 변경까지 반영된 그래프로 답합니다. 그래프 DB가 아예 없으면 자동으로 만들지 않으니 그때만 `/build-graph`를 돌립니다.
89
+
87
90
  ## 실행 방법
88
91
 
89
92
  ### 기본 (마지막 커밋 변경 파일 자동 감지)
@@ -131,6 +134,7 @@ ges_code_graph {
131
134
  | `depthExhausted` | `maxDepth`에 걸려 탐색이 멈췄고 갈 곳이 남아 있었다 |
132
135
  | `unexploredNodes` | 그때 다음 홉에서 기다리던 노드 수 |
133
136
  | `summary` | 한 줄 요약 |
137
+ | `freshness` | 질의 전 최신화 결과. `status`가 `fresh`(바뀐 것 없음), `refreshed`(반영하고 답함), `stale`(이전 그래프로 답함), `skipped`(DB가 없거나 최신화를 끔) 중 하나 |
134
138
 
135
139
  ### `rankedFiles`의 출처 표시
136
140
 
@@ -184,6 +188,13 @@ ges_code_graph {
184
188
  레포 최상위에서 /build-graph를 다시 돌리면 함께 바뀐 파일까지 잡습니다.
185
189
  ```
186
190
 
191
+ `freshness.status`가 `stale`이면 결과 표시 위에 안내를 붙입니다. 결과는 나오지만 최근에 고친 파일이 빠져 있을 수 있습니다.
192
+
193
+ ```
194
+ ⚠️ 이전 그래프 기준으로 본 결과입니다 ({freshness.message}).
195
+ 최근에 고친 파일은 빠져 있을 수 있습니다. 잠시 뒤 다시 부르면 그때 다시 맞춥니다.
196
+ ```
197
+
187
198
  `depthExhausted: true`면 위 표시 바로 아래에 한 줄을 덧붙입니다. 빠뜨리지 않습니다.
188
199
 
189
200
  ```
@@ -225,4 +236,3 @@ ges_code_graph {
225
236
  ```
226
237
 
227
238
  돌아온 순서대로 사용자에게 제시합니다. 스폰이 그 별칭을 거부하면 `sonnet`으로 1회 재시도합니다. 그것도 안 되면 기존 방식(테스트 파일 우선)으로 진행합니다. 폴백 절차는 [`../_shared/agent-model.md`](../_shared/agent-model.md)와 같습니다.
228
- 6. 빌드된 그래프가 오래된 경우 `/build-graph --incremental` 실행을 권장합니다.
@@ -54,6 +54,7 @@ outputs:
54
54
  - coChangeTotalMatched
55
55
  - riskScore
56
56
  - summary
57
+ - freshness
57
58
  ---
58
59
 
59
60
  # Diff Radius Skill
@@ -70,6 +71,8 @@ outputs:
70
71
  /build-graph
71
72
  ```
72
73
 
74
+ 한 번 빌드해두면 그 뒤는 손대지 않아도 됩니다. 질의하기 전에 그래프를 작업 트리에 맞추므로 커밋 안 한 변경까지 반영된 그래프로 답합니다. 그래프 DB가 아예 없으면 자동으로 만들지 않으니 그때만 `/build-graph`를 돌립니다.
75
+
73
76
  ## 실행 방법
74
77
 
75
78
  ### 기본 (staged + unstaged 전체)
@@ -123,6 +126,7 @@ ges_code_graph {
123
126
  | `coChangeTotalMatched` | 임계를 통과한 이력 이웃 수. `coChangeMatchedCapped`가 꺼져 있으면 하한이 아니라 정확한 수다 |
124
127
  | `riskScore` | 위험도 점수 0~1 |
125
128
  | `summary` | 한 줄 요약 |
129
+ | `freshness` | 질의 전 최신화 결과. `status`가 `fresh`(바뀐 것 없음), `refreshed`(반영하고 답함), `stale`(이전 그래프로 답함), `skipped`(DB가 없거나 최신화를 끔) 중 하나 |
126
130
 
127
131
  `rankedFiles` 각 항목의 `origin`은 `both`(import와 이력 양쪽), `history`(이력 전용), `import`(import 전용) 셋이다. `history`는 매니페스트끼리의 약속이나 코드와 그 문서처럼 서로 import하지 않아 파싱으로는 영영 안 잡히는 관계다. 커밋 직전에 "이것도 같이 고쳐야 하지 않나"를 잡아주는 자리라 이 스킬에서 특히 쓸모가 있다.
128
132
 
@@ -162,6 +166,13 @@ ges_code_graph {
162
166
  레포 최상위에서 /build-graph를 다시 돌리면 함께 바뀐 파일까지 잡습니다.
163
167
  ```
164
168
 
169
+ `freshness.status`가 `stale`이면 결과 표시 위에 안내를 붙입니다. 결과는 나오지만 최근에 고친 파일이 빠져 있을 수 있습니다.
170
+
171
+ ```
172
+ ⚠️ 이전 그래프 기준으로 본 결과입니다 ({freshness.message}).
173
+ 최근에 고친 파일은 빠져 있을 수 있습니다. 잠시 뒤 다시 부르면 그때 다시 맞춥니다.
174
+ ```
175
+
165
176
  `depthExhausted: true`면 위 표시 바로 아래에 한 줄을 덧붙입니다. 빠뜨리지 않습니다.
166
177
 
167
178
  ```
@@ -148,6 +148,25 @@
148
148
  "description": "Enable OS desktop notifications for pipeline events (env: GESTALT_NOTIFICATIONS)",
149
149
  "default": false
150
150
  },
151
+ "codeGraph": {
152
+ "type": "object",
153
+ "description": "Code knowledge graph settings",
154
+ "properties": {
155
+ "hooks": {
156
+ "type": "object",
157
+ "description": "Claude Code plugin hooks that inject code graph pointers into the session. Claude Code only",
158
+ "properties": {
159
+ "enabled": {
160
+ "type": "boolean",
161
+ "description": "Inject a repo map at session start, related file pointers per prompt, and impact plus co-change after edits. Off by default because plugin hooks run in every repo (env: GESTALT_CODE_GRAPH_HOOKS=1|0)",
162
+ "default": false
163
+ }
164
+ },
165
+ "additionalProperties": false
166
+ }
167
+ },
168
+ "additionalProperties": false
169
+ },
151
170
  "logLevel": {
152
171
  "type": "string",
153
172
  "enum": ["debug", "info", "warn", "error"],