@method-ai-hq/sdk 0.0.0-stage → 0.14.2

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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -2
  3. package/dist/packages/contracts/src/identity.d.ts +16 -0
  4. package/dist/packages/contracts/src/identity.js +41 -0
  5. package/dist/packages/contracts/src/method-package.d.ts +71 -0
  6. package/dist/packages/contracts/src/method-package.js +22 -0
  7. package/dist/packages/method-document/src/conversion-report.d.ts +138 -0
  8. package/dist/packages/method-document/src/conversion-report.js +23 -0
  9. package/dist/packages/sdk/examples/daily-briefing/README.md +31 -0
  10. package/dist/packages/sdk/examples/daily-briefing/TASK.md +3 -0
  11. package/dist/packages/sdk/examples/daily-briefing/approved-report.md +138 -0
  12. package/dist/packages/sdk/examples/daily-briefing/briefing_artifacts.py +39 -0
  13. package/dist/packages/sdk/examples/daily-briefing/briefing_check_inputs.py +47 -0
  14. package/dist/packages/sdk/examples/daily-briefing/briefing_files.py +31 -0
  15. package/dist/packages/sdk/examples/daily-briefing/briefing_manifest.py +23 -0
  16. package/dist/packages/sdk/examples/daily-briefing/briefing_markdown.py +67 -0
  17. package/dist/packages/sdk/examples/daily-briefing/briefing_progress.py +18 -0
  18. package/dist/packages/sdk/examples/daily-briefing/briefing_render.py +71 -0
  19. package/dist/packages/sdk/examples/daily-briefing/briefing_sessions.py +37 -0
  20. package/dist/packages/sdk/examples/daily-briefing/briefing_times.py +158 -0
  21. package/dist/packages/sdk/examples/daily-briefing/briefing_validation.py +101 -0
  22. package/dist/packages/sdk/examples/daily-briefing/briefing_website.py +215 -0
  23. package/dist/packages/sdk/examples/daily-briefing/checks.json +19 -0
  24. package/dist/packages/sdk/examples/daily-briefing/daily-briefing.method +158 -0
  25. package/dist/packages/sdk/examples/daily-briefing/inputs.json +1 -0
  26. package/dist/packages/sdk/examples/daily-briefing/package-lock.json +10 -0
  27. package/dist/packages/sdk/examples/daily-briefing/package.json +4 -0
  28. package/dist/packages/sdk/examples/daily-briefing/pyproject.toml +8 -0
  29. package/dist/packages/sdk/examples/daily-briefing/reader/reader.css +35 -0
  30. package/dist/packages/sdk/examples/daily-briefing/reader/reader.js +42 -0
  31. package/dist/packages/sdk/examples/daily-briefing/sample/context.json +1 -0
  32. package/dist/packages/sdk/examples/daily-briefing/sample/documents/document-001.md +219 -0
  33. package/dist/packages/sdk/examples/daily-briefing/sample/media.json +1 -0
  34. package/dist/packages/sdk/examples/daily-briefing/sample/metadata/documents.json +39 -0
  35. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0001.json +49 -0
  36. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0002.json +49 -0
  37. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0003.json +49 -0
  38. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0004.json +49 -0
  39. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0005.json +49 -0
  40. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0006.json +49 -0
  41. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0007.json +49 -0
  42. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0008.json +49 -0
  43. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0009.json +49 -0
  44. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0010.json +49 -0
  45. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0011.json +49 -0
  46. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0012.json +49 -0
  47. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0013.json +49 -0
  48. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0014.json +49 -0
  49. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0015.json +49 -0
  50. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0016.json +49 -0
  51. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0017.json +49 -0
  52. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0018.json +49 -0
  53. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0019.json +49 -0
  54. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0020.json +49 -0
  55. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0021.json +49 -0
  56. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0022.json +49 -0
  57. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0023.json +49 -0
  58. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0024.json +49 -0
  59. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0025.json +49 -0
  60. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0026.json +49 -0
  61. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0027.json +49 -0
  62. package/dist/packages/sdk/examples/daily-briefing/sample/records/chatgpt-0028.json +49 -0
  63. package/dist/packages/sdk/examples/daily-briefing/sample/sessions.json +1 -0
  64. package/dist/packages/sdk/examples/daily-briefing/sample/timeline.jsonl +28 -0
  65. package/dist/packages/sdk/examples/daily-briefing/sample/untimed.jsonl +0 -0
  66. package/dist/packages/sdk/examples/daily-briefing/sample-output.zip +0 -0
  67. package/dist/packages/sdk/examples/daily-briefing/sample-report.md +51 -0
  68. package/dist/packages/sdk/examples/daily-briefing/uv.lock +128 -0
  69. package/dist/packages/sdk/examples/daily-briefing/vendor/marked-LICENSE.md +44 -0
  70. package/dist/packages/sdk/examples/daily-briefing/vendor/marked.mjs +77 -0
  71. package/dist/packages/sdk/examples/files.json +126 -0
  72. package/dist/packages/sdk/examples/message-routing/README.md +23 -0
  73. package/dist/packages/sdk/examples/message-routing/TASK.md +5 -0
  74. package/dist/packages/sdk/examples/message-routing/choose-destination.mjs +10 -0
  75. package/dist/packages/sdk/examples/message-routing/create-ticket.mjs +15 -0
  76. package/dist/packages/sdk/examples/message-routing/inputs.json +1 -0
  77. package/dist/packages/sdk/examples/message-routing/message-routing.method +45 -0
  78. package/dist/packages/sdk/examples/message-routing/result.fixture.json +6 -0
  79. package/dist/packages/sdk/examples/message-routing/routing.mjs +29 -0
  80. package/dist/packages/sdk/examples/message-routing/routing.test.mjs +27 -0
  81. package/dist/packages/sdk/examples/message-routing/ticket.method +88 -0
  82. package/dist/packages/sdk/examples/message-routing/ticket.test.mjs +64 -0
  83. package/dist/packages/sdk/examples/notes-summary/README.md +23 -0
  84. package/dist/packages/sdk/examples/notes-summary/TASK.md +3 -0
  85. package/dist/packages/sdk/examples/notes-summary/cases/dates-in-decisions/case.json +36 -0
  86. package/dist/packages/sdk/examples/notes-summary/cases/dates-in-decisions/examples.json +16 -0
  87. package/dist/packages/sdk/examples/notes-summary/cases/dates-in-decisions/files/0 +10 -0
  88. package/dist/packages/sdk/examples/notes-summary/cases/dates-in-decisions/recording.json +195 -0
  89. package/dist/packages/sdk/examples/notes-summary/notes/2026-10-05-standup.md +4 -0
  90. package/dist/packages/sdk/examples/notes-summary/notes/2026-10-07-planning.md +3 -0
  91. package/dist/packages/sdk/examples/notes-summary/notes-summary.method +54 -0
  92. package/dist/packages/sdk/examples/notes-summary/out/.keep +0 -0
  93. package/dist/packages/sdk/examples/notes-summary/read-notes.mjs +4 -0
  94. package/dist/packages/sdk/examples/notes-summary/save.mjs +7 -0
  95. package/dist/packages/sdk/examples/outbound-management/README.md +119 -0
  96. package/dist/packages/sdk/examples/outbound-management/TASK.md +5 -0
  97. package/dist/packages/sdk/examples/outbound-management/check_plan.py +16 -0
  98. package/dist/packages/sdk/examples/outbound-management/check_sources.py +14 -0
  99. package/dist/packages/sdk/examples/outbound-management/crm.py +153 -0
  100. package/dist/packages/sdk/examples/outbound-management/crm_test.py +141 -0
  101. package/dist/packages/sdk/examples/outbound-management/fixtures/README.md +15 -0
  102. package/dist/packages/sdk/examples/outbound-management/fixtures/crm.json +54 -0
  103. package/dist/packages/sdk/examples/outbound-management/fixtures/day-1/messages.json +29 -0
  104. package/dist/packages/sdk/examples/outbound-management/fixtures/day-2/messages.json +38 -0
  105. package/dist/packages/sdk/examples/outbound-management/fixtures/observations.json +12 -0
  106. package/dist/packages/sdk/examples/outbound-management/fixtures/plan.json +69 -0
  107. package/dist/packages/sdk/examples/outbound-management/fixtures/receipt.json +1 -0
  108. package/dist/packages/sdk/examples/outbound-management/fixtures/state.json +99 -0
  109. package/dist/packages/sdk/examples/outbound-management/fixtures/tasks.md +16 -0
  110. package/dist/packages/sdk/examples/outbound-management/inputs.json +4 -0
  111. package/dist/packages/sdk/examples/outbound-management/outbound.method +277 -0
  112. package/dist/packages/sdk/examples/outbound-management/read_crm.py +4 -0
  113. package/dist/packages/sdk/examples/outbound-management/save_day.py +4 -0
  114. package/dist/packages/sdk/examples/outbound-management/starter/crm.json +11 -0
  115. package/dist/packages/sdk/examples/social-briefing/README.md +41 -0
  116. package/dist/packages/sdk/examples/social-briefing/TASK.md +5 -0
  117. package/dist/packages/sdk/examples/social-briefing/inputs.json +5 -0
  118. package/dist/packages/sdk/examples/social-briefing/result.fixture.json +14 -0
  119. package/dist/packages/sdk/examples/social-briefing/social-briefing.method +110 -0
  120. package/dist/packages/sdk/examples/support-triage/README.md +77 -0
  121. package/dist/packages/sdk/examples/support-triage/TASK.md +3 -0
  122. package/dist/packages/sdk/examples/support-triage/cases/double-charge-to-billing/case.json +40 -0
  123. package/dist/packages/sdk/examples/support-triage/cases/double-charge-to-billing/recording.json +460 -0
  124. package/dist/packages/sdk/examples/support-triage/fake-helpdesk.mjs +38 -0
  125. package/dist/packages/sdk/examples/support-triage/helpdesk.mjs +33 -0
  126. package/dist/packages/sdk/examples/support-triage/inputs.json +1 -0
  127. package/dist/packages/sdk/examples/support-triage/read-ticket.mjs +8 -0
  128. package/dist/packages/sdk/examples/support-triage/route.mjs +4 -0
  129. package/dist/packages/sdk/examples/support-triage/sample-tickets.json +5 -0
  130. package/dist/packages/sdk/examples/support-triage/set-ticket.mjs +9 -0
  131. package/dist/packages/sdk/examples/support-triage/support-triage.method +165 -0
  132. package/dist/packages/sdk/examples/support-triage/triage.mjs +38 -0
  133. package/dist/packages/sdk/examples/support-triage/triage.test.mjs +68 -0
  134. package/dist/packages/sdk/observers/mail.delivery/fetch.mjs +87 -0
  135. package/dist/packages/sdk/observers/mail.delivery/fixtures/bounce-by-recipient.json +1 -0
  136. package/dist/packages/sdk/observers/mail.delivery/fixtures/bounce.json +1 -0
  137. package/dist/packages/sdk/observers/mail.delivery/fixtures/delayed.json +1 -0
  138. package/dist/packages/sdk/observers/mail.delivery/fixtures/delivered.json +1 -0
  139. package/dist/packages/sdk/observers/mail.delivery/fixtures/empty.json +1 -0
  140. package/dist/packages/sdk/observers/mail.delivery/fixtures/other-message.json +1 -0
  141. package/dist/packages/sdk/observers/mail.delivery/judge.mjs +13 -0
  142. package/dist/packages/sdk/observers/mail.delivery/observer.json +14 -0
  143. package/dist/packages/sdk/package.json +232 -0
  144. package/dist/packages/sdk/src/authoring-example.d.ts +91 -0
  145. package/dist/packages/sdk/src/authoring-example.js +50 -0
  146. package/dist/packages/sdk/src/authoring-instructions.d.ts +20 -0
  147. package/dist/packages/sdk/src/authoring-instructions.js +151 -0
  148. package/dist/packages/sdk/src/authoring-prompt.d.ts +2 -0
  149. package/dist/packages/sdk/src/authoring-prompt.js +8 -0
  150. package/dist/packages/sdk/src/authoring.d.ts +10 -0
  151. package/dist/packages/sdk/src/authoring.js +287 -0
  152. package/dist/packages/sdk/src/bindings.d.ts +4 -0
  153. package/dist/packages/sdk/src/bindings.js +124 -0
  154. package/dist/packages/sdk/src/bridge.d.ts +2 -0
  155. package/dist/packages/sdk/src/bridge.js +23 -0
  156. package/dist/packages/sdk/src/browser-runtime/pyproject.toml +5 -0
  157. package/dist/packages/sdk/src/browser-runtime/tools.json +189 -0
  158. package/dist/packages/sdk/src/browser-runtime/uv.lock +3894 -0
  159. package/dist/packages/sdk/src/browser-service.py +127 -0
  160. package/dist/packages/sdk/src/browser.d.ts +38 -0
  161. package/dist/packages/sdk/src/browser.js +203 -0
  162. package/dist/packages/sdk/src/capabilities.d.ts +13 -0
  163. package/dist/packages/sdk/src/capabilities.js +68 -0
  164. package/dist/packages/sdk/src/classification-client.d.ts +4 -0
  165. package/dist/packages/sdk/src/classification-client.js +27 -0
  166. package/dist/packages/sdk/src/cloud.d.ts +23 -0
  167. package/dist/packages/sdk/src/cloud.js +43 -0
  168. package/dist/packages/sdk/src/computer-settings.d.ts +28 -0
  169. package/dist/packages/sdk/src/computer-settings.js +57 -0
  170. package/dist/packages/sdk/src/connect.d.ts +47 -0
  171. package/dist/packages/sdk/src/connect.js +203 -0
  172. package/dist/packages/sdk/src/current-inspection.d.ts +3 -0
  173. package/dist/packages/sdk/src/current-inspection.js +146 -0
  174. package/dist/packages/sdk/src/current-runtime.d.ts +14 -0
  175. package/dist/packages/sdk/src/current-runtime.js +167 -0
  176. package/dist/packages/sdk/src/doctor.d.ts +17 -0
  177. package/dist/packages/sdk/src/doctor.js +68 -0
  178. package/dist/packages/sdk/src/executable.d.ts +2 -0
  179. package/dist/packages/sdk/src/executable.js +22 -0
  180. package/dist/packages/sdk/src/explain-effects.d.ts +32 -0
  181. package/dist/packages/sdk/src/explain-effects.js +192 -0
  182. package/dist/packages/sdk/src/explain.d.ts +115 -0
  183. package/dist/packages/sdk/src/explain.js +441 -0
  184. package/dist/packages/sdk/src/files.d.ts +9 -0
  185. package/dist/packages/sdk/src/files.js +50 -0
  186. package/dist/packages/sdk/src/guard-keys.d.ts +5 -0
  187. package/dist/packages/sdk/src/guard-keys.js +42 -0
  188. package/dist/packages/sdk/src/hosted-models.d.ts +49 -0
  189. package/dist/packages/sdk/src/hosted-models.js +81 -0
  190. package/dist/packages/sdk/src/improve.d.ts +55 -0
  191. package/dist/packages/sdk/src/improve.js +159 -0
  192. package/dist/packages/sdk/src/index.d.ts +13 -0
  193. package/dist/packages/sdk/src/index.js +13 -0
  194. package/dist/packages/sdk/src/inspect.d.ts +6 -0
  195. package/dist/packages/sdk/src/inspect.js +17 -0
  196. package/dist/packages/sdk/src/link.d.ts +12 -0
  197. package/dist/packages/sdk/src/link.js +53 -0
  198. package/dist/packages/sdk/src/local-cli.d.ts +24 -0
  199. package/dist/packages/sdk/src/local-cli.js +146 -0
  200. package/dist/packages/sdk/src/local-setup.d.ts +15 -0
  201. package/dist/packages/sdk/src/local-setup.js +42 -0
  202. package/dist/packages/sdk/src/method-client.d.ts +30 -0
  203. package/dist/packages/sdk/src/method-client.js +250 -0
  204. package/dist/packages/sdk/src/method-files.d.ts +29 -0
  205. package/dist/packages/sdk/src/method-files.js +93 -0
  206. package/dist/packages/sdk/src/method-help.d.ts +19 -0
  207. package/dist/packages/sdk/src/method-help.js +404 -0
  208. package/dist/packages/sdk/src/method-issues.d.ts +86 -0
  209. package/dist/packages/sdk/src/method-issues.js +192 -0
  210. package/dist/packages/sdk/src/method-sync.d.ts +46 -0
  211. package/dist/packages/sdk/src/method-sync.js +293 -0
  212. package/dist/packages/sdk/src/method.d.ts +5 -0
  213. package/dist/packages/sdk/src/method.js +359 -0
  214. package/dist/packages/sdk/src/model-checks.d.ts +96 -0
  215. package/dist/packages/sdk/src/model-checks.js +181 -0
  216. package/dist/packages/sdk/src/outbox.d.ts +120 -0
  217. package/dist/packages/sdk/src/outbox.js +297 -0
  218. package/dist/packages/sdk/src/own-model-key.d.ts +22 -0
  219. package/dist/packages/sdk/src/own-model-key.js +76 -0
  220. package/dist/packages/sdk/src/prepare.d.ts +24 -0
  221. package/dist/packages/sdk/src/prepare.js +245 -0
  222. package/dist/packages/sdk/src/process.d.ts +15 -0
  223. package/dist/packages/sdk/src/process.js +107 -0
  224. package/dist/packages/sdk/src/production.d.ts +182 -0
  225. package/dist/packages/sdk/src/production.js +284 -0
  226. package/dist/packages/sdk/src/progress.d.ts +12 -0
  227. package/dist/packages/sdk/src/progress.js +48 -0
  228. package/dist/packages/sdk/src/proposals.d.ts +73 -0
  229. package/dist/packages/sdk/src/proposals.js +284 -0
  230. package/dist/packages/sdk/src/quality.d.ts +82 -0
  231. package/dist/packages/sdk/src/quality.js +294 -0
  232. package/dist/packages/sdk/src/result-files.d.ts +5 -0
  233. package/dist/packages/sdk/src/result-files.js +149 -0
  234. package/dist/packages/sdk/src/result-transfer.d.ts +21 -0
  235. package/dist/packages/sdk/src/result-transfer.js +37 -0
  236. package/dist/packages/sdk/src/run-data.d.ts +11 -0
  237. package/dist/packages/sdk/src/run-data.js +80 -0
  238. package/dist/packages/sdk/src/run-method.d.ts +2 -0
  239. package/dist/packages/sdk/src/run-method.js +2 -0
  240. package/dist/packages/sdk/src/run-saved.d.ts +5 -0
  241. package/dist/packages/sdk/src/run-saved.js +138 -0
  242. package/dist/packages/sdk/src/run-worker.d.ts +6 -0
  243. package/dist/packages/sdk/src/run-worker.js +131 -0
  244. package/dist/packages/sdk/src/secrets.d.ts +37 -0
  245. package/dist/packages/sdk/src/secrets.js +196 -0
  246. package/dist/packages/sdk/src/update.d.ts +5 -0
  247. package/dist/packages/sdk/src/update.js +39 -0
  248. package/dist/packages/sdk/src/versions.d.ts +58 -0
  249. package/dist/packages/sdk/src/versions.js +144 -0
  250. package/dist/packages/sdk/src/worker.d.ts +120 -0
  251. package/dist/packages/sdk/src/worker.js +443 -0
  252. package/dist/packages/workflow-language/src/execution.d.ts +1 -0
  253. package/dist/packages/workflow-language/src/execution.js +1 -0
  254. package/dist/packages/workflow-language/src/inspection.d.ts +990 -0
  255. package/dist/packages/workflow-language/src/inspection.js +130 -0
  256. package/dist/packages/workflow-language/src/result-files.d.ts +160 -0
  257. package/dist/packages/workflow-language/src/result-files.js +67 -0
  258. package/dist/packages/workflow-language/src/schema.d.ts +207 -0
  259. package/dist/packages/workflow-language/src/schema.js +56 -0
  260. package/dist/packages/workflow-language/src/validate.d.ts +11 -0
  261. package/dist/packages/workflow-language/src/validate.js +77 -0
  262. package/package.json +230 -4
@@ -0,0 +1,287 @@
1
+ import { preflight } from "@withmethod/runtime/preflight.js";
2
+ import { configSchema, methodSchema } from "@withmethod/runtime/schema.js";
3
+ import { isModelId } from "@withmethod/runtime/semantics.js";
4
+ import { localSetup } from "./local-setup.js";
5
+ /** Deterministic local authoring. No model calls, network calls, or workflow execution. */
6
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, unlinkSync } from "node:fs";
7
+ import { dirname, resolve } from "node:path";
8
+ import { renameSync, writeFileSync } from "node:fs";
9
+ import { parseArgs } from "node:util";
10
+ import { CurrentCheckSchema, CurrentStepSchema } from "../../workflow-language/src/schema.js";
11
+ import { loadWorkflow, parseDocumentValue, serializeWorkflow } from "../../workflow-language/src/validate.js";
12
+ export function writeDocument(path, value) { const tmp = `${path}.${process.pid}.tmp`; try {
13
+ writeFileSync(tmp, serializeWorkflow(value), { mode: 0o600, flag: "wx" });
14
+ renameSync(tmp, path);
15
+ }
16
+ finally {
17
+ if (existsSync(tmp))
18
+ unlinkSync(tmp);
19
+ } }
20
+ import { authoringGuide, methodHelp } from "./method-help.js";
21
+ export const authoringHelp = authoringGuide();
22
+ export function authoringPath(path) {
23
+ return resolve(path);
24
+ }
25
+ export const readDocument = (file) => parseDocumentValue(readFileSync(authoringPath(file), "utf8"));
26
+ const own = (v, k) => v !== null && typeof v === "object" && Object.hasOwn(v, k);
27
+ function keys(path) {
28
+ if (!/^(?:\/(?:[^~]|~[01])*)*$/.test(path))
29
+ throw Error("Use a valid JSON Pointer, for example /steps/0/name.");
30
+ return path === "" ? [] : path.slice(1).split("/").map(k => k.replaceAll("~1", "/").replaceAll("~0", "~"));
31
+ }
32
+ export function at(document, path) {
33
+ let node = document;
34
+ for (const key of keys(path)) {
35
+ if (!own(node, key))
36
+ throw Error(`No value at ${path}.`);
37
+ node = node[key];
38
+ }
39
+ return node;
40
+ }
41
+ export function change(document, path, value, remove = false) {
42
+ const parts = keys(path), key = parts.pop();
43
+ if (key === undefined) {
44
+ if (remove)
45
+ throw Error("Cannot remove the whole document.");
46
+ return value;
47
+ }
48
+ const parent = at(document, parts.length ? "/" + parts.map(k => k.replaceAll("~", "~0").replaceAll("/", "~1")).join("/") : "");
49
+ if (!parent || typeof parent !== "object")
50
+ throw Error("The parent must be an object or array.");
51
+ if (Array.isArray(parent)) {
52
+ const index = key === "-" && !remove ? parent.length : /^(0|[1-9][0-9]*)$/.test(key) ? Number(key) : -1;
53
+ if (index < 0 || index > parent.length || remove && index === parent.length)
54
+ throw Error("Invalid array position.");
55
+ if (remove)
56
+ parent.splice(index, 1);
57
+ else
58
+ parent[index] = value;
59
+ }
60
+ else {
61
+ if (remove) {
62
+ if (!own(parent, key))
63
+ throw Error(`No value at ${path}.`);
64
+ delete parent[key];
65
+ }
66
+ else
67
+ Object.defineProperty(parent, key, { value, enumerable: true, writable: true, configurable: true });
68
+ }
69
+ return document;
70
+ }
71
+ /** Read, change, and replace the file in one rename. */
72
+ export function editDocument(file, edit) {
73
+ const path = authoringPath(file);
74
+ const result = edit(readDocument(path));
75
+ writeDocument(path, result);
76
+ return result;
77
+ }
78
+ export function differences(a, b, path = "") {
79
+ if (JSON.stringify(a) === JSON.stringify(b))
80
+ return [];
81
+ if (a && b && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b))
82
+ return [...new Set([...Object.keys(a), ...Object.keys(b)])].flatMap(k => differences(a[k], b[k], path + "/" + k.replaceAll("~", "~0").replaceAll("/", "~1")));
83
+ return [{ path, ...(a !== undefined ? { before: a } : {}), ...(b !== undefined ? { after: b } : {}) }];
84
+ }
85
+ export async function localAuthoring(args) {
86
+ const command = args[0];
87
+ const stepEdit = command === "step" && ["add", "update", "remove", "move"].includes(args[1] ?? "");
88
+ if (!stepEdit && !["authoring", "init", "show", "set", "remove", "check", "validate", "diff", "schema"].includes(command ?? ""))
89
+ return false;
90
+ if (args.includes("--help")) {
91
+ process.stdout.write(methodHelp(args));
92
+ return true;
93
+ }
94
+ if (command === "authoring") {
95
+ if (args.length > 3 || args.length === 3 && args[1] !== 'example')
96
+ throw Error("Use method authoring [TOPIC] or method authoring example EXAMPLE_ID.");
97
+ process.stdout.write(authoringGuide(args[1], args[2]));
98
+ return true;
99
+ }
100
+ const { values: v, positionals: p } = parseArgs({ args: args.slice(1), allowPositionals: true, options: Object.fromEntries([...["name", "goal", "id", "instructions-file", "json", "value-file", "text", "text-file", "path", "before", "model", "purpose", "kind", "runtime", "entrypoint", "workspace"].map(k => [k, { type: "string" }]),
101
+ // validate and check read these two flags from args.
102
+ ["notes", { type: "boolean" }], ["all", { type: "boolean" }]]) });
103
+ const print = (value) => process.stdout.write(JSON.stringify(value, null, 2) + "\n");
104
+ const value = () => {
105
+ const sources = ["json", "value-file", "text", "text-file"].filter(k => v[k] !== undefined);
106
+ if (sources.length !== 1)
107
+ throw Error("Supply exactly one of --json, --value-file, --text, or --text-file.");
108
+ return v.json !== undefined ? JSON.parse(v.json) : v["value-file"] ? readDocument(v["value-file"]) : v.text !== undefined ? v.text : readFileSync(authoringPath(v["text-file"]), "utf8");
109
+ };
110
+ if (command === "schema") {
111
+ // The short reference is enough to write a Method; the JSON schemas are for tools.
112
+ if (!p[0]) {
113
+ process.stdout.write((await import("./authoring-instructions.js")).fieldReference);
114
+ return true;
115
+ }
116
+ if (["method", "config"].includes(p[0])) {
117
+ print(p[0] === "config" ? configSchema : methodSchema);
118
+ return true;
119
+ }
120
+ const schemas = { method: methodSchema, config: configSchema,
121
+ ...Object.fromEntries(["step", "check", "data"].map(name => [name, { $schema: methodSchema.$schema, $defs: methodSchema.$defs, $ref: `#/$defs/${name}` }])),
122
+ environment: { ...methodSchema.properties.environment.additionalProperties } };
123
+ const schema = schemas[p[0] ?? "method"];
124
+ if (!schema)
125
+ throw Error("Unknown schema. See method authoring.");
126
+ print(schema);
127
+ return true;
128
+ }
129
+ const file = stepEdit || command === "check" && ["set", "remove"].includes(p[0] ?? "") ? p[1] : p[0];
130
+ if (!file)
131
+ throw Error(`Supply a Method file. Read method ${command} --help.`);
132
+ if (command === "init") {
133
+ if (!v.name || !v.goal)
134
+ throw Error("Supply --name and --goal.");
135
+ const path = authoringPath(file);
136
+ if (existsSync(path))
137
+ throw Error("Choose a new draft file.");
138
+ const draft = { format: "method/3.4", name: v.name, goal: v.goal, steps: {}, result: {} };
139
+ // Exclusive creation prevents simultaneous init from replacing a draft.
140
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
141
+ const fd = openSync(path, "wx", 0o600);
142
+ closeSync(fd);
143
+ writeDocument(path, draft);
144
+ print({ file: path, workflow: draft });
145
+ return true;
146
+ }
147
+ if (command === "validate") {
148
+ let definition = "invalid";
149
+ const { collectIssues, shownIssues } = await import("./method-issues.js");
150
+ const flags = { notes: args.includes("--notes"), all: args.includes("--all") };
151
+ try {
152
+ const report = await collectIssues(file);
153
+ const shown = shownIssues(report, flags);
154
+ if (report.issues.some(issue => issue.level === "error")) {
155
+ print({ valid: false, definition: report.invalid ? "invalid" : "valid", executed: false, ...shown });
156
+ process.exitCode = 1;
157
+ return true;
158
+ }
159
+ const workflow = loadWorkflow((await import("./versions.js")).methodContent(readDocument(file)));
160
+ definition = "valid";
161
+ const { config, sourceRoot, agent } = await localSetup(file, v);
162
+ const declared = Object.keys(workflow.secrets ?? {});
163
+ const secrets = (await import('./secrets.js')).resolveSecrets(declared);
164
+ const { MethodClient } = await import("./method-client.js");
165
+ const client = new MethodClient();
166
+ const signedIn = (() => { try {
167
+ return !!client.token();
168
+ }
169
+ catch {
170
+ return false;
171
+ } })();
172
+ // A missing secret is the missing_secret issue, so preflight gets a stand-in for it. With a saved sign-in,
173
+ // classification and hosted models use the account, as in method run.
174
+ const signedInOptions = signedIn ? { classification: (await import("./classification-client.js")).managedClassification(client), hostedModels: (await import("./hosted-models.js")).managedModels(client) } : {};
175
+ // The run resolves the account's classifier version; validate checks only that it can.
176
+ if (signedIn && !config.classification)
177
+ config.classification = { provider: "typesafe", model: (await import("@withmethod/runtime/classification.js")).typesafeModel };
178
+ const { files, missingSetup } = await preflight(workflow, config, sourceRoot, { allowMissingSetup: true, secrets: { ...Object.fromEntries(declared.map(name => [name, "missing"])), ...secrets }, ...signedInOptions });
179
+ // What each step executes, and what it still needs on this computer.
180
+ const missingSecrets = declared.filter(name => !secrets[name]);
181
+ const ownKey = (await import("./own-model-key.js")).ownKeyEnv();
182
+ const steps = Object.entries(workflow.steps).map(([id, step]) => {
183
+ const exec = step.do, named = workflow.models?.[exec?.model] ?? (isModelId(exec?.model) ? exec.model : undefined);
184
+ const profile = named?.agent ? { backend: named.agent, model: named.model } : named ? { backend: "method", model: typeof named === "string" ? named : named.model } : config.models?.[exec?.model] ?? (exec?.model === "default" ? undefined : config.models?.default);
185
+ const runs = step.ask ? "asks the user"
186
+ : exec.kind === "run" ? `${exec.runtime} ${exec.entrypoint}`
187
+ : exec.kind === "classify" ? (config.classification?.api_key_env || ownKey ? "Jev through OpenRouter with your own key" : "Method's classifier")
188
+ : profile?.backend === "method" ? (ownKey && !agent ? `${profile.model} through OpenRouter with your own key` : `the hosted model ${profile.model}`)
189
+ : profile ? `${profile.backend}${profile.model ? ` ${profile.model}` : ""}`
190
+ : signedIn ? (ownKey && !agent ? "the account's default model through OpenRouter with your own key" : "the account's hosted model") : "a local Codex or Claude agent";
191
+ const needs = [...(exec?.kind === "run" ? missingSecrets.map(name => `secret ${name}`) : []),
192
+ ...(!signedIn && (exec?.kind === "classify" && !config.classification?.api_key_env && !ownKey || ["call", "agent"].includes(exec?.kind) && !profile) ? [`method login (for ${exec.kind === "classify" ? "classification" : "hosted models"})`] : [])];
193
+ return { id, runs, ...(needs.length ? { needs } : {}) };
194
+ });
195
+ print({ valid: true, definition, local_setup: missingSetup.length ? "needs_preparation" : "valid", ...(missingSetup.length ? { missing_setup: [...new Set(missingSetup)] } : {}), workspace: sourceRoot, files: files.length, steps, executed: false, ...shown });
196
+ }
197
+ catch (error) {
198
+ // A setup error from preflight is an error issue too.
199
+ const issue = { level: "error", code: error?.code ?? "invalid_method", message: error instanceof Error ? error.message : String(error), fix: "Fix what the message names, then validate again." };
200
+ print({ valid: false, definition, local_setup: definition === "valid" ? "invalid" : "not_checked", executed: false, error: issue.message, issues: [issue], issue_counts: { errors: 1, warnings: 0, notes: 0, accepted: 0 } });
201
+ process.exitCode = 1;
202
+ }
203
+ return true;
204
+ }
205
+ if (command === "check" && /\.(method|json)$/i.test(file) && !p[2]) {
206
+ // method check FILE: only the issues, without the local setup.
207
+ const { collectIssues, shownIssues } = await import("./method-issues.js");
208
+ const report = await collectIssues(file);
209
+ const errors = report.issues.some(issue => issue.level === "error");
210
+ print({ valid: !errors, ...shownIssues(report, { notes: args.includes("--notes"), all: args.includes("--all") }) });
211
+ if (errors)
212
+ process.exitCode = 1;
213
+ return true;
214
+ }
215
+ if (command === "show") {
216
+ print(at(readDocument(file), v.path ?? ""));
217
+ return true;
218
+ }
219
+ if (command === "diff") {
220
+ if (!p[1])
221
+ throw Error("Supply two files.");
222
+ print(differences(readDocument(file), readDocument(p[1])));
223
+ return true;
224
+ }
225
+ const result = editDocument(file, doc => {
226
+ if (command === "set" || command === "remove") {
227
+ if (p[1] === undefined)
228
+ throw Error("Supply a JSON Pointer.");
229
+ return change(doc, p[1], command === "set" ? value() : undefined, command === "remove");
230
+ }
231
+ if (!doc.steps || Array.isArray(doc.steps) || typeof doc.steps !== "object")
232
+ throw Error("The draft needs a steps map.");
233
+ const action = p[0], id = p[2];
234
+ if (stepEdit) {
235
+ if (action === "add") {
236
+ if (!v.id)
237
+ throw Error("Supply --id.");
238
+ if (Object.hasOwn(doc.steps, v.id))
239
+ throw Error("That step already exists.");
240
+ {
241
+ if (v["value-file"] || v.json)
242
+ doc.steps[v.id] = CurrentStepSchema.parse(value());
243
+ else {
244
+ const kind = v.kind ?? "agent";
245
+ const execution = kind === "run" ? { kind, runtime: v.runtime, entrypoint: v.entrypoint } : { kind, model: v.model ?? "default", prompt: v["instructions-file"] ? readFileSync(authoringPath(v["instructions-file"]), "utf8") : undefined, ...(kind === "agent" ? { tools: [] } : {}) };
246
+ doc.steps[v.id] = CurrentStepSchema.parse({ ...(v.name ? { name: v.name } : {}), ...(v.purpose ? { purpose: v.purpose } : {}), do: execution });
247
+ }
248
+ }
249
+ }
250
+ else {
251
+ if (!id || !Object.hasOwn(doc.steps, id))
252
+ throw Error("Step not found.");
253
+ if (action === "remove")
254
+ delete doc.steps[id];
255
+ else if (action === "update") {
256
+ const patch = value();
257
+ if (!patch || Array.isArray(patch) || typeof patch !== "object")
258
+ throw Error("Supply step fields.");
259
+ doc.steps[id] = CurrentStepSchema.parse({ ...doc.steps[id], ...patch });
260
+ }
261
+ else {
262
+ if (!v.before || !Object.hasOwn(doc.steps, v.before))
263
+ throw Error("Supply --before with a step ID.");
264
+ if (v.before !== id) {
265
+ const entries = Object.entries(doc.steps).filter(([key]) => key !== id);
266
+ const at = entries.findIndex(([key]) => key === v.before);
267
+ entries.splice(at, 0, [id, doc.steps[id]]);
268
+ doc.steps = Object.fromEntries(entries);
269
+ }
270
+ }
271
+ }
272
+ }
273
+ else {
274
+ if (!id || !Object.hasOwn(doc.steps, id))
275
+ throw Error("Step not found.");
276
+ if (action === "remove")
277
+ delete doc.steps[id].check;
278
+ else if (action === "set")
279
+ doc.steps[id].check = CurrentCheckSchema.parse(value());
280
+ else
281
+ throw Error("Use check set or check remove.");
282
+ }
283
+ return doc;
284
+ });
285
+ print({ file: resolve(file), workflow: result });
286
+ return true;
287
+ }
@@ -0,0 +1,4 @@
1
+ import type { MethodClient } from './method-client.js';
2
+ export declare function bindInput(client: MethodClient, idOrFile: string, name: string, path: string, upload?: boolean): Promise<any>;
3
+ export declare function bindConnection(client: MethodClient, idOrFile: string, name: string, value: string, upload?: boolean): Promise<any>;
4
+ export declare function resolveBindings(client: MethodClient, id: string, method: any, config: any, root: string, runDirectory: string): Promise<any>;
@@ -0,0 +1,124 @@
1
+ import { existsSync, readFileSync, readdirSync, lstatSync, realpathSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve, dirname, relative, isAbsolute } from 'node:path';
3
+ import { packagePath } from '../../contracts/src/method-package.js';
4
+ import { fileHash } from './method-files.js';
5
+ import { writePrivateJson } from './files.js';
6
+ import { bindConnectionValue, readComputerSettings } from './computer-settings.js';
7
+ import { ensureMethodId } from './versions.js';
8
+ import { readDocument } from './authoring.js';
9
+ /** A Method by ID (its saved definition) or by local FILE (its id: line is written when it has none). */
10
+ async function target(client, idOrFile) {
11
+ if (/\.method$/i.test(idOrFile) && existsSync(idOrFile)) {
12
+ const id = ensureMethodId(idOrFile);
13
+ return { id, workflow: readDocument(idOrFile) };
14
+ }
15
+ if (!client.token())
16
+ throw Error('Use the Method FILE, or sign in with method login to bind a saved Method by ID.');
17
+ return { id: idOrFile, workflow: (await client.request(`/api/cli/methods/${encodeURIComponent(idOrFile)}`)).workflow };
18
+ }
19
+ export async function bindInput(client, idOrFile, name, path, upload = false) {
20
+ if (!/^[a-z][a-z0-9_]*$/.test(name))
21
+ throw Error('Use the environment binding name.');
22
+ const { id, workflow } = await target(client, idOrFile);
23
+ if (workflow.environment?.[name]?.type !== 'files')
24
+ throw Error('Use the name of a declared files binding.');
25
+ const root = realpathSync(resolve(path));
26
+ if (!upload) {
27
+ bindConnectionValue(id, name, root);
28
+ return { saved: true, scope: 'this computer', method_id: id, name };
29
+ }
30
+ const files = [];
31
+ async function walk(dir, prefix = '') {
32
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
33
+ // Do not enumerate protected trees. The upload is only the explicitly chosen folder.
34
+ if (['.git', '.codex', '.claude', 'node_modules', '.venv'].includes(entry.name) || entry.name.startsWith('.env') || entry.name === 'secrets.env')
35
+ continue;
36
+ const name = prefix + entry.name;
37
+ packagePath(name);
38
+ const path = join(dir, entry.name);
39
+ if (entry.isSymbolicLink())
40
+ throw Error(`Input contains a symbolic link: ${name}`);
41
+ if (entry.isDirectory())
42
+ await walk(path, name + '/');
43
+ else if (entry.isFile()) {
44
+ const bytes = readFileSync(path);
45
+ if (bytes.length > 20_000_000)
46
+ throw Error(`Input file exceeds 20 MB: ${name}`);
47
+ const hash = fileHash(bytes);
48
+ await client.transfer(`/api/cli/files/${hash}`, bytes);
49
+ files.push({ path: name, sha256: hash, size: bytes.length });
50
+ }
51
+ }
52
+ }
53
+ await walk(root);
54
+ return client.request(`/api/cli/methods/${encodeURIComponent(id)}/bindings/${name}`, 'PUT', { kind: 'files', files });
55
+ }
56
+ export async function bindConnection(client, idOrFile, name, value, upload = false) {
57
+ const { id, workflow } = await target(client, idOrFile);
58
+ if (!workflow.environment?.[name] || workflow.environment[name].type === 'files')
59
+ throw Error('Use a declared service, browser, desktop, or tool binding.');
60
+ // Values identify a connection. Credentials remain in the service's existing login store.
61
+ if (workflow.environment[name].type === 'browser' && /^method-browser:[a-z][a-z0-9_-]*$/.test(value)) {
62
+ if (upload)
63
+ throw Error('Browser selection is private to this computer.');
64
+ bindConnectionValue(id, name, value);
65
+ return { saved: true, scope: 'this computer', method_id: id, name };
66
+ }
67
+ const url = new URL(value);
68
+ if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password || url.search || url.hash)
69
+ throw Error('Use a connection URL without credentials, query parameters, or a fragment.');
70
+ if (upload)
71
+ return client.request(`/api/cli/methods/${encodeURIComponent(id)}/bindings/${name}`, 'PUT', { kind: 'connection', value: url.href });
72
+ bindConnectionValue(id, name, url.href);
73
+ return { saved: true, scope: 'this computer', method_id: id, name };
74
+ }
75
+ export async function resolveBindings(client, id, method, config, root, runDirectory) {
76
+ const local = readComputerSettings().bindings[id] ?? {};
77
+ const snapshot = join(runDirectory, 'input-bindings.json');
78
+ const remote = existsSync(snapshot) ? JSON.parse(readFileSync(snapshot, 'utf8')) : await client.request(`/api/cli/methods/${encodeURIComponent(id)}/bindings`);
79
+ const environment = { ...config.environment }, missing = [];
80
+ for (const [name, definition] of Object.entries(method.environment ?? {})) {
81
+ if (definition.type === 'browser' && !local[name] && !remote[name] && !environment[name]) {
82
+ environment[name] = 'method-browser:default';
83
+ continue;
84
+ }
85
+ if (local[name] && (definition.type !== 'files' || existsSync(local[name]))) {
86
+ environment[name] = local[name];
87
+ continue;
88
+ }
89
+ if (environment[name]) {
90
+ if (definition.type === 'files')
91
+ environment[name] = resolve(root, environment[name]);
92
+ continue;
93
+ }
94
+ if (remote[name]?.kind === 'connection') {
95
+ environment[name] = remote[name].value;
96
+ continue;
97
+ }
98
+ if (remote[name]?.kind === 'files') {
99
+ const folder = join(runDirectory, 'inputs', name);
100
+ mkdirSync(folder, { recursive: true, mode: 0o700 });
101
+ for (const f of remote[name].files) {
102
+ const target = join(folder, packagePath(f.path));
103
+ mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
104
+ const parent = relative(realpathSync(folder), realpathSync(dirname(target)));
105
+ if (parent.startsWith('..') || isAbsolute(parent) || existsSync(target) && lstatSync(target).isSymbolicLink())
106
+ throw Error('Input destination leaves the run folder.');
107
+ if (existsSync(target) && fileHash(readFileSync(target)) === f.sha256)
108
+ continue;
109
+ const bytes = await client.transfer(`/api/cli/methods/${encodeURIComponent(id)}/bindings/${name}/files/${f.sha256}`);
110
+ if (fileHash(bytes) !== f.sha256 || bytes.length !== f.size)
111
+ throw Error(`Input checksum failed: ${f.path}`);
112
+ writeFileSync(target, bytes, { mode: 0o600 });
113
+ }
114
+ environment[name] = folder;
115
+ continue;
116
+ }
117
+ missing.push({ name, description: definition.description, command: definition.type === 'files' ? `method bind ${id} ${name} --file PATH` : `method bind ${id} ${name} --connection URL`, ...(definition.type === 'files' ? { account_copy: `Add --upload only to save this selected input folder privately in your Method account.` } : {}) });
118
+ }
119
+ if (missing.length)
120
+ throw Object.assign(new Error('Supply the missing Method inputs or connections.'), { code: 'needs_input', missing });
121
+ if (!existsSync(snapshot))
122
+ writePrivateJson(snapshot, remote);
123
+ return { ...config, environment };
124
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ /** Python calls the same current runtime; no callback executor or second interpreter. */
3
+ import { createInterface } from "node:readline";
4
+ import { z } from "zod";
5
+ import { runMethod } from "./run-method.js";
6
+ import { authoringPath } from "./authoring.js";
7
+ import { loadWorkflow } from "../../workflow-language/src/validate.js";
8
+ import { renderPrompt } from "../../method-document/src/conversion-report.js";
9
+ const lines = createInterface({ input: process.stdin, terminal: false });
10
+ const send = (value) => process.stdout.write(JSON.stringify(value) + "\n");
11
+ async function main() {
12
+ const first = await lines[Symbol.asyncIterator]().next();
13
+ if (first.done)
14
+ throw Error("The bridge needs one JSON request.");
15
+ const message = z.object({ op: z.enum(["load", "prompt", "run_method"]), workflow: z.unknown().optional() }).passthrough().parse(JSON.parse(first.value));
16
+ if (message.op === "load")
17
+ return loadWorkflow(message.workflow);
18
+ if (message.op === "prompt")
19
+ return renderPrompt(loadWorkflow(message.workflow));
20
+ const data = z.object({ file: z.string(), config: z.record(z.unknown()), options: z.record(z.unknown()).default({}) }).parse(message);
21
+ return runMethod(authoringPath(data.file), data.config, { ...data.options, onEvent: (event) => { send({ type: "event", event }); } });
22
+ }
23
+ main().then(result => send({ type: "result", result }), error => { send({ type: "error", error: error instanceof Error ? error.message : String(error) }); process.exitCode = 1; }).finally(() => lines.close());
@@ -0,0 +1,5 @@
1
+ [project]
2
+ name = "method-browser"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.12,<3.13"
5
+ dependencies = ["browser-use==0.13.10", "mcp==2.1.1"]
@@ -0,0 +1,189 @@
1
+ [
2
+ {
3
+ "name": "browser_navigate",
4
+ "description": "Navigate to a URL in the browser",
5
+ "inputSchema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "url": {
9
+ "type": "string",
10
+ "description": "The URL to navigate to"
11
+ },
12
+ "new_tab": {
13
+ "type": "boolean",
14
+ "description": "Whether to open in a new tab",
15
+ "default": false
16
+ }
17
+ },
18
+ "required": [
19
+ "url"
20
+ ]
21
+ }
22
+ },
23
+ {
24
+ "name": "browser_click",
25
+ "description": "Click an element by index or at specific viewport coordinates. Use index for elements from browser_get_state, or coordinate_x/coordinate_y for pixel-precise clicking.",
26
+ "inputSchema": {
27
+ "type": "object",
28
+ "properties": {
29
+ "index": {
30
+ "type": "integer",
31
+ "description": "The index of the element to click (from browser_get_state). Provide this OR coordinate_x+coordinate_y."
32
+ },
33
+ "coordinate_x": {
34
+ "type": "integer",
35
+ "description": "X coordinate in pixels from the left edge of the viewport. Must be used together with coordinate_y. Provide this OR index."
36
+ },
37
+ "coordinate_y": {
38
+ "type": "integer",
39
+ "description": "Y coordinate in pixels from the top edge of the viewport. Must be used together with coordinate_x. Provide this OR index."
40
+ },
41
+ "new_tab": {
42
+ "type": "boolean",
43
+ "description": "Whether to open any resulting navigation in a new tab",
44
+ "default": false
45
+ }
46
+ }
47
+ }
48
+ },
49
+ {
50
+ "name": "browser_type",
51
+ "description": "Type text into an input field. Clears existing text by default; pass text=\"\" to clear only.",
52
+ "inputSchema": {
53
+ "type": "object",
54
+ "properties": {
55
+ "index": {
56
+ "type": "integer",
57
+ "description": "The index of the input element (from browser_get_state)"
58
+ },
59
+ "text": {
60
+ "type": "string",
61
+ "description": "The text to type. Pass an empty string (\"\") to clear the field without typing."
62
+ }
63
+ },
64
+ "required": [
65
+ "index",
66
+ "text"
67
+ ]
68
+ }
69
+ },
70
+ {
71
+ "name": "browser_get_state",
72
+ "description": "Get the current state of the page including all interactive elements",
73
+ "inputSchema": {
74
+ "type": "object",
75
+ "properties": {
76
+ "include_screenshot": {
77
+ "type": "boolean",
78
+ "description": "Whether to include a screenshot of the current page",
79
+ "default": false
80
+ }
81
+ }
82
+ },
83
+ "annotations": {
84
+ "readOnlyHint": true
85
+ }
86
+ },
87
+ {
88
+ "name": "browser_get_html",
89
+ "description": "Get the raw HTML of the current page or a specific element by CSS selector",
90
+ "inputSchema": {
91
+ "type": "object",
92
+ "properties": {
93
+ "selector": {
94
+ "type": "string",
95
+ "description": "Optional CSS selector to get HTML of a specific element. If omitted, returns full page HTML."
96
+ }
97
+ }
98
+ },
99
+ "annotations": {
100
+ "readOnlyHint": true
101
+ }
102
+ },
103
+ {
104
+ "name": "browser_screenshot",
105
+ "description": "Take a screenshot of the current page. Returns viewport metadata as text and the screenshot as an image.",
106
+ "inputSchema": {
107
+ "type": "object",
108
+ "properties": {
109
+ "full_page": {
110
+ "type": "boolean",
111
+ "description": "Whether to capture the full scrollable page or just the visible viewport",
112
+ "default": false
113
+ }
114
+ }
115
+ },
116
+ "annotations": {
117
+ "readOnlyHint": true
118
+ }
119
+ },
120
+ {
121
+ "name": "browser_scroll",
122
+ "description": "Scroll the page",
123
+ "inputSchema": {
124
+ "type": "object",
125
+ "properties": {
126
+ "direction": {
127
+ "type": "string",
128
+ "enum": [
129
+ "up",
130
+ "down"
131
+ ],
132
+ "description": "Direction to scroll",
133
+ "default": "down"
134
+ }
135
+ }
136
+ }
137
+ },
138
+ {
139
+ "name": "browser_go_back",
140
+ "description": "Go back to the previous page",
141
+ "inputSchema": {
142
+ "type": "object",
143
+ "properties": {}
144
+ }
145
+ },
146
+ {
147
+ "name": "browser_list_tabs",
148
+ "description": "List all open tabs",
149
+ "inputSchema": {
150
+ "type": "object",
151
+ "properties": {}
152
+ },
153
+ "annotations": {
154
+ "readOnlyHint": true
155
+ }
156
+ },
157
+ {
158
+ "name": "browser_switch_tab",
159
+ "description": "Switch to a different tab",
160
+ "inputSchema": {
161
+ "type": "object",
162
+ "properties": {
163
+ "tab_id": {
164
+ "type": "string",
165
+ "description": "4 Character Tab ID of the tab to switch to"
166
+ }
167
+ },
168
+ "required": [
169
+ "tab_id"
170
+ ]
171
+ }
172
+ },
173
+ {
174
+ "name": "browser_close_tab",
175
+ "description": "Close a tab",
176
+ "inputSchema": {
177
+ "type": "object",
178
+ "properties": {
179
+ "tab_id": {
180
+ "type": "string",
181
+ "description": "4 Character Tab ID of the tab to close"
182
+ }
183
+ },
184
+ "required": [
185
+ "tab_id"
186
+ ]
187
+ }
188
+ }
189
+ ]