@mono-agent/agent-app 0.15.2 → 0.15.4

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 (44) hide show
  1. package/README.md +13 -0
  2. package/dist/app-controller-responder.d.ts.map +1 -1
  3. package/dist/app-controller-responder.js +9 -7
  4. package/dist/app-controller-responder.js.map +1 -1
  5. package/dist/channel-drivers/native-notify.d.ts.map +1 -1
  6. package/dist/channel-drivers/native-notify.js +18 -8
  7. package/dist/channel-drivers/native-notify.js.map +1 -1
  8. package/dist/config-reference.d.ts.map +1 -1
  9. package/dist/config-reference.js +101 -2
  10. package/dist/config-reference.js.map +1 -1
  11. package/dist/configured-agent.d.ts.map +1 -1
  12. package/dist/configured-agent.js +206 -4
  13. package/dist/configured-agent.js.map +1 -1
  14. package/dist/doctor.d.ts.map +1 -1
  15. package/dist/doctor.js +150 -0
  16. package/dist/doctor.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/modules/catalog.js +1 -1
  22. package/dist/modules/catalog.js.map +1 -1
  23. package/dist/modules/known-tools.d.ts +1 -1
  24. package/dist/modules/known-tools.d.ts.map +1 -1
  25. package/dist/modules/known-tools.js +4 -0
  26. package/dist/modules/known-tools.js.map +1 -1
  27. package/dist/run-history.js +1 -0
  28. package/dist/run-history.js.map +1 -1
  29. package/dist/runtime-routes.d.ts +10 -0
  30. package/dist/runtime-routes.d.ts.map +1 -1
  31. package/dist/runtime-routes.js +12 -0
  32. package/dist/runtime-routes.js.map +1 -1
  33. package/dist/wizard/prompts.d.ts.map +1 -1
  34. package/dist/wizard/prompts.js +1 -0
  35. package/dist/wizard/prompts.js.map +1 -1
  36. package/dist/wizard/run.js +1 -1
  37. package/dist/wizard/run.js.map +1 -1
  38. package/package.json +15 -15
  39. package/schema/mono-agent.config.schema.json +243 -0
  40. package/skills/mono-agent-composer/references/config-blueprint.md +13 -3
  41. package/skills/mono-agent-composer/references/discovery-questions.md +12 -1
  42. package/skills/mono-agent-composer/references/feature-coverage.md +4 -1
  43. package/skills/mono-agent-composer/references/playbooks.md +25 -2
  44. package/skills/mono-agent-composer/references/validation.md +1 -0
package/dist/doctor.js CHANGED
@@ -84,6 +84,7 @@ export async function validateMonoAgentFolder(options) {
84
84
  sections.push(await contextSection(coreConfig, options.cwd));
85
85
  sections.push(await memorySection(coreConfig, options.cwd, options.env, liveness, allowFilesystemWrites, options.preferAppPluginInstall === true));
86
86
  sections.push(await toolsSection(coreConfig, options));
87
+ sections.push(await webToolsSection(coreConfig, options, liveness));
87
88
  sections.push(await continuationSection(coreConfig, options));
88
89
  sections.push(await sandboxSection(coreConfig, options.sandboxEngine));
89
90
  }
@@ -1759,8 +1760,157 @@ async function toolsSection(config, input) {
1759
1760
  details.push(`Direct OpenCode model${directOpenCodeModels.length === 1 ? "" : "s"} ${directOpenCodeModels.join(", ")} cannot safely consume ` +
1760
1761
  `MCP runtime options from ${effectiveMcpSources.join("; ")}. Disable those MCP sources or use a Pi runtime (including pi:opencode-go:*).`);
1761
1762
  }
1763
+ // Subagents: the Agent tool is registered only when BOTH the capability is
1764
+ // enabled and the tool is allowed, so surface either half being missing.
1765
+ const subagents = config.subagents;
1766
+ const agentAllowed = allowAll || allowedTools.includes("Agent");
1767
+ if (subagents?.enabled === true) {
1768
+ const count = subagents.definitions?.length ?? 0;
1769
+ const inline = subagents.inline?.enabled === false
1770
+ ? "; call-time authoring off"
1771
+ : `; call-time authoring on${subagents.inline?.allowedTools === undefined ? "" : ` (capped at ${subagents.inline.allowedTools.join(", ")})`}`;
1772
+ details.push(`Subagents: enabled, ${count} profile${count === 1 ? "" : "s"}${count === 0 ? " (general-purpose only)" : ""}${inline}.`);
1773
+ for (const tool of subagents.inline?.allowedTools ?? []) {
1774
+ if (!isKnownToolName(tool) && !isMcpToolName(tool)) {
1775
+ status = "error";
1776
+ details.push(`subagents.inline.allowedTools lists unknown tool "${tool}".`);
1777
+ }
1778
+ }
1779
+ if (!agentAllowed) {
1780
+ status = status === "error" ? status : "waiting";
1781
+ details.push("Subagents are enabled but Agent is not in tools.allowedTools, so the tool is never registered. Add \"Agent\" to tools.allowedTools.");
1782
+ }
1783
+ for (const definition of subagents.definitions ?? []) {
1784
+ if (definition.promptPath !== undefined && !(await pathExists(definition.promptPath))) {
1785
+ status = "error";
1786
+ details.push(`Subagent "${definition.name}" promptPath does not exist: ${definition.promptPath}`);
1787
+ }
1788
+ for (const tool of definition.allowedTools ?? []) {
1789
+ if (!isKnownToolName(tool) && !isMcpToolName(tool)) {
1790
+ status = "error";
1791
+ details.push(`Subagent "${definition.name}" allows unknown tool "${tool}".`);
1792
+ }
1793
+ }
1794
+ for (const server of definition.mcpServers ?? []) {
1795
+ if (configuredMcpServerNames.length > 0 && !configuredMcpServerNames.includes(server)) {
1796
+ status = "error";
1797
+ details.push(`Subagent "${definition.name}" references MCP server "${server}", which is not in tools.mcpConfigPath.`);
1798
+ }
1799
+ }
1800
+ }
1801
+ }
1802
+ else if (agentAllowed && !allowAll) {
1803
+ status = status === "error" ? status : "waiting";
1804
+ details.push("Agent is allowed but subagents.enabled is not true, so the tool is never registered. Set subagents.enabled to true or drop Agent from tools.allowedTools.");
1805
+ }
1762
1806
  return { id: "tools", label: "Tools & MCP", status, details };
1763
1807
  }
1808
+ const MIN_AGENT_BROWSER_VERSION = [0, 33, 1];
1809
+ async function webToolsSection(config, input, liveness) {
1810
+ const web = config.tools.web;
1811
+ const search = web?.search ?? { backend: "auto" };
1812
+ const fetchConfig = web?.fetch ?? { render: "never", browserCommand: "agent-browser" };
1813
+ const details = [`WebSearch backend: ${search.backend}.`];
1814
+ let status = "ok";
1815
+ if (search.endpoint === undefined) {
1816
+ details.push(search.backend === "keyless"
1817
+ ? "SearXNG is not configured; keyless search is enabled."
1818
+ : "SearXNG is not configured; auto mode will use keyless search.");
1819
+ }
1820
+ else {
1821
+ details.push(`SearXNG endpoint: ${search.endpoint}.`);
1822
+ if (!liveness) {
1823
+ details.push("SearXNG liveness was not probed.");
1824
+ }
1825
+ else {
1826
+ const probe = await probeSearxngEndpoint(search.endpoint);
1827
+ if (probe.ok) {
1828
+ details.push("SearXNG JSON search probe succeeded.");
1829
+ }
1830
+ else {
1831
+ status = "waiting";
1832
+ details.push(`[WARN] SearXNG JSON search probe failed (${probe.reason}). ` +
1833
+ (search.backend === "auto"
1834
+ ? "Start the local companion or fix tools.web.search.endpoint; auto mode can still fall back to keyless search."
1835
+ : "Start the local companion or fix tools.web.search.endpoint; strict SearXNG mode has no fallback."));
1836
+ }
1837
+ }
1838
+ }
1839
+ details.push(`WebFetch browser rendering: ${fetchConfig.render}.`);
1840
+ if (fetchConfig.render === "never") {
1841
+ details.push("Static Defuddle/Readability extraction is active; agent-browser is not required.");
1842
+ }
1843
+ else if (!liveness) {
1844
+ details.push(`agent-browser liveness was not probed (${fetchConfig.browserCommand}).`);
1845
+ }
1846
+ else {
1847
+ const version = await readAgentBrowserVersion(fetchConfig.browserCommand, input);
1848
+ if (version === null || compareVersion(version, MIN_AGENT_BROWSER_VERSION) < 0) {
1849
+ status = "waiting";
1850
+ const found = version === null ? "missing or unreadable" : `v${version.join(".")}`;
1851
+ details.push(`[WARN] agent-browser is ${found}; WebFetch auto rendering requires >=${MIN_AGENT_BROWSER_VERSION.join(".")}.`);
1852
+ }
1853
+ else {
1854
+ details.push(`agent-browser v${version.join(".")} is ready.`);
1855
+ }
1856
+ }
1857
+ return { id: "web-tools", label: "Web search & fetch", status, details };
1858
+ }
1859
+ async function probeSearxngEndpoint(endpoint) {
1860
+ const ctrl = new AbortController();
1861
+ const timer = setTimeout(() => { ctrl.abort(); }, LIVENESS_PROBE_TIMEOUT_MS);
1862
+ try {
1863
+ const response = await fetch(`${endpoint.replace(/\/+$/u, "")}/search`, {
1864
+ method: "POST",
1865
+ headers: {
1866
+ Accept: "application/json",
1867
+ "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
1868
+ },
1869
+ body: new URLSearchParams({ q: "mono-agent doctor", format: "json", categories: "general" }),
1870
+ redirect: "error",
1871
+ signal: ctrl.signal,
1872
+ });
1873
+ if (!response.ok)
1874
+ return { ok: false, reason: `HTTP ${response.status}` };
1875
+ const body = await response.json();
1876
+ return Array.isArray(body.results)
1877
+ ? { ok: true, reason: "" }
1878
+ : { ok: false, reason: "response did not contain a results array" };
1879
+ }
1880
+ catch (error) {
1881
+ return { ok: false, reason: error instanceof Error ? error.message : String(error) };
1882
+ }
1883
+ finally {
1884
+ clearTimeout(timer);
1885
+ }
1886
+ }
1887
+ async function readAgentBrowserVersion(command, input) {
1888
+ const run = input.sdkAuthStatusExecFile ?? defaultSdkAuthStatusExecFile;
1889
+ try {
1890
+ const { stdout } = await run(command, ["--version"], {
1891
+ cwd: input.cwd,
1892
+ env: Object.fromEntries(["PATH", "LANG", "LC_ALL", "LC_CTYPE", "SHELL", "TMPDIR", "TMP", "TEMP"]
1893
+ .flatMap((key) => typeof input.env[key] === "string" ? [[key, input.env[key]]] : [])),
1894
+ timeout: SDK_AUTH_STATUS_TIMEOUT_MS,
1895
+ maxBuffer: SDK_AUTH_STATUS_MAX_BUFFER_BYTES,
1896
+ encoding: "utf8",
1897
+ });
1898
+ const match = /(?:^|\s)v?(\d+)\.(\d+)\.(\d+)(?:\s|$)/u.exec(stdout.trim());
1899
+ if (match === null)
1900
+ return null;
1901
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
1902
+ }
1903
+ catch {
1904
+ return null;
1905
+ }
1906
+ }
1907
+ function compareVersion(left, right) {
1908
+ for (let index = 0; index < 3; index += 1) {
1909
+ if (left[index] !== right[index])
1910
+ return left[index] - right[index];
1911
+ }
1912
+ return 0;
1913
+ }
1764
1914
  async function continuationSection(config, input) {
1765
1915
  let settings;
1766
1916
  try {