@mandujs/mcp 0.36.2 → 0.37.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.
- package/package.json +4 -4
- package/src/activity-adapter.ts +23 -23
- package/src/adapters/index.ts +20 -20
- package/src/adapters/monitor-adapter.ts +100 -100
- package/src/adapters/tool-adapter.ts +90 -90
- package/src/executor/index.ts +22 -22
- package/src/executor/tool-executor.ts +148 -148
- package/src/hooks/config-watcher.ts +173 -173
- package/src/hooks/index.ts +23 -23
- package/src/hooks/mcp-hooks.ts +227 -227
- package/src/index.ts +0 -0
- package/src/logging/index.ts +15 -15
- package/src/logging/mcp-transport.ts +134 -134
- package/src/profiles.ts +34 -34
- package/src/registry/index.ts +13 -13
- package/src/registry/mcp-tool-registry.ts +298 -298
- package/src/resources/skills/guides.ts +1136 -1136
- package/src/resources/skills/index.ts +12 -12
- package/src/resources/skills/mandu-composition/SKILL.md +91 -91
- package/src/resources/skills/mandu-composition/metadata.json +13 -13
- package/src/resources/skills/mandu-composition/rules/_sections.md +26 -26
- package/src/resources/skills/mandu-composition/rules/_template.md +77 -77
- package/src/resources/skills/mandu-composition/rules/comp-arch-avoid-boolean-props.md +146 -146
- package/src/resources/skills/mandu-composition/rules/comp-arch-compound-components.md +164 -164
- package/src/resources/skills/mandu-composition/rules/comp-island-event.md +161 -161
- package/src/resources/skills/mandu-composition/rules/comp-island-slot-split.md +167 -167
- package/src/resources/skills/mandu-composition/rules/comp-pattern-children.md +149 -149
- package/src/resources/skills/mandu-composition/rules/comp-state-context-interface.md +148 -148
- package/src/resources/skills/mandu-composition/rules/comp-state-lift-state.md +150 -150
- package/src/resources/skills/mandu-deployment/SKILL.md +92 -92
- package/src/resources/skills/mandu-deployment/_sections.md +41 -41
- package/src/resources/skills/mandu-deployment/_template.md +38 -38
- package/src/resources/skills/mandu-deployment/metadata.json +13 -13
- package/src/resources/skills/mandu-deployment/rules/db-provider-supabase.md +300 -300
- package/src/resources/skills/mandu-deployment/rules/deploy-build-bun.md +109 -109
- package/src/resources/skills/mandu-deployment/rules/deploy-build-output.md +115 -115
- package/src/resources/skills/mandu-deployment/rules/deploy-cicd-github.md +219 -219
- package/src/resources/skills/mandu-deployment/rules/deploy-docker-bun.md +150 -150
- package/src/resources/skills/mandu-deployment/rules/deploy-docker-compose.md +223 -223
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-fly.md +152 -152
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-render.md +179 -179
- package/src/resources/skills/mandu-deployment/rules/deploy-platform-vercel.md +140 -140
- package/src/resources/skills/mandu-fs-routes/SKILL.md +82 -82
- package/src/resources/skills/mandu-fs-routes/metadata.json +12 -12
- package/src/resources/skills/mandu-fs-routes/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-fs-routes/rules/_template.md +69 -69
- package/src/resources/skills/mandu-fs-routes/rules/routes-api-methods.md +65 -65
- package/src/resources/skills/mandu-fs-routes/rules/routes-dynamic-param.md +93 -93
- package/src/resources/skills/mandu-fs-routes/rules/routes-naming-page.md +55 -55
- package/src/resources/skills/mandu-guard/SKILL.md +129 -129
- package/src/resources/skills/mandu-guard/metadata.json +12 -12
- package/src/resources/skills/mandu-guard/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-guard/rules/_template.md +82 -82
- package/src/resources/skills/mandu-guard/rules/guard-config-rules.md +100 -100
- package/src/resources/skills/mandu-guard/rules/guard-layer-direction.md +76 -76
- package/src/resources/skills/mandu-guard/rules/guard-preset-mandu.md +81 -81
- package/src/resources/skills/mandu-guard/rules/guard-validate-import.md +80 -80
- package/src/resources/skills/mandu-hydration/SKILL.md +91 -91
- package/src/resources/skills/mandu-hydration/metadata.json +12 -12
- package/src/resources/skills/mandu-hydration/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-hydration/rules/_template.md +72 -72
- package/src/resources/skills/mandu-hydration/rules/hydration-data-event.md +109 -109
- package/src/resources/skills/mandu-hydration/rules/hydration-directive-use-client.md +55 -55
- package/src/resources/skills/mandu-hydration/rules/hydration-island-setup.md +113 -113
- package/src/resources/skills/mandu-hydration/rules/hydration-priority-visible.md +68 -68
- package/src/resources/skills/mandu-performance/SKILL.md +85 -85
- package/src/resources/skills/mandu-performance/metadata.json +14 -14
- package/src/resources/skills/mandu-performance/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-performance/rules/_template.md +64 -64
- package/src/resources/skills/mandu-performance/rules/perf-async-defer-await.md +103 -103
- package/src/resources/skills/mandu-performance/rules/perf-async-parallel.md +95 -95
- package/src/resources/skills/mandu-performance/rules/perf-bun-file.md +124 -124
- package/src/resources/skills/mandu-performance/rules/perf-bun-serve.md +125 -125
- package/src/resources/skills/mandu-performance/rules/perf-bundle-imports.md +80 -80
- package/src/resources/skills/mandu-performance/rules/perf-bundle-island-lazy.md +145 -145
- package/src/resources/skills/mandu-performance/rules/perf-cache-react.md +98 -98
- package/src/resources/skills/mandu-performance/rules/perf-render-transitions.md +154 -154
- package/src/resources/skills/mandu-security/SKILL.md +87 -87
- package/src/resources/skills/mandu-security/metadata.json +13 -13
- package/src/resources/skills/mandu-security/rules/_sections.md +31 -31
- package/src/resources/skills/mandu-security/rules/_template.md +74 -74
- package/src/resources/skills/mandu-security/rules/sec-auth-guard.md +127 -127
- package/src/resources/skills/mandu-security/rules/sec-env-management.md +133 -133
- package/src/resources/skills/mandu-security/rules/sec-input-validate.md +148 -148
- package/src/resources/skills/mandu-security/rules/sec-protect-csrf.md +146 -146
- package/src/resources/skills/mandu-security/rules/sec-protect-headers.md +138 -138
- package/src/resources/skills/mandu-slot/SKILL.md +85 -85
- package/src/resources/skills/mandu-slot/metadata.json +12 -12
- package/src/resources/skills/mandu-slot/rules/_sections.md +36 -36
- package/src/resources/skills/mandu-slot/rules/_template.md +63 -63
- package/src/resources/skills/mandu-slot/rules/slot-basic-structure.md +38 -38
- package/src/resources/skills/mandu-slot/rules/slot-ctx-response.md +56 -56
- package/src/resources/skills/mandu-slot/rules/slot-guard-auth.md +59 -59
- package/src/resources/skills/mandu-slot/rules/slot-http-methods.md +64 -64
- package/src/resources/skills/mandu-styling/SKILL.md +154 -154
- package/src/resources/skills/mandu-styling/_sections.md +43 -43
- package/src/resources/skills/mandu-styling/_template.md +32 -32
- package/src/resources/skills/mandu-styling/metadata.json +15 -15
- package/src/resources/skills/mandu-styling/rules/style-component-compound.md +235 -235
- package/src/resources/skills/mandu-styling/rules/style-component-slots.md +255 -255
- package/src/resources/skills/mandu-styling/rules/style-component-tokens.md +205 -205
- package/src/resources/skills/mandu-styling/rules/style-island-animations.md +272 -272
- package/src/resources/skills/mandu-styling/rules/style-island-scoping.md +167 -167
- package/src/resources/skills/mandu-styling/rules/style-island-variants.md +221 -221
- package/src/resources/skills/mandu-styling/rules/style-perf-critical.md +209 -209
- package/src/resources/skills/mandu-styling/rules/style-perf-purge.md +192 -192
- package/src/resources/skills/mandu-styling/rules/style-setup-modules.md +162 -162
- package/src/resources/skills/mandu-styling/rules/style-setup-panda.md +164 -164
- package/src/resources/skills/mandu-styling/rules/style-setup-tailwind.md +170 -170
- package/src/resources/skills/mandu-styling/rules/style-tailwind-v4-gotchas.md +179 -179
- package/src/resources/skills/mandu-styling/rules/style-theme-darkmode.md +229 -229
- package/src/resources/skills/mandu-testing/SKILL.md +99 -99
- package/src/resources/skills/mandu-testing/metadata.json +13 -13
- package/src/resources/skills/mandu-testing/rules/_sections.md +26 -26
- package/src/resources/skills/mandu-testing/rules/_template.md +65 -65
- package/src/resources/skills/mandu-testing/rules/test-component-island.md +195 -195
- package/src/resources/skills/mandu-testing/rules/test-e2e-playwright.md +196 -196
- package/src/resources/skills/mandu-testing/rules/test-mock-fetch.md +219 -219
- package/src/resources/skills/mandu-testing/rules/test-slot-unit.md +192 -192
- package/src/resources/skills/mandu-ui/SKILL.md +117 -117
- package/src/resources/skills/mandu-ui/_sections.md +23 -23
- package/src/resources/skills/mandu-ui/_template.md +32 -32
- package/src/resources/skills/mandu-ui/metadata.json +13 -13
- package/src/resources/skills/mandu-ui/rules/ui-accessibility-aria.md +232 -232
- package/src/resources/skills/mandu-ui/rules/ui-accessibility-focus.md +238 -238
- package/src/resources/skills/mandu-ui/rules/ui-composition-patterns.md +259 -259
- package/src/resources/skills/mandu-ui/rules/ui-island-integration.md +258 -258
- package/src/resources/skills/mandu-ui/rules/ui-radix-patterns.md +213 -213
- package/src/resources/skills/mandu-ui/rules/ui-shadcn-setup.md +209 -209
- package/src/resources/skills/recipes.ts +932 -932
- package/src/server.ts +3 -3
- package/src/tools/ate-exemplar.ts +92 -92
- package/src/tools/ate-flakes.ts +90 -90
- package/src/tools/ate-mutate.ts +103 -103
- package/src/tools/ate-mutation-report.ts +64 -64
- package/src/tools/ate-oracle-pending.ts +49 -49
- package/src/tools/ate-oracle-replay.ts +44 -44
- package/src/tools/ate-oracle-verdict.ts +70 -70
- package/src/tools/ate-prompt.ts +146 -146
- package/src/tools/brain.ts +3 -3
- package/src/tools/deploy-plan.ts +378 -378
- package/src/tools/deploy-preview.ts +316 -316
- package/src/tools/design.ts +825 -825
- package/src/tools/docs.ts +350 -350
- package/src/tools/kitchen.ts +109 -23
- package/src/tools/lint.ts +226 -226
- package/src/tools/loop-close.ts +175 -175
- package/src/tools/negotiate.ts +263 -263
- package/src/tools/run-tests.ts +424 -424
- package/src/tools/runtime.ts +1 -1
- package/src/tools/slot-validation.ts +199 -199
- package/src/tx-lock.ts +73 -73
- package/src/utils/runtime-control.ts +52 -52
package/src/tools/loop-close.ts
CHANGED
|
@@ -1,175 +1,175 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP tool — `mandu.loop.close`
|
|
3
|
-
*
|
|
4
|
-
* Thin, safe adapter over `@mandujs/skills/loop-closure`. Given agent
|
|
5
|
-
* output (stdout, stderr, exitCode), runs the built-in loop-closure
|
|
6
|
-
* detectors and returns a structured follow-up prompt:
|
|
7
|
-
*
|
|
8
|
-
* {
|
|
9
|
-
* stallReason: string,
|
|
10
|
-
* nextPrompt: string,
|
|
11
|
-
* evidence: Array<{ kind, file?, line?, snippet, label? }>
|
|
12
|
-
* }
|
|
13
|
-
*
|
|
14
|
-
* SAFETY INVARIANTS — enforced by design:
|
|
15
|
-
* - `closeLoop()` is pure: no I/O, no spawn, no file writes.
|
|
16
|
-
* - This wrapper adds only input validation + field shaping.
|
|
17
|
-
* - The `nextPrompt` is ADVISORY text. It is never auto-executed.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
-
import { closeLoop, listDetectorIds } from "@mandujs/skills/loop-closure";
|
|
22
|
-
|
|
23
|
-
interface LoopCloseInput {
|
|
24
|
-
stdout?: unknown;
|
|
25
|
-
stderr?: unknown;
|
|
26
|
-
exitCode?: unknown;
|
|
27
|
-
detectors?: unknown;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function validateInput(raw: Record<string, unknown>): {
|
|
31
|
-
ok: true;
|
|
32
|
-
value: {
|
|
33
|
-
stdout: string;
|
|
34
|
-
stderr: string;
|
|
35
|
-
exitCode: number;
|
|
36
|
-
detectors?: string[];
|
|
37
|
-
};
|
|
38
|
-
} | { ok: false; error: string; field: string; hint: string } {
|
|
39
|
-
const stdout = raw.stdout ?? "";
|
|
40
|
-
if (typeof stdout !== "string") {
|
|
41
|
-
return {
|
|
42
|
-
ok: false,
|
|
43
|
-
error: "'stdout' must be a string",
|
|
44
|
-
field: "stdout",
|
|
45
|
-
hint: "Omit or pass '' for no stdout",
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const stderr = raw.stderr ?? "";
|
|
50
|
-
if (typeof stderr !== "string") {
|
|
51
|
-
return {
|
|
52
|
-
ok: false,
|
|
53
|
-
error: "'stderr' must be a string",
|
|
54
|
-
field: "stderr",
|
|
55
|
-
hint: "Omit or pass '' for no stderr",
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let exitCode = 0;
|
|
60
|
-
if (raw.exitCode !== undefined) {
|
|
61
|
-
if (typeof raw.exitCode !== "number" || !Number.isFinite(raw.exitCode)) {
|
|
62
|
-
return {
|
|
63
|
-
ok: false,
|
|
64
|
-
error: "'exitCode' must be a finite number",
|
|
65
|
-
field: "exitCode",
|
|
66
|
-
hint: "Pass the child-process exit code, typically 0 (success) or non-zero (failure)",
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
exitCode = Math.trunc(raw.exitCode);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let detectors: string[] | undefined;
|
|
73
|
-
if (raw.detectors !== undefined) {
|
|
74
|
-
if (!Array.isArray(raw.detectors) ||
|
|
75
|
-
!raw.detectors.every((d) => typeof d === "string")) {
|
|
76
|
-
return {
|
|
77
|
-
ok: false,
|
|
78
|
-
error: "'detectors' must be an array of detector IDs",
|
|
79
|
-
field: "detectors",
|
|
80
|
-
hint: `Valid IDs: ${listDetectorIds().join(", ")}`,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
detectors = raw.detectors as string[];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
ok: true,
|
|
88
|
-
value: { stdout, stderr, exitCode, ...(detectors ? { detectors } : {}) },
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
93
|
-
// Handler
|
|
94
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
95
|
-
|
|
96
|
-
async function runLoopClose(
|
|
97
|
-
input: LoopCloseInput,
|
|
98
|
-
): Promise<
|
|
99
|
-
| {
|
|
100
|
-
stallReason: string;
|
|
101
|
-
nextPrompt: string;
|
|
102
|
-
evidence: Array<{
|
|
103
|
-
kind: string;
|
|
104
|
-
file?: string;
|
|
105
|
-
line?: number;
|
|
106
|
-
snippet: string;
|
|
107
|
-
label?: string;
|
|
108
|
-
}>;
|
|
109
|
-
detectors_run: string[];
|
|
110
|
-
}
|
|
111
|
-
| { error: string; field?: string; hint?: string }
|
|
112
|
-
> {
|
|
113
|
-
const validated = validateInput(input as Record<string, unknown>);
|
|
114
|
-
if (!validated.ok) {
|
|
115
|
-
return {
|
|
116
|
-
error: validated.error,
|
|
117
|
-
field: validated.field,
|
|
118
|
-
hint: validated.hint,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const report = closeLoop(validated.value);
|
|
123
|
-
return {
|
|
124
|
-
stallReason: report.stallReason,
|
|
125
|
-
nextPrompt: report.nextPrompt,
|
|
126
|
-
evidence: report.evidence,
|
|
127
|
-
detectors_run: validated.value.detectors ?? listDetectorIds(),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
132
|
-
// Tool definition + handler map
|
|
133
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
134
|
-
|
|
135
|
-
export const loopCloseToolDefinitions: Tool[] = [
|
|
136
|
-
{
|
|
137
|
-
name: "mandu.loop.close",
|
|
138
|
-
description:
|
|
139
|
-
"Analyze agent output (stdout, stderr, exitCode) and return a structured `nextPrompt` that names the primary stall pattern, explains how to address it, and lists supporting evidence. This tool is pure — it never writes files, spawns processes, or auto-executes anything. The returned prompt is advisory text only.",
|
|
140
|
-
annotations: {
|
|
141
|
-
readOnlyHint: true,
|
|
142
|
-
},
|
|
143
|
-
inputSchema: {
|
|
144
|
-
type: "object",
|
|
145
|
-
properties: {
|
|
146
|
-
stdout: {
|
|
147
|
-
type: "string",
|
|
148
|
-
description: "Captured stdout from the most recent command/run.",
|
|
149
|
-
},
|
|
150
|
-
stderr: {
|
|
151
|
-
type: "string",
|
|
152
|
-
description: "Captured stderr from the most recent command/run.",
|
|
153
|
-
},
|
|
154
|
-
exitCode: {
|
|
155
|
-
type: "number",
|
|
156
|
-
description: "Child-process exit code. Defaults to 0 when omitted.",
|
|
157
|
-
},
|
|
158
|
-
detectors: {
|
|
159
|
-
type: "array",
|
|
160
|
-
items: { type: "string" },
|
|
161
|
-
description:
|
|
162
|
-
"Optional detector-ID allow-list. Omit to run the full built-in set.",
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
required: [],
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
export function loopCloseTools(_projectRoot: string) {
|
|
171
|
-
const handlers: Record<string, (args: Record<string, unknown>) => Promise<unknown>> = {
|
|
172
|
-
"mandu.loop.close": async (args) => runLoopClose(args as LoopCloseInput),
|
|
173
|
-
};
|
|
174
|
-
return handlers;
|
|
175
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool — `mandu.loop.close`
|
|
3
|
+
*
|
|
4
|
+
* Thin, safe adapter over `@mandujs/skills/loop-closure`. Given agent
|
|
5
|
+
* output (stdout, stderr, exitCode), runs the built-in loop-closure
|
|
6
|
+
* detectors and returns a structured follow-up prompt:
|
|
7
|
+
*
|
|
8
|
+
* {
|
|
9
|
+
* stallReason: string,
|
|
10
|
+
* nextPrompt: string,
|
|
11
|
+
* evidence: Array<{ kind, file?, line?, snippet, label? }>
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* SAFETY INVARIANTS — enforced by design:
|
|
15
|
+
* - `closeLoop()` is pure: no I/O, no spawn, no file writes.
|
|
16
|
+
* - This wrapper adds only input validation + field shaping.
|
|
17
|
+
* - The `nextPrompt` is ADVISORY text. It is never auto-executed.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
+
import { closeLoop, listDetectorIds } from "@mandujs/skills/loop-closure";
|
|
22
|
+
|
|
23
|
+
interface LoopCloseInput {
|
|
24
|
+
stdout?: unknown;
|
|
25
|
+
stderr?: unknown;
|
|
26
|
+
exitCode?: unknown;
|
|
27
|
+
detectors?: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function validateInput(raw: Record<string, unknown>): {
|
|
31
|
+
ok: true;
|
|
32
|
+
value: {
|
|
33
|
+
stdout: string;
|
|
34
|
+
stderr: string;
|
|
35
|
+
exitCode: number;
|
|
36
|
+
detectors?: string[];
|
|
37
|
+
};
|
|
38
|
+
} | { ok: false; error: string; field: string; hint: string } {
|
|
39
|
+
const stdout = raw.stdout ?? "";
|
|
40
|
+
if (typeof stdout !== "string") {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
error: "'stdout' must be a string",
|
|
44
|
+
field: "stdout",
|
|
45
|
+
hint: "Omit or pass '' for no stdout",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const stderr = raw.stderr ?? "";
|
|
50
|
+
if (typeof stderr !== "string") {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
error: "'stderr' must be a string",
|
|
54
|
+
field: "stderr",
|
|
55
|
+
hint: "Omit or pass '' for no stderr",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let exitCode = 0;
|
|
60
|
+
if (raw.exitCode !== undefined) {
|
|
61
|
+
if (typeof raw.exitCode !== "number" || !Number.isFinite(raw.exitCode)) {
|
|
62
|
+
return {
|
|
63
|
+
ok: false,
|
|
64
|
+
error: "'exitCode' must be a finite number",
|
|
65
|
+
field: "exitCode",
|
|
66
|
+
hint: "Pass the child-process exit code, typically 0 (success) or non-zero (failure)",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
exitCode = Math.trunc(raw.exitCode);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let detectors: string[] | undefined;
|
|
73
|
+
if (raw.detectors !== undefined) {
|
|
74
|
+
if (!Array.isArray(raw.detectors) ||
|
|
75
|
+
!raw.detectors.every((d) => typeof d === "string")) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
error: "'detectors' must be an array of detector IDs",
|
|
79
|
+
field: "detectors",
|
|
80
|
+
hint: `Valid IDs: ${listDetectorIds().join(", ")}`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
detectors = raw.detectors as string[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
value: { stdout, stderr, exitCode, ...(detectors ? { detectors } : {}) },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
93
|
+
// Handler
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
async function runLoopClose(
|
|
97
|
+
input: LoopCloseInput,
|
|
98
|
+
): Promise<
|
|
99
|
+
| {
|
|
100
|
+
stallReason: string;
|
|
101
|
+
nextPrompt: string;
|
|
102
|
+
evidence: Array<{
|
|
103
|
+
kind: string;
|
|
104
|
+
file?: string;
|
|
105
|
+
line?: number;
|
|
106
|
+
snippet: string;
|
|
107
|
+
label?: string;
|
|
108
|
+
}>;
|
|
109
|
+
detectors_run: string[];
|
|
110
|
+
}
|
|
111
|
+
| { error: string; field?: string; hint?: string }
|
|
112
|
+
> {
|
|
113
|
+
const validated = validateInput(input as Record<string, unknown>);
|
|
114
|
+
if (!validated.ok) {
|
|
115
|
+
return {
|
|
116
|
+
error: validated.error,
|
|
117
|
+
field: validated.field,
|
|
118
|
+
hint: validated.hint,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const report = closeLoop(validated.value);
|
|
123
|
+
return {
|
|
124
|
+
stallReason: report.stallReason,
|
|
125
|
+
nextPrompt: report.nextPrompt,
|
|
126
|
+
evidence: report.evidence,
|
|
127
|
+
detectors_run: validated.value.detectors ?? listDetectorIds(),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
132
|
+
// Tool definition + handler map
|
|
133
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
export const loopCloseToolDefinitions: Tool[] = [
|
|
136
|
+
{
|
|
137
|
+
name: "mandu.loop.close",
|
|
138
|
+
description:
|
|
139
|
+
"Analyze agent output (stdout, stderr, exitCode) and return a structured `nextPrompt` that names the primary stall pattern, explains how to address it, and lists supporting evidence. This tool is pure — it never writes files, spawns processes, or auto-executes anything. The returned prompt is advisory text only.",
|
|
140
|
+
annotations: {
|
|
141
|
+
readOnlyHint: true,
|
|
142
|
+
},
|
|
143
|
+
inputSchema: {
|
|
144
|
+
type: "object",
|
|
145
|
+
properties: {
|
|
146
|
+
stdout: {
|
|
147
|
+
type: "string",
|
|
148
|
+
description: "Captured stdout from the most recent command/run.",
|
|
149
|
+
},
|
|
150
|
+
stderr: {
|
|
151
|
+
type: "string",
|
|
152
|
+
description: "Captured stderr from the most recent command/run.",
|
|
153
|
+
},
|
|
154
|
+
exitCode: {
|
|
155
|
+
type: "number",
|
|
156
|
+
description: "Child-process exit code. Defaults to 0 when omitted.",
|
|
157
|
+
},
|
|
158
|
+
detectors: {
|
|
159
|
+
type: "array",
|
|
160
|
+
items: { type: "string" },
|
|
161
|
+
description:
|
|
162
|
+
"Optional detector-ID allow-list. Omit to run the full built-in set.",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
required: [],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
export function loopCloseTools(_projectRoot: string) {
|
|
171
|
+
const handlers: Record<string, (args: Record<string, unknown>) => Promise<unknown>> = {
|
|
172
|
+
"mandu.loop.close": async (args) => runLoopClose(args as LoopCloseInput),
|
|
173
|
+
};
|
|
174
|
+
return handlers;
|
|
175
|
+
}
|