@mandujs/core 0.54.10 → 0.54.12

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 (67) hide show
  1. package/package.json +1 -1
  2. package/scripts/postinstall-lock.ts +153 -153
  3. package/src/a11y/run-audit.ts +15 -15
  4. package/src/agent/__tests__/context.test.ts +17 -65
  5. package/src/agent/context.ts +535 -535
  6. package/src/agent/index.ts +6 -6
  7. package/src/agent/plan.ts +282 -282
  8. package/src/agent/repair.ts +171 -171
  9. package/src/agent/sync.ts +200 -200
  10. package/src/agent/types.ts +10 -18
  11. package/src/agent/verify.ts +17 -115
  12. package/src/brain/doctor/analyzer.ts +7 -7
  13. package/src/bundler/__tests__/build-runner.ts +81 -62
  14. package/src/bundler/__tests__/cold-start.test.ts +60 -60
  15. package/src/bundler/__tests__/css.test.ts +20 -20
  16. package/src/bundler/analyzer.ts +15 -15
  17. package/src/bundler/build.test.ts +130 -83
  18. package/src/bundler/build.ts +570 -524
  19. package/src/bundler/css.ts +42 -42
  20. package/src/bundler/manifest-schema.ts +21 -21
  21. package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +13 -13
  22. package/src/bundler/plugins/block-generated-imports.ts +13 -13
  23. package/src/bundler/types.ts +31 -31
  24. package/src/client/island.ts +79 -79
  25. package/src/config/validate.ts +1 -1
  26. package/src/deploy/inference/context.ts +82 -82
  27. package/src/devtools/client/components/panel/islands-panel.tsx +16 -16
  28. package/src/devtools/client/components/panel/panel-container.tsx +1 -1
  29. package/src/error/formatter.ts +22 -31
  30. package/src/filling/context.ts +17 -17
  31. package/src/generator/generate.ts +30 -30
  32. package/src/generator/index.ts +3 -3
  33. package/src/generator/templates.test.ts +66 -65
  34. package/src/generator/templates.ts +210 -210
  35. package/src/guard/check.ts +9 -9
  36. package/src/guard/config-guard.ts +13 -13
  37. package/src/guard/fs-routes-policy.ts +51 -51
  38. package/src/guard/index.ts +11 -11
  39. package/src/index.ts +3 -3
  40. package/src/kitchen/api/file-api.ts +11 -11
  41. package/src/report/index.ts +1 -1
  42. package/src/resource/__tests__/generator.test.ts +6 -6
  43. package/src/resource/__tests__/schema.test.ts +14 -14
  44. package/src/resource/ddl/__tests__/emit.test.ts +165 -165
  45. package/src/resource/ddl/emit.ts +146 -146
  46. package/src/resource/generator-schema.ts +11 -11
  47. package/src/resource/generators/slot.ts +72 -72
  48. package/src/resource/schema.ts +21 -21
  49. package/src/router/client-entry.test.ts +192 -140
  50. package/src/router/client-entry.ts +516 -486
  51. package/src/router/fs-routes.ts +16 -16
  52. package/src/router/fs-scanner.ts +16 -28
  53. package/src/runtime/__tests__/devtools-adapter.test.ts +68 -68
  54. package/src/runtime/__tests__/observability-lifecycle.test.ts +103 -103
  55. package/src/runtime/__tests__/page-render-response.test.ts +103 -103
  56. package/src/runtime/__tests__/request-middleware.test.ts +70 -70
  57. package/src/runtime/devtools-adapter.ts +68 -68
  58. package/src/runtime/escape.ts +34 -34
  59. package/src/runtime/observability-lifecycle.ts +290 -290
  60. package/src/runtime/page-render-response.ts +106 -106
  61. package/src/runtime/request-middleware.ts +31 -31
  62. package/src/runtime/server.ts +243 -243
  63. package/src/runtime/ssr.ts +59 -59
  64. package/src/runtime/static-files.ts +289 -289
  65. package/src/runtime/streaming-ssr.ts +22 -22
  66. package/src/watcher/__tests__/watcher.test.ts +59 -59
  67. package/src/watcher/watcher.ts +61 -61
package/src/agent/sync.ts CHANGED
@@ -1,200 +1,200 @@
1
- import fs from "fs/promises";
2
- import path from "path";
3
- import type {
4
- AgentSuggestedCommand,
5
- AgentSyncFile,
6
- AgentSyncReport,
7
- AgentSyncTarget,
8
- BuildAgentSyncOptions,
9
- } from "./types";
10
-
11
- const SYNC_ROOT = path.join(".mandu", "agent-sync");
12
- const TARGETS = ["codex", "claude", "gemini"] as const;
13
- type ConcreteTarget = (typeof TARGETS)[number];
14
-
15
- function toPosix(value: string): string {
16
- return value.split(path.sep).join("/");
17
- }
18
-
19
- function isTarget(value: string | undefined): value is AgentSyncTarget {
20
- return value === "codex" || value === "claude" || value === "gemini" || value === "all";
21
- }
22
-
23
- function concreteTargets(target: AgentSyncTarget): ConcreteTarget[] {
24
- return target === "all" ? [...TARGETS] : [target];
25
- }
26
-
27
- function targetFile(target: ConcreteTarget): string {
28
- if (target === "codex") return path.join(SYNC_ROOT, "codex", "AGENTS.md");
29
- if (target === "claude") return path.join(SYNC_ROOT, "claude", "CLAUDE.md");
30
- return path.join(SYNC_ROOT, "gemini", "GEMINI.md");
31
- }
32
-
33
- function renderInstructions(target: ConcreteTarget): string {
34
- const title =
35
- target === "codex"
36
- ? "Codex"
37
- : target === "claude"
38
- ? "Claude Code"
39
- : "Gemini CLI";
40
- return [
41
- `# Mandu Agent Workflow for ${title}`,
42
- "",
43
- "Mandu is an agent-native fullstack framework. Use the official agent surface before direct source edits.",
44
- "",
45
- "## Canonical Loop",
46
- "",
47
- "```text",
48
- "context -> plan -> apply -> verify -> repair",
49
- "```",
50
- "",
51
- "## Required First Choices",
52
- "",
53
- "1. Start with `mandu.agent.context` or `mandu agent context --json`.",
54
- "2. Create a plan with `mandu.agent.plan` or `mandu agent plan \"<task>\" --json --write`.",
55
- "3. Prefer `mandu.agent.apply` and domain MCP tools before direct file edits.",
56
- "4. End code-changing work with `mandu.agent.verify` or `mandu agent verify --changed --json --write`.",
57
- "5. If verification fails, run `mandu.agent.repair` or `mandu agent repair --from .mandu/agent-verify.json --json`, then verify again.",
58
- "",
59
- "## MCP Profile",
60
- "",
61
- "Use the reduced default profile:",
62
- "",
63
- "```bash",
64
- "MANDU_MCP_PROFILE=agent-core",
65
- "```",
66
- "",
67
- "Escalate to `agent-full` only when the plan selects route, API, slot, hydration, contract, guard, testing, or lint domains. Use `internal` only for framework maintenance.",
68
- "",
69
- "## Domain Skill Escalation",
70
- "",
71
- "- route/api: `mandu-fs-routes`",
72
- "- hydration/island/partial: `mandu-hydration`",
73
- "- slot/filling: `mandu-slot`",
74
- "- guard/import boundary: `mandu-guard`",
75
- "- test/e2e/ATE: `mandu-testing`",
76
- "- deploy: `mandu-deployment`",
77
- "- security/auth/session: `mandu-security`",
78
- "- styling/ui/design: `mandu-styling`, `mandu-ui`, `mandu-composition`",
79
- "",
80
- "Domain skills are addenda. They do not replace the canonical loop.",
81
- "",
82
- ].join("\n");
83
- }
84
-
85
- function renderClaudeSkill(): string {
86
- return [
87
- "---",
88
- "name: mandu-agent-workflow",
89
- "description: Canonical context -> plan -> apply -> verify -> repair workflow for Mandu projects.",
90
- "---",
91
- "",
92
- "# Mandu Agent Workflow",
93
- "",
94
- "Use this skill first in Mandu projects. Follow `context -> plan -> apply -> verify -> repair`.",
95
- "",
96
- "Preferred tools: `mandu.agent.context`, `mandu.agent.plan`, `mandu.agent.apply`, `mandu.agent.verify`, `mandu.agent.repair`.",
97
- "",
98
- "CLI fallback:",
99
- "",
100
- "```bash",
101
- "mandu agent context --json",
102
- "mandu agent plan \"<task>\" --json --write",
103
- "mandu agent apply --from .mandu/agent-plan.json --json",
104
- "mandu agent verify --changed --json --write",
105
- "mandu agent repair --from .mandu/agent-verify.json --json",
106
- "```",
107
- "",
108
- ].join("\n");
109
- }
110
-
111
- function syncEntries(target: ConcreteTarget): Array<{ target: ConcreteTarget; relPath: string; content: string }> {
112
- const entries = [
113
- {
114
- target,
115
- relPath: targetFile(target),
116
- content: renderInstructions(target),
117
- },
118
- ];
119
- if (target === "claude") {
120
- entries.push({
121
- target,
122
- relPath: path.join(SYNC_ROOT, "claude", "skills", "mandu-agent-workflow", "SKILL.md"),
123
- content: renderClaudeSkill(),
124
- });
125
- }
126
- return entries;
127
- }
128
-
129
- async function writeEntry(
130
- rootDir: string,
131
- entry: { target: ConcreteTarget; relPath: string; content: string },
132
- dryRun: boolean,
133
- ): Promise<AgentSyncFile> {
134
- const absPath = path.join(rootDir, entry.relPath);
135
- let action: AgentSyncFile["action"] = "created";
136
- try {
137
- const existing = await fs.readFile(absPath, "utf8");
138
- action = existing === entry.content ? "unchanged" : "updated";
139
- } catch {
140
- action = "created";
141
- }
142
-
143
- if (dryRun) {
144
- action = "planned";
145
- } else if (action !== "unchanged") {
146
- await fs.mkdir(path.dirname(absPath), { recursive: true });
147
- await fs.writeFile(absPath, entry.content, "utf8");
148
- }
149
-
150
- return {
151
- target: entry.target,
152
- path: toPosix(entry.relPath),
153
- action,
154
- bytes: Buffer.byteLength(entry.content, "utf8"),
155
- };
156
- }
157
-
158
- function nextCommands(): AgentSuggestedCommand[] {
159
- return [
160
- {
161
- command: "mandu agent context --json",
162
- reason: "Confirm the generated workflow matches the current project state.",
163
- required: true,
164
- },
165
- {
166
- command: "MANDU_MCP_PROFILE=agent-core",
167
- reason: "Use the reduced default MCP exposure for coding agents.",
168
- required: true,
169
- },
170
- ];
171
- }
172
-
173
- export async function buildAgentSyncReport(
174
- rootDir: string = process.cwd(),
175
- options: BuildAgentSyncOptions = {},
176
- ): Promise<AgentSyncReport> {
177
- const target = isTarget(options.target) ? options.target : "all";
178
- const dryRun = options.dryRun === true;
179
- const root = path.resolve(rootDir);
180
- const files: AgentSyncFile[] = [];
181
-
182
- for (const concrete of concreteTargets(target)) {
183
- for (const entry of syncEntries(concrete)) {
184
- files.push(await writeEntry(root, entry, dryRun));
185
- }
186
- }
187
-
188
- return {
189
- schemaVersion: 1,
190
- framework: "mandu",
191
- generatedAt: new Date().toISOString(),
192
- ok: true,
193
- target,
194
- profile: "agent-core",
195
- workflow: ["context", "plan", "apply", "verify", "repair"],
196
- files,
197
- warnings: dryRun ? ["Dry-run only. No files were written."] : [],
198
- nextCommands: nextCommands(),
199
- };
200
- }
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import type {
4
+ AgentSuggestedCommand,
5
+ AgentSyncFile,
6
+ AgentSyncReport,
7
+ AgentSyncTarget,
8
+ BuildAgentSyncOptions,
9
+ } from "./types";
10
+
11
+ const SYNC_ROOT = path.join(".mandu", "agent-sync");
12
+ const TARGETS = ["codex", "claude", "gemini"] as const;
13
+ type ConcreteTarget = (typeof TARGETS)[number];
14
+
15
+ function toPosix(value: string): string {
16
+ return value.split(path.sep).join("/");
17
+ }
18
+
19
+ function isTarget(value: string | undefined): value is AgentSyncTarget {
20
+ return value === "codex" || value === "claude" || value === "gemini" || value === "all";
21
+ }
22
+
23
+ function concreteTargets(target: AgentSyncTarget): ConcreteTarget[] {
24
+ return target === "all" ? [...TARGETS] : [target];
25
+ }
26
+
27
+ function targetFile(target: ConcreteTarget): string {
28
+ if (target === "codex") return path.join(SYNC_ROOT, "codex", "AGENTS.md");
29
+ if (target === "claude") return path.join(SYNC_ROOT, "claude", "CLAUDE.md");
30
+ return path.join(SYNC_ROOT, "gemini", "GEMINI.md");
31
+ }
32
+
33
+ function renderInstructions(target: ConcreteTarget): string {
34
+ const title =
35
+ target === "codex"
36
+ ? "Codex"
37
+ : target === "claude"
38
+ ? "Claude Code"
39
+ : "Gemini CLI";
40
+ return [
41
+ `# Mandu Agent Workflow for ${title}`,
42
+ "",
43
+ "Mandu is an agent-native fullstack framework. Use the official agent surface before direct source edits.",
44
+ "",
45
+ "## Canonical Loop",
46
+ "",
47
+ "```text",
48
+ "context -> plan -> apply -> verify -> repair",
49
+ "```",
50
+ "",
51
+ "## Required First Choices",
52
+ "",
53
+ "1. Start with `mandu.agent.context` or `mandu agent context --json`.",
54
+ "2. Create a plan with `mandu.agent.plan` or `mandu agent plan \"<task>\" --json --write`.",
55
+ "3. Prefer `mandu.agent.apply` and domain MCP tools before direct file edits.",
56
+ "4. End code-changing work with `mandu.agent.verify` or `mandu agent verify --changed --json --write`.",
57
+ "5. If verification fails, run `mandu.agent.repair` or `mandu agent repair --from .mandu/agent-verify.json --json`, then verify again.",
58
+ "",
59
+ "## MCP Profile",
60
+ "",
61
+ "Use the reduced default profile:",
62
+ "",
63
+ "```bash",
64
+ "MANDU_MCP_PROFILE=agent-core",
65
+ "```",
66
+ "",
67
+ "Escalate to `agent-full` only when the plan selects route, API, slot, hydration, contract, guard, testing, or lint domains. Use `internal` only for framework maintenance.",
68
+ "",
69
+ "## Domain Skill Escalation",
70
+ "",
71
+ "- route/api: `mandu-fs-routes`",
72
+ "- hydration/island/partial: `mandu-hydration`",
73
+ "- slot/filling: `mandu-slot`",
74
+ "- guard/import boundary: `mandu-guard`",
75
+ "- test/e2e/ATE: `mandu-testing`",
76
+ "- deploy: `mandu-deployment`",
77
+ "- security/auth/session: `mandu-security`",
78
+ "- styling/ui/design: `mandu-styling`, `mandu-ui`, `mandu-composition`",
79
+ "",
80
+ "Domain skills are addenda. They do not replace the canonical loop.",
81
+ "",
82
+ ].join("\n");
83
+ }
84
+
85
+ function renderClaudeSkill(): string {
86
+ return [
87
+ "---",
88
+ "name: mandu-agent-workflow",
89
+ "description: Canonical context -> plan -> apply -> verify -> repair workflow for Mandu projects.",
90
+ "---",
91
+ "",
92
+ "# Mandu Agent Workflow",
93
+ "",
94
+ "Use this skill first in Mandu projects. Follow `context -> plan -> apply -> verify -> repair`.",
95
+ "",
96
+ "Preferred tools: `mandu.agent.context`, `mandu.agent.plan`, `mandu.agent.apply`, `mandu.agent.verify`, `mandu.agent.repair`.",
97
+ "",
98
+ "CLI fallback:",
99
+ "",
100
+ "```bash",
101
+ "mandu agent context --json",
102
+ "mandu agent plan \"<task>\" --json --write",
103
+ "mandu agent apply --from .mandu/agent-plan.json --json",
104
+ "mandu agent verify --changed --json --write",
105
+ "mandu agent repair --from .mandu/agent-verify.json --json",
106
+ "```",
107
+ "",
108
+ ].join("\n");
109
+ }
110
+
111
+ function syncEntries(target: ConcreteTarget): Array<{ target: ConcreteTarget; relPath: string; content: string }> {
112
+ const entries = [
113
+ {
114
+ target,
115
+ relPath: targetFile(target),
116
+ content: renderInstructions(target),
117
+ },
118
+ ];
119
+ if (target === "claude") {
120
+ entries.push({
121
+ target,
122
+ relPath: path.join(SYNC_ROOT, "claude", "skills", "mandu-agent-workflow", "SKILL.md"),
123
+ content: renderClaudeSkill(),
124
+ });
125
+ }
126
+ return entries;
127
+ }
128
+
129
+ async function writeEntry(
130
+ rootDir: string,
131
+ entry: { target: ConcreteTarget; relPath: string; content: string },
132
+ dryRun: boolean,
133
+ ): Promise<AgentSyncFile> {
134
+ const absPath = path.join(rootDir, entry.relPath);
135
+ let action: AgentSyncFile["action"] = "created";
136
+ try {
137
+ const existing = await fs.readFile(absPath, "utf8");
138
+ action = existing === entry.content ? "unchanged" : "updated";
139
+ } catch {
140
+ action = "created";
141
+ }
142
+
143
+ if (dryRun) {
144
+ action = "planned";
145
+ } else if (action !== "unchanged") {
146
+ await fs.mkdir(path.dirname(absPath), { recursive: true });
147
+ await fs.writeFile(absPath, entry.content, "utf8");
148
+ }
149
+
150
+ return {
151
+ target: entry.target,
152
+ path: toPosix(entry.relPath),
153
+ action,
154
+ bytes: Buffer.byteLength(entry.content, "utf8"),
155
+ };
156
+ }
157
+
158
+ function nextCommands(): AgentSuggestedCommand[] {
159
+ return [
160
+ {
161
+ command: "mandu agent context --json",
162
+ reason: "Confirm the generated workflow matches the current project state.",
163
+ required: true,
164
+ },
165
+ {
166
+ command: "MANDU_MCP_PROFILE=agent-core",
167
+ reason: "Use the reduced default MCP exposure for coding agents.",
168
+ required: true,
169
+ },
170
+ ];
171
+ }
172
+
173
+ export async function buildAgentSyncReport(
174
+ rootDir: string = process.cwd(),
175
+ options: BuildAgentSyncOptions = {},
176
+ ): Promise<AgentSyncReport> {
177
+ const target = isTarget(options.target) ? options.target : "all";
178
+ const dryRun = options.dryRun === true;
179
+ const root = path.resolve(rootDir);
180
+ const files: AgentSyncFile[] = [];
181
+
182
+ for (const concrete of concreteTargets(target)) {
183
+ for (const entry of syncEntries(concrete)) {
184
+ files.push(await writeEntry(root, entry, dryRun));
185
+ }
186
+ }
187
+
188
+ return {
189
+ schemaVersion: 1,
190
+ framework: "mandu",
191
+ generatedAt: new Date().toISOString(),
192
+ ok: true,
193
+ target,
194
+ profile: "agent-core",
195
+ workflow: ["context", "plan", "apply", "verify", "repair"],
196
+ files,
197
+ warnings: dryRun ? ["Dry-run only. No files were written."] : [],
198
+ nextCommands: nextCommands(),
199
+ };
200
+ }
@@ -153,27 +153,19 @@ export interface AgentVerifyCheck {
153
153
  details?: Record<string, unknown>;
154
154
  }
155
155
 
156
- export interface AgentSuggestedCommand {
157
- command: string;
158
- reason: string;
159
- required: boolean;
160
- }
161
-
162
- export interface AgentChangedFileReason {
163
- file: string;
164
- reasons: string[];
165
- recommendedChecks: string[];
166
- internalApi: boolean;
167
- }
168
-
169
- export interface AgentVerifyReport {
156
+ export interface AgentSuggestedCommand {
157
+ command: string;
158
+ reason: string;
159
+ required: boolean;
160
+ }
161
+
162
+ export interface AgentVerifyReport {
170
163
  schemaVersion: 1;
171
164
  framework: "mandu";
172
165
  generatedAt: string;
173
- project: AgentProjectSummary;
174
- changedFiles: string[];
175
- changedFileReasons: AgentChangedFileReason[];
176
- gitAvailable: boolean;
166
+ project: AgentProjectSummary;
167
+ changedFiles: string[];
168
+ gitAvailable: boolean;
177
169
  notes: string[];
178
170
  ok: boolean;
179
171
  checks: AgentVerifyCheck[];
@@ -7,9 +7,8 @@ import type { ContractViolation } from "../guard/contract-guard";
7
7
  import {
8
8
  buildAgentContext,
9
9
  } from "./context";
10
- import type {
11
- AgentChangedFileReason,
12
- AgentDiagnostic,
10
+ import type {
11
+ AgentDiagnostic,
13
12
  AgentDiagnosticSeverity,
14
13
  AgentSuggestedCommand,
15
14
  AgentVerifyCheck,
@@ -209,11 +208,7 @@ function matchesChanged(
209
208
  return candidates.some((file) => changed.has(file));
210
209
  }
211
210
 
212
- function commandSuggestions(
213
- changedFiles: string[],
214
- diagnostics: AgentDiagnostic[],
215
- changedFileReasons: AgentChangedFileReason[] = [],
216
- ): AgentSuggestedCommand[] {
211
+ function commandSuggestions(changedFiles: string[], diagnostics: AgentDiagnostic[]): AgentSuggestedCommand[] {
217
212
  const files = changedFiles.map(normalizePath).filter((value): value is string => Boolean(value));
218
213
  const out: AgentSuggestedCommand[] = [];
219
214
  const add = (command: string, reason: string, required: boolean) => {
@@ -245,101 +240,15 @@ function commandSuggestions(
245
240
  if (files.some((file) => file.startsWith("packages/mcp/"))) {
246
241
  add("bun test packages/mcp/tests", "MCP package files changed.", true);
247
242
  }
248
- if (files.some((file) => file.includes("package.json") || file === "bun.lock")) {
249
- add("bun run check:publish", "Package metadata or lockfile changed.", true);
250
- }
251
- if (changedFileReasons.some((entry) => entry.internalApi)) {
252
- add("bun run check:public-api && bun run check:target-boundaries", "Internal framework boundaries changed.", true);
253
- }
254
- if (diagnostics.some((d) => d.severity === "error" || d.severity === "fatal")) {
243
+ if (files.some((file) => file.includes("package.json") || file === "bun.lock")) {
244
+ add("bun run check:publish", "Package metadata or lockfile changed.", true);
245
+ }
246
+ if (diagnostics.some((d) => d.severity === "error" || d.severity === "fatal")) {
255
247
  add("mandu agent repair --from .mandu/agent-verify.json", "Verification produced repairable diagnostics.", false);
256
248
  }
257
249
 
258
250
  return out;
259
- }
260
-
261
- function isInternalApiEdit(file: string): boolean {
262
- return [
263
- "packages/core/src/runtime/",
264
- "packages/core/src/bundler/",
265
- "packages/core/src/server/",
266
- "packages/core/src/guard/",
267
- "packages/core/src/spec/",
268
- "packages/core/src/router/",
269
- "packages/core/src/internal/",
270
- ].some((prefix) => file.startsWith(prefix));
271
- }
272
-
273
- function changedFileReason(file: string): AgentChangedFileReason {
274
- const normalized = normalizePath(file) ?? file;
275
- const reasons: string[] = [];
276
- const recommendedChecks: string[] = [];
277
-
278
- if (/\.(ts|tsx|js|jsx)$/.test(normalized)) {
279
- reasons.push("Source code changed.");
280
- recommendedChecks.push("bun run typecheck");
281
- }
282
- if (/\.test\.(ts|tsx|js|jsx)$/.test(normalized)) {
283
- reasons.push("Test code changed.");
284
- recommendedChecks.push(`bun test ${normalized}`);
285
- }
286
- if (normalized.startsWith("packages/cli/")) {
287
- reasons.push("CLI behavior or documentation changed.");
288
- recommendedChecks.push("bun test packages/cli/src");
289
- }
290
- if (normalized.startsWith("packages/mcp/")) {
291
- reasons.push("MCP tool surface changed.");
292
- recommendedChecks.push("bun test packages/mcp/tests");
293
- }
294
- if (normalized.startsWith("docs/") || normalized.endsWith("README.md") || normalized.endsWith("README.ko.md")) {
295
- reasons.push("User-facing documentation changed.");
296
- recommendedChecks.push("bun run check:docs-drift");
297
- }
298
- if (normalized === "package.json" || normalized === "bun.lock" || normalized.endsWith("/package.json")) {
299
- reasons.push("Package metadata or dependency graph changed.");
300
- recommendedChecks.push("bun run check:publish");
301
- }
302
-
303
- const internalApi = isInternalApiEdit(normalized);
304
- if (internalApi) {
305
- reasons.push("Framework internal API changed.");
306
- recommendedChecks.push("bun run check:public-api && bun run check:target-boundaries");
307
- }
308
-
309
- return {
310
- file: normalized,
311
- reasons: reasons.length > 0 ? reasons : ["Changed file requires standard verification."],
312
- recommendedChecks: [...new Set(recommendedChecks)],
313
- internalApi,
314
- };
315
- }
316
-
317
- function buildChangedFileReasons(changedFiles: string[]): AgentChangedFileReason[] {
318
- return changedFiles
319
- .map(normalizePath)
320
- .filter((file): file is string => Boolean(file))
321
- .map(changedFileReason);
322
- }
323
-
324
- function internalApiDiagnostics(changedFileReasons: AgentChangedFileReason[]): AgentDiagnostic[] {
325
- return changedFileReasons
326
- .filter((entry) => entry.internalApi)
327
- .map((entry) => ({
328
- code: "MANDU_VERIFY_INTERNAL_API_EDIT",
329
- severity: "warning" as const,
330
- title: "Internal framework API changed",
331
- file: entry.file,
332
- cause: "This file is part of Mandu's internal runtime/bundler/guard surface and can affect public behavior indirectly.",
333
- suggestedFix: {
334
- type: "run_command" as const,
335
- command: "bun run check:public-api && bun run check:target-boundaries",
336
- description: "Verify public API classification and target-safe import boundaries.",
337
- },
338
- docs: "docs/architect/public-api-boundary.md",
339
- repairable: false,
340
- source: "agent.verify",
341
- }));
342
- }
251
+ }
343
252
 
344
253
  function check(
345
254
  id: string,
@@ -372,22 +281,16 @@ export async function buildAgentVerifyReport(
372
281
  rootDir: string = process.cwd(),
373
282
  options: BuildAgentVerifyOptions = {},
374
283
  ): Promise<AgentVerifyReport> {
375
- const root = path.resolve(rootDir);
376
- const changed = await collectChangedFiles(root, options);
377
- const changedSet = new Set(changed.files.map(normalizePath).filter((value): value is string => Boolean(value)));
378
- const changedFileReasons = buildChangedFileReasons(changed.files);
284
+ const root = path.resolve(rootDir);
285
+ const changed = await collectChangedFiles(root, options);
286
+ const changedSet = new Set(changed.files.map(normalizePath).filter((value): value is string => Boolean(value)));
379
287
  const context = await buildAgentContext(root, {
380
288
  includeDiagnose: false,
381
289
  includeGit: false,
382
290
  });
383
291
  const notes = [...changed.notes];
384
- const checks: AgentVerifyCheck[] = [];
385
- const diagnostics: AgentDiagnostic[] = [];
386
- const internalDiagnostics = internalApiDiagnostics(changedFileReasons);
387
- diagnostics.push(...internalDiagnostics);
388
- checks.push(check("internal-api", "Internal API boundary", internalDiagnostics, {
389
- changedFiles: changedFileReasons.filter((entry) => entry.internalApi).length,
390
- }));
292
+ const checks: AgentVerifyCheck[] = [];
293
+ const diagnostics: AgentDiagnostic[] = [];
391
294
 
392
295
  if (options.includeDiagnose !== false) {
393
296
  try {
@@ -479,15 +382,14 @@ export async function buildAgentVerifyReport(
479
382
  schemaVersion: 1,
480
383
  framework: "mandu",
481
384
  generatedAt: new Date().toISOString(),
482
- project: context.project,
483
- changedFiles: changed.files,
484
- changedFileReasons,
485
- gitAvailable: changed.gitAvailable,
385
+ project: context.project,
386
+ changedFiles: changed.files,
387
+ gitAvailable: changed.gitAvailable,
486
388
  notes,
487
389
  ok,
488
390
  checks,
489
391
  diagnostics,
490
- suggestedCommands: commandSuggestions(changed.files, diagnostics, changedFileReasons),
392
+ suggestedCommands: commandSuggestions(changed.files, diagnostics),
491
393
  nextRepairInput: AGENT_VERIFY_RELATIVE_PATH,
492
394
  };
493
395
  }
@@ -206,13 +206,13 @@ export function generateTemplatePatches(
206
206
  "Do NOT import or re-export the island in page.tsx — island() returns " +
207
207
  "a config object, not a React component. Use data-island attributes instead.",
208
208
  type: "modify",
209
- content:
210
- `// Example: app/my-feature.island.tsx\n` +
211
- `import { wrapComponent } from "@mandujs/core/client";\n\n` +
212
- `export default wrapComponent(MyComponent);\n\n` +
213
- `// In page.tsx, reference via: <div data-island="my-feature">...</div>`,
214
- confidence: 0.9,
215
- });
209
+ content:
210
+ `// Example: app/my-feature.island.tsx\n` +
211
+ `import { wrapComponent } from "@mandujs/core/client";\n\n` +
212
+ `export default wrapComponent(MyComponent);\n\n` +
213
+ `// In page.tsx, reference via: <div data-island="my-feature">...</div>`,
214
+ confidence: 0.9,
215
+ });
216
216
  break;
217
217
 
218
218
  default: