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

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,42 @@
1
+ import { browserConfig } from './browser.js';
2
+ import { existsSync, statSync } from "node:fs";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { readDocument } from "@withmethod/runtime/io.js";
5
+ import { validateConfig } from "@withmethod/runtime/validate.js";
6
+ import { authoringPath } from "./authoring.js";
7
+ import { readComputerSettings } from "./computer-settings.js";
8
+ import { typesafeModel } from "@withmethod/runtime/classification.js";
9
+ /**
10
+ * The runtime configuration for a local Method. No file beside the Method is read: models come from the Method,
11
+ * limits and tools from the Method (tools are copied into the configuration), connections and an own classifier key from this computer (computer.json), and
12
+ * runtimes from PATH. A files connection with no
13
+ * binding uses the folder of the same name beside the Method, when it exists.
14
+ * `base` is a configuration that the SDK made itself (a saved version's package); bindings still apply.
15
+ */
16
+ export async function localSetup(file, flags, base) {
17
+ const path = authoringPath(file), folder = dirname(path);
18
+ const sourceRoot = authoringPath(flags.workspace ?? folder);
19
+ const settings = readComputerSettings();
20
+ const method = await readDocument(path);
21
+ const config = base ? structuredClone(base) : { allow_local_processes: true };
22
+ config.allow_local_processes = true;
23
+ if (settings.classification_key_env && !config.classification)
24
+ config.classification = { provider: 'typesafe', model: typesafeModel, api_key_env: settings.classification_key_env };
25
+ const bound = typeof method.id === 'string' ? settings.bindings[method.id] ?? {} : {};
26
+ const environment = { ...config.environment };
27
+ for (const [name, definition] of Object.entries(method.environment ?? {})) {
28
+ if (bound[name])
29
+ environment[name] = definition.type === 'files' ? authoringPath(resolve(folder, bound[name])) : bound[name];
30
+ else if (environment[name] && definition.type === 'files')
31
+ environment[name] = authoringPath(resolve(sourceRoot, environment[name]));
32
+ else if (!environment[name] && definition.type === 'files' && existsSync(join(folder, name)) && statSync(join(folder, name)).isDirectory())
33
+ environment[name] = join(folder, name);
34
+ }
35
+ if (Object.keys(environment).length)
36
+ config.environment = environment;
37
+ // A method/3.4 document declares its own tools; the runtime reads tools from the configuration.
38
+ if (method.tools && Object.keys(method.tools).length)
39
+ config.tools = { ...config.tools, ...method.tools };
40
+ validateConfig(config);
41
+ return { config: browserConfig(method, config), sourceRoot, agent: flags.agent ?? settings.agent };
42
+ }
@@ -0,0 +1,30 @@
1
+ export declare const DEFAULT_SERVER: string;
2
+ export declare function serverOrigin(value: string): string;
3
+ export declare class MethodClient {
4
+ readonly fetcher: typeof fetch;
5
+ readonly server: string;
6
+ readonly credentialFile: string;
7
+ constructor(server?: string, fetcher?: typeof fetch, configRoot?: string);
8
+ token(): string | null;
9
+ /**
10
+ * One request. There is no fixed total timeout: the request stops only when no bytes move (sent or received) for
11
+ * stallMs (default 15 s). onProgress receives the number of bytes sent so far.
12
+ */
13
+ request<T = any>(path: string, method?: string, body?: unknown, authenticated?: boolean, options?: {
14
+ signal?: AbortSignal;
15
+ stallMs?: number;
16
+ maxResponseBytes?: number;
17
+ onProgress?: (sent: number) => void;
18
+ }): Promise<T>;
19
+ /** Upload (data) or download bytes. Retries a lost connection or a server error twice; stops only when no bytes move. */
20
+ transfer(path: string, data?: Uint8Array, options?: {
21
+ stallMs?: number;
22
+ onProgress?: (sent: number) => void;
23
+ attempts?: number;
24
+ }): Promise<Uint8Array>;
25
+ /** Send bytes in chunks and read the answer in chunks; a watchdog aborts when no bytes moved for stallMs. */
26
+ private send;
27
+ login(openBrowser?: (url: string) => void): Promise<void>;
28
+ logout(): Promise<void>;
29
+ }
30
+ export declare function openUrl(url: string): void;
@@ -0,0 +1,250 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { spawn } from "node:child_process";
3
+ import { randomBytes } from "node:crypto";
4
+ import { existsSync, readFileSync, rmSync } from "node:fs";
5
+ import { hostname } from "node:os";
6
+ import { configRoot as defaultConfigRoot } from "./computer-settings.js";
7
+ import { join } from "node:path";
8
+ import { z } from "zod";
9
+ import { sha256 } from "../../contracts/src/identity.js";
10
+ import { writePrivateJson } from "./files.js";
11
+ // METHOD_SERVER selects another server (staging, or a local server in tests) for every command.
12
+ export const DEFAULT_SERVER = process.env.METHOD_SERVER || "https://app.withmethod.ai";
13
+ export function serverOrigin(value) {
14
+ const url = new URL(value);
15
+ if (url.username ||
16
+ url.password ||
17
+ url.search ||
18
+ url.hash ||
19
+ url.pathname !== "/" ||
20
+ (url.protocol !== "https:" &&
21
+ !(url.protocol === "http:" &&
22
+ ["127.0.0.1", "localhost", "[::1]"].includes(url.hostname))))
23
+ throw Error("Use an HTTPS Method server, or a loopback URL for local development.");
24
+ return url.origin;
25
+ }
26
+ // Upload chunk size: progress is seen at least once per chunk.
27
+ const chunkBytes = 64 * 1024;
28
+ const Credential = z.object({
29
+ server: z.string(),
30
+ token: z.string().regex(/^method_[A-Za-z0-9_-]{43}$/),
31
+ });
32
+ export class MethodClient {
33
+ fetcher;
34
+ server;
35
+ credentialFile;
36
+ constructor(server = DEFAULT_SERVER, fetcher = fetch, configRoot = defaultConfigRoot()) {
37
+ this.fetcher = fetcher;
38
+ this.server = serverOrigin(server);
39
+ this.credentialFile = join(configRoot, `${sha256(this.server).slice(0, 24)}.json`);
40
+ }
41
+ token() {
42
+ // A service key in METHOD_API_KEY signs a production worker in without a saved sign-in.
43
+ if (process.env.METHOD_API_KEY)
44
+ return process.env.METHOD_API_KEY;
45
+ const file = this.credentialFile;
46
+ if (!file || !existsSync(file))
47
+ return null;
48
+ const saved = Credential.parse(JSON.parse(readFileSync(file, "utf8")));
49
+ if (saved.server !== this.server)
50
+ throw Error("The saved Method sign-in belongs to another server.");
51
+ return saved.token;
52
+ }
53
+ /**
54
+ * One request. There is no fixed total timeout: the request stops only when no bytes move (sent or received) for
55
+ * stallMs (default 15 s). onProgress receives the number of bytes sent so far.
56
+ */
57
+ async request(path, method = "GET", body, authenticated = true, options = {}) {
58
+ if (!path.startsWith("/") || path.startsWith("//"))
59
+ throw Error("Use a Method API path.");
60
+ const token = authenticated ? this.token() : null;
61
+ if (authenticated && !token)
62
+ throw Error("Sign in with method login first.");
63
+ const data = body === undefined ? undefined : JSON.stringify(body);
64
+ // A lost connection: a read is tried again (three attempts in all, like transfer); any request says which server.
65
+ let sent;
66
+ for (let attempt = 1;; attempt++) {
67
+ try {
68
+ sent = await this.send(path, method, { ...(data ? { body: data, type: "application/json" } : {}), token, ...options });
69
+ break;
70
+ }
71
+ catch (error) {
72
+ const lost = error?.name === "TypeError" && !options.signal?.aborted;
73
+ if (lost && method === "GET" && attempt < 3) {
74
+ await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
75
+ continue;
76
+ }
77
+ if (lost)
78
+ throw Object.assign(Error(`Method cannot be reached at ${this.server} (${method} ${path}): ${error.cause?.code ?? error.message}. Check the connection and run again.`), { code: "network" });
79
+ throw error;
80
+ }
81
+ }
82
+ const { status, statusText, ok, bytes } = sent;
83
+ const text = Buffer.from(bytes).toString("utf8");
84
+ let result;
85
+ try {
86
+ result = JSON.parse(text);
87
+ }
88
+ catch {
89
+ const title = /<title[^>]*>([^<]*)<\/title>/i.exec(text)?.[1]?.split("|")[0]?.trim();
90
+ throw Object.assign(Error(`${status}: ${title || statusText || "Method returned a non-JSON response"} (${method} ${path}). Local run files are preserved.`), { status });
91
+ }
92
+ if (!ok)
93
+ throw Object.assign(Error(`${status}: ${String(result.message ?? result.error ?? "Method request failed").slice(0, 1000)}`), { status, code: typeof result.code === 'string' ? result.code.slice(0, 100) : 'method_request_failed' });
94
+ return result;
95
+ }
96
+ /** Upload (data) or download bytes. Retries a lost connection or a server error twice; stops only when no bytes move. */
97
+ async transfer(path, data, options = {}) {
98
+ if (!path.startsWith('/api/cli/') || path.includes('://'))
99
+ throw Error('Use a Method file API path.');
100
+ const token = this.token();
101
+ if (!token)
102
+ throw Error('Sign in with method login first.');
103
+ for (let attempt = 1;; attempt++) {
104
+ try {
105
+ const response = await this.send(path, data ? 'PUT' : 'GET', { token, stallMs: options.stallMs ?? 60_000, ...(options.onProgress ? { onProgress: options.onProgress } : {}), ...(data ? { body: data, type: 'application/octet-stream' } : {}) });
106
+ if (!response.ok)
107
+ throw Object.assign(new Error(`${response.status}: ${Buffer.from(response.bytes).toString('utf8').slice(0, 1000)}`), { status: response.status, retryable: response.status >= 500 || response.status === 429 });
108
+ return response.bytes;
109
+ }
110
+ catch (error) {
111
+ if (attempt >= (options.attempts ?? 3) || error.retryable === false)
112
+ throw error;
113
+ await new Promise(resolve => setTimeout(resolve, 500 * 2 ** (attempt - 1)));
114
+ }
115
+ }
116
+ }
117
+ /** Send bytes in chunks and read the answer in chunks; a watchdog aborts when no bytes moved for stallMs. */
118
+ async send(path, method, options) {
119
+ const stallMs = options.stallMs ?? 15_000, controller = new AbortController();
120
+ let timer;
121
+ // stallMs 0: no watchdog, for a server that sends nothing until its answer is complete (a model request).
122
+ const touch = () => {
123
+ clearTimeout(timer);
124
+ if (stallMs === 0)
125
+ return;
126
+ timer = setTimeout(() => controller.abort(Object.assign(new Error(`No data moved for ${Math.round(stallMs / 1000)} s (${method} ${path}).`), { name: 'TimeoutError', code: 'stalled' })), stallMs);
127
+ };
128
+ const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
129
+ touch();
130
+ try {
131
+ let body;
132
+ const raw = options.body;
133
+ const data = typeof raw === 'string' && raw.length > chunkBytes ? new TextEncoder().encode(raw) : raw;
134
+ const size = typeof data === 'string' ? Buffer.byteLength(data) : data?.byteLength ?? 0;
135
+ if (data && typeof data !== 'string' && data.byteLength > chunkBytes) {
136
+ let offset = 0;
137
+ body = new ReadableStream({
138
+ pull(stream) {
139
+ if (offset >= data.byteLength) {
140
+ stream.close();
141
+ return;
142
+ }
143
+ const end = Math.min(offset + chunkBytes, data.byteLength);
144
+ stream.enqueue(data.subarray(offset, end));
145
+ offset = end;
146
+ touch();
147
+ options.onProgress?.(offset);
148
+ },
149
+ });
150
+ }
151
+ else if (data)
152
+ body = data;
153
+ const response = await this.fetcher(this.server + path, {
154
+ method, redirect: "error", signal,
155
+ headers: { ...(options.type ? { "content-type": options.type } : {}), ...(options.token ? { authorization: `Bearer ${options.token}` } : {}) },
156
+ ...(body === undefined ? {} : { body, ...(body instanceof ReadableStream ? { duplex: 'half' } : {}) }),
157
+ });
158
+ if (data && !(body instanceof ReadableStream))
159
+ options.onProgress?.(size);
160
+ touch();
161
+ const chunks = [];
162
+ let length = 0;
163
+ const reader = response.body?.getReader();
164
+ if (reader)
165
+ for (;;) {
166
+ const { done, value } = await reader.read();
167
+ if (done)
168
+ break;
169
+ touch();
170
+ length += value.byteLength;
171
+ if (options.maxResponseBytes !== undefined && length > options.maxResponseBytes) {
172
+ await reader.cancel();
173
+ throw Error('Method response exceeds the size limit.');
174
+ }
175
+ chunks.push(value);
176
+ }
177
+ else if (typeof response.arrayBuffer === 'function')
178
+ chunks.push(new Uint8Array(await response.arrayBuffer()));
179
+ return { status: response.status, statusText: response.statusText, ok: response.ok, bytes: new Uint8Array(Buffer.concat(chunks)) };
180
+ }
181
+ catch (error) {
182
+ if (controller.signal.aborted && controller.signal.reason instanceof Error)
183
+ throw controller.signal.reason;
184
+ throw error;
185
+ }
186
+ finally {
187
+ clearTimeout(timer);
188
+ }
189
+ }
190
+ async login(openBrowser = openUrl) {
191
+ if (this.token()) {
192
+ try {
193
+ await this.request("/api/cli/me");
194
+ process.stderr.write("Method is connected.\n");
195
+ return;
196
+ }
197
+ catch (error) {
198
+ if (!String(error).includes("401:"))
199
+ throw error;
200
+ }
201
+ }
202
+ const pendingFile = `${this.credentialFile}.pending`;
203
+ const prior = existsSync(pendingFile) ? JSON.parse(readFileSync(pendingFile, 'utf8')) : null;
204
+ const token = prior?.expires_at > Date.now() ? prior.token : `method_${Buffer.from(randomBytes(32)).toString("base64url")}`;
205
+ const started = prior?.expires_at > Date.now() ? prior : await this.request("/auth/cli/start", "POST", { name: hostname(), token_hash: sha256(token) }, false);
206
+ writePrivateJson(pendingFile, { ...started, token });
207
+ const verification = new URL(started.verification_url);
208
+ // The hosted app uses its API origin for WorkOS cookies. No credentials are sent to this URL.
209
+ if (verification.protocol !== "https:" &&
210
+ verification.origin !== this.server)
211
+ throw Error("Invalid browser sign-in URL.");
212
+ process.stderr.write(`Authorize Method in your browser. Check this code: ${started.code}\n${verification}\n`);
213
+ openBrowser(verification.toString());
214
+ while (Date.now() < started.expires_at) {
215
+ await new Promise((resolve) => setTimeout(resolve, 2000));
216
+ const result = await this.request("/auth/cli/poll", "POST", { poll_secret: started.poll_secret }, false);
217
+ if (result.status === "approved") {
218
+ writePrivateJson(this.credentialFile, { server: this.server, token });
219
+ rmSync(pendingFile, { force: true });
220
+ process.stderr.write("Method is connected.\n");
221
+ return;
222
+ }
223
+ if (result.status === "expired")
224
+ break;
225
+ }
226
+ rmSync(pendingFile, { force: true });
227
+ throw Error("Browser sign-in expired. Run method login again.");
228
+ }
229
+ async logout() {
230
+ if (this.token())
231
+ await this.request("/api/cli/logout", "POST", {});
232
+ rmSync(this.credentialFile, { force: true });
233
+ rmSync(`${this.credentialFile}.pending`, { force: true });
234
+ }
235
+ }
236
+ export function openUrl(url) {
237
+ // $BROWSER, as many command-line tools read it, picks the program that opens the link.
238
+ const chosen = process.env.BROWSER?.trim();
239
+ const command = chosen
240
+ ? chosen
241
+ : process.platform === "darwin"
242
+ ? "open"
243
+ : process.platform === "win32"
244
+ ? "rundll32"
245
+ : "xdg-open";
246
+ const args = !chosen && process.platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
247
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
248
+ child.on("error", () => process.stderr.write("Open the sign-in link above in your browser.\n"));
249
+ child.unref();
250
+ }
@@ -0,0 +1,29 @@
1
+ import { type MethodPackage } from '../../contracts/src/method-package.js';
2
+ import type { MethodClient } from './method-client.js';
3
+ export declare const runtimeVersion: string;
4
+ export declare const fileHash: (data: Uint8Array) => string;
5
+ export declare function contained(root: string, name: string): string;
6
+ /** The files that a saved package holds: declared files, script entrypoints, and dependency lockfiles. */
7
+ export declare function packageFileNames(root: string, workflow: any): string[];
8
+ /**
9
+ * The files of the Method's cases/ folder. A Method with account run data saves its cases with each version; a Method
10
+ * with device run data keeps them on this computer. Hidden files and links are not included. A file over the package
11
+ * limit of 20 MB is not included; its name goes to tooLarge, so the save can say so.
12
+ */
13
+ export declare const maxPackageFileBytes = 20000000;
14
+ export declare function caseFileNames(root: string, tooLarge?: string[]): string[];
15
+ /**
16
+ * The saved package of a local Method: its declared files, script entrypoints, and dependency lockfiles. Reads files on
17
+ * this computer only; the outbox uploads them later.
18
+ */
19
+ export declare function buildPackage(file: string, workflow: any): Promise<{
20
+ pack: MethodPackage;
21
+ sources: Record<string, string>;
22
+ tooLarge: string[];
23
+ }>;
24
+ export declare function restorePackage(saved: {
25
+ workflow_id: string;
26
+ version_id: string;
27
+ workflow: any;
28
+ package?: MethodPackage | null;
29
+ }, root: string, client: MethodClient): Promise<boolean>;
@@ -0,0 +1,93 @@
1
+ import { existsSync, readFileSync, realpathSync, mkdirSync, writeFileSync, renameSync, readdirSync, lstatSync, statSync } from 'node:fs';
2
+ import { dirname, resolve, relative, isAbsolute } from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { createRequire } from 'node:module';
5
+ import { MethodPackageSchema, packageDigest, packagePath } from '../../contracts/src/method-package.js';
6
+ import { lockDependencies } from './prepare.js';
7
+ export const runtimeVersion = createRequire(import.meta.url)('@withmethod/runtime/package.json').version;
8
+ export const fileHash = (data) => createHash('sha256').update(data).digest('hex');
9
+ export function contained(root, name) {
10
+ packagePath(name);
11
+ const path = realpathSync(resolve(root, name)), rel = relative(realpathSync(root), path);
12
+ if (isAbsolute(rel) || rel.startsWith('..'))
13
+ throw Error(`File leaves the Method folder: ${name}`);
14
+ return path;
15
+ }
16
+ /** The files that a saved package holds: declared files, script entrypoints, and dependency lockfiles. */
17
+ export function packageFileNames(root, workflow) {
18
+ const executions = [...Object.values(workflow.steps).flatMap((s) => [s.do, s.check, ...Object.values(s.effects ?? {}).flatMap((e) => [e.observe, e.judge])]),
19
+ ...Object.values(workflow.tools ?? {}).map((t) => t.run)].filter(Boolean);
20
+ return [...new Set([...(workflow.files ?? []), ...executions.filter(e => e.kind === 'run').map(e => e.entrypoint),
21
+ ...['package.json', 'package-lock.json', 'pyproject.toml', 'uv.lock'].filter(name => existsSync(resolve(root, name)))])].sort();
22
+ }
23
+ /**
24
+ * The files of the Method's cases/ folder. A Method with account run data saves its cases with each version; a Method
25
+ * with device run data keeps them on this computer. Hidden files and links are not included. A file over the package
26
+ * limit of 20 MB is not included; its name goes to tooLarge, so the save can say so.
27
+ */
28
+ export const maxPackageFileBytes = 20_000_000;
29
+ export function caseFileNames(root, tooLarge = []) {
30
+ const names = [];
31
+ const walk = (relativeDir) => {
32
+ const folder = resolve(root, relativeDir);
33
+ if (!existsSync(folder) || !lstatSync(folder).isDirectory())
34
+ return;
35
+ for (const entry of readdirSync(folder, { withFileTypes: true })) {
36
+ const name = `${relativeDir}/${entry.name}`;
37
+ if (entry.name.startsWith('.'))
38
+ continue;
39
+ try {
40
+ packagePath(name);
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ if (entry.isDirectory())
46
+ walk(name);
47
+ else if (entry.isFile())
48
+ (statSync(resolve(root, name)).size <= maxPackageFileBytes ? names : tooLarge).push(name);
49
+ }
50
+ };
51
+ walk('cases');
52
+ return names;
53
+ }
54
+ /**
55
+ * The saved package of a local Method: its declared files, script entrypoints, and dependency lockfiles. Reads files on
56
+ * this computer only; the outbox uploads them later.
57
+ */
58
+ export async function buildPackage(file, workflow) {
59
+ const root = dirname(resolve(file));
60
+ await lockDependencies(root);
61
+ const tooLarge = [];
62
+ const names = [...new Set([...packageFileNames(root, workflow), ...(workflow.run_data === 'device' ? [] : caseFileNames(root, tooLarge))])].sort();
63
+ const sources = {};
64
+ const files = names.map(path => { const source = contained(root, path), bytes = readFileSync(source), sha256 = fileHash(bytes); sources[sha256] = source; return { path, sha256, size: bytes.length }; });
65
+ const pack = MethodPackageSchema.parse({ schema: 'method-package/1', runtime: runtimeVersion, files, digest: packageDigest(workflow, { runtime: runtimeVersion, files }) });
66
+ return { pack, sources, tooLarge };
67
+ }
68
+ export async function restorePackage(saved, root, client) {
69
+ if (!saved.package)
70
+ return false;
71
+ const pack = MethodPackageSchema.parse(saved.package);
72
+ if (packageDigest(saved.workflow, pack) !== pack.digest)
73
+ throw Error('Saved Method package checksum does not match.');
74
+ mkdirSync(root, { recursive: true, mode: 0o700 });
75
+ for (const f of pack.files) {
76
+ const path = resolve(root, packagePath(f.path));
77
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
78
+ const parent = relative(realpathSync(root), realpathSync(dirname(path)));
79
+ if (parent.startsWith('..') || isAbsolute(parent))
80
+ throw Error('Package destination leaves its folder.');
81
+ if (existsSync(path)) {
82
+ if (fileHash(readFileSync(contained(root, f.path))) === f.sha256)
83
+ continue;
84
+ throw Error(`Saved file conflicts with a local file: ${f.path}`);
85
+ }
86
+ const bytes = await client.transfer(`/api/cli/methods/${encodeURIComponent(saved.workflow_id)}/files/${f.sha256}?version=${encodeURIComponent(saved.version_id)}`);
87
+ if (bytes.length !== f.size || fileHash(bytes) !== f.sha256)
88
+ throw Error(`Saved file checksum does not match: ${f.path}`);
89
+ writeFileSync(`${path}.download`, bytes, { mode: 0o600 });
90
+ renameSync(`${path}.download`, path);
91
+ }
92
+ return true;
93
+ }
@@ -0,0 +1,19 @@
1
+ export { exampleSelection } from "./authoring-instructions.js";
2
+ type Command = {
3
+ usage: string;
4
+ purpose: string;
5
+ arguments: string;
6
+ result: string;
7
+ errors: string;
8
+ example: string;
9
+ remote?: boolean;
10
+ };
11
+ export declare const commandHelp: Record<string, Command>;
12
+ export declare function renderCommand(name: string, includeCommon?: boolean): string;
13
+ export declare const guideTopics: readonly ["start", "concepts", "execution", "examples", "example", "recipes", "recovery", "commands"];
14
+ export declare function authoringGuide(topic?: string, exampleId?: string): string;
15
+ export declare const overviewHelp = "Method \u2014 author, save and run methods with your coding agent.\n\nBefore creating, editing, or proposing a Method, run `method authoring` and read its guidance. Do this before choosing an existing Method as a reference.\n\nLearn: method authoring Start the installed guide.\n method authoring all Read the full manual offline.\n method COMMAND --help Read arguments, results and examples.\n method help step add Read help for a subcommand.\n method schema [TYPE] Read a formal JSON schema.\n\nLocal drafts: init, show, set, remove, step add/update/remove/move,\n check set/remove, validate, diff.\nOnline documents: list, get, steps, step, publish, explain.\nImprovements: improve, proposals, apply.\nKeys for scripts: secret find, secret import, secret set, secret list.\nExecution and evidence: run, run-status, wait, cancel, runs, logs, sync, observe.\nEffects and corrections: effect add/list, case new/retire/list, test.\nInputs and shared state: bind, state.\nBrowser and computer setup: browser connect, config.\nAccount access: status, login, logout, devices, revoke.\nProduction runs: connect, answer, keys create/list/revoke, worker.\n\nSign in with method login first. Read the authoring guide, give each prompt its own step, write the files, validate, and run. Each signed-in run saves a version when the file changed. Publish a version when the user wants to share or schedule it.\nUse method run task.method to run it.\nOnline server: https://app.withmethod.ai. Use --server only to select another\nserver. Sign-in uses browser approval. Never send credentials in chat.\n";
16
+ /** Resolve help before parsing flags, creating a client, or touching any draft. */
17
+ export declare function methodHelp(args: string[]): string | undefined;
18
+ /** The CLI and published reference use this same command inventory. */
19
+ export declare function commandTable(): string;