@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,81 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { z } from 'zod';
3
+ const Default = z.object({ provider: z.literal('openrouter'), model: z.string().trim().min(1) });
4
+ // A model service that is briefly unavailable gets three attempts in all, like classification.
5
+ const attempts = 3;
6
+ /** Where a run's hosted model requests go: this computer's own OpenRouter key when it has one, else the account. */
7
+ export async function hostedModelsFor(client) {
8
+ const { ownKeyEnv, ownKeyModels } = await import('./own-model-key.js');
9
+ const env = ownKeyEnv();
10
+ return env ? ownKeyModels(env) : managedModels(client);
11
+ }
12
+ /** Hosted models through the signed-in Method account. The account's model credit pays for them. */
13
+ export function managedModels(client) {
14
+ return {
15
+ async model() {
16
+ return Default.parse(await client.request('/api/cli/models/default', 'GET', undefined, true, { stallMs: 30_000 })).model;
17
+ },
18
+ async request(body, signal) {
19
+ const request = { request_id: randomUUID(), request: body };
20
+ for (let attempt = 1;; attempt++) {
21
+ try {
22
+ // No time limit: the server sends nothing until the model has answered, which can take minutes.
23
+ return await client.request('/api/cli/models/respond', 'POST', request, true, { signal, stallMs: 0, maxResponseBytes: 4 * 1024 * 1024 });
24
+ }
25
+ catch (error) {
26
+ if (attempt >= attempts || signal.aborted || !(error.status === 503 || error.status === 429) || error.code === 'model_credit_used')
27
+ throw error;
28
+ await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
29
+ }
30
+ }
31
+ },
32
+ };
33
+ }
34
+ const PrivateModels = z.object({ models: z.array(z.object({ id: z.string(), providers: z.array(z.string()) })), default: z.string().nullable().optional(), checked_at: z.string() });
35
+ const day = 24 * 60 * 60_000;
36
+ /**
37
+ * The hosted models that work with the private options (no training, zero data retention), from the server. The list
38
+ * is kept for a day under the Method cache; undefined when it cannot be fetched and no copy is saved.
39
+ */
40
+ export async function privateModels(client, options = {}) {
41
+ const { methodCache } = await import('./prepare.js');
42
+ const { createHash } = await import('node:crypto');
43
+ const { existsSync, readFileSync } = await import('node:fs');
44
+ const { join } = await import('node:path');
45
+ const { writePrivateJson } = await import('./files.js');
46
+ const file = join(methodCache(), 'models', `private-${createHash('sha256').update(client.server).digest('hex').slice(0, 16)}.json`);
47
+ let saved;
48
+ try {
49
+ saved = existsSync(file) ? PrivateModels.parse(JSON.parse(readFileSync(file, 'utf8'))) : undefined;
50
+ }
51
+ catch {
52
+ saved = undefined;
53
+ }
54
+ if (saved && !options.refresh && Date.now() - Date.parse(saved.checked_at) < day)
55
+ return saved;
56
+ try {
57
+ const signal = options.waitMs ? AbortSignal.timeout(options.waitMs) : undefined;
58
+ const list = PrivateModels.parse(await client.request('/api/cli/models/private', 'GET', undefined, true, { stallMs: 15_000, ...(signal ? { signal } : {}) }));
59
+ writePrivateJson(file, list);
60
+ return list;
61
+ }
62
+ catch (error) {
63
+ if (options.refresh && !saved)
64
+ throw error;
65
+ return saved;
66
+ }
67
+ }
68
+ /** method models [--refresh] [--server URL]: the hosted models that work with the private options. */
69
+ export async function modelsCommand(args, clientFactory) {
70
+ const { parseArgs } = await import('node:util');
71
+ const { DEFAULT_SERVER } = await import('./method-client.js');
72
+ const { values } = parseArgs({ args, options: { refresh: { type: 'boolean' }, server: { type: 'string' } } });
73
+ const client = clientFactory(values.server ?? DEFAULT_SERVER);
74
+ if (!client.token())
75
+ throw Error('Run method login first. The list of private models comes from your Method account.');
76
+ const list = await privateModels(client, { refresh: !!values.refresh });
77
+ if (!list)
78
+ throw Error('Method cannot be reached, and no saved list exists. Try again when online.');
79
+ process.stdout.write(JSON.stringify({ private: 'Each model below has a provider that does not train on requests and keeps no copy (zero data retention). Hosted runs use only those providers.',
80
+ default: list.default ?? null, checked_at: list.checked_at, models: list.models.map(model => model.id), use: 'Name a model ID on a step (model: provider/model) or in models:.' }, null, 2) + '\n');
81
+ }
@@ -0,0 +1,55 @@
1
+ import { type MethodClient } from './method-client.js';
2
+ /** run_id: the run that the note is about; an account run ID for an account improvement, a run folder for one on this computer. */
3
+ export type ImproveRequest = {
4
+ step_id?: string;
5
+ note?: string;
6
+ case_id?: string;
7
+ run_id?: string;
8
+ };
9
+ /** Runs a local Method file; the default is the runtime that `method run FILE` uses. */
10
+ export type RunFile = (file: string, flags: Record<string, unknown>, syncFactory: undefined, onEvent: undefined, client: MethodClient, baseConfig: undefined, secrets: Record<string, string>) => Promise<{
11
+ status: string;
12
+ result?: unknown;
13
+ }>;
14
+ /** The SubmitProposal that improve.method returns, read from its result. */
15
+ export type ImproveProposal = {
16
+ cause: string;
17
+ workflow: unknown | null;
18
+ evidence: {
19
+ kind: ProposalKind;
20
+ steps?: string[];
21
+ [key: string]: unknown;
22
+ };
23
+ };
24
+ type ProposalKind = 'change' | 'case' | 'rubric' | 'script' | 'none';
25
+ /**
26
+ * Read the result of improve.method: {proposal: <SubmitProposal as JSON text>, kind, proposal_id}. A change has the
27
+ * proposed workflow; a case or rubric fix has case_suggestion; a script change has script_change; none has neither.
28
+ */
29
+ export declare function readImproveResult(result: unknown): ImproveProposal;
30
+ /**
31
+ * `method improve FILE`. A Method with account run data starts an improvement run in the account. A Method with device
32
+ * run data runs improve.method on this computer, so its run content stays here, and saves a local proposal.
33
+ */
34
+ export declare function improveCommand(args: string[], clientFactory: (server: string) => MethodClient, run?: RunFile): Promise<boolean>;
35
+ /** Download the published improve.method and its files into the Method cache, once per version. */
36
+ export declare function cachedImproveMethod(client: MethodClient): Promise<{
37
+ file: string;
38
+ root: string;
39
+ version_id: string;
40
+ }>;
41
+ /**
42
+ * Run improve.method on this computer and save its result as a local proposal of the file. The run gets the signed-in
43
+ * key and server as its IMPROVE_API_KEY and IMPROVE_SERVER secrets, for this run only: they stay in memory.
44
+ */
45
+ export declare function improveOnDevice(client: MethodClient, file: string, request: ImproveRequest, run?: RunFile): Promise<{
46
+ proposal_id: string;
47
+ source: string;
48
+ file: string;
49
+ kind: ProposalKind;
50
+ cause: string;
51
+ steps: string[];
52
+ proposal_file: string;
53
+ next: string;
54
+ }>;
55
+ export {};
@@ -0,0 +1,159 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { randomBytes, randomUUID } from 'node:crypto';
4
+ import { parseArgs } from 'node:util';
5
+ import { MethodPackageSchema, packageDigest, packagePath } from '../../contracts/src/method-package.js';
6
+ import { loadWorkflow } from '../../workflow-language/src/validate.js';
7
+ import { authoringPath, readDocument } from './authoring.js';
8
+ import { DEFAULT_SERVER } from './method-client.js';
9
+ import { fileHash } from './method-files.js';
10
+ import { methodCache } from './prepare.js';
11
+ import { writePrivateJson } from './files.js';
12
+ import { currentVersion, methodContent, methodIdPattern } from './versions.js';
13
+ import { localRuns, saveLocalProposal } from './proposals.js';
14
+ const kinds = ['change', 'case', 'rubric', 'script', 'none'];
15
+ /**
16
+ * Read the result of improve.method: {proposal: <SubmitProposal as JSON text>, kind, proposal_id}. A change has the
17
+ * proposed workflow; a case or rubric fix has case_suggestion; a script change has script_change; none has neither.
18
+ */
19
+ export function readImproveResult(result) {
20
+ const value = result;
21
+ if (!value || typeof value.proposal !== 'string')
22
+ throw Error('The improvement run gave no proposal.');
23
+ let proposal;
24
+ try {
25
+ proposal = JSON.parse(value.proposal);
26
+ }
27
+ catch {
28
+ throw Error('The improvement run gave a proposal that is not JSON.');
29
+ }
30
+ if (typeof proposal?.cause !== 'string' || !proposal.cause.trim())
31
+ throw Error('The improvement proposal has no cause.');
32
+ const evidence = proposal.evidence;
33
+ if (!evidence || typeof evidence !== 'object' || !kinds.includes(evidence.kind))
34
+ throw Error('The improvement proposal has no known kind.');
35
+ if (value.kind !== undefined && value.kind !== evidence.kind)
36
+ throw Error(`The improvement run says kind ${String(value.kind)}, but its proposal is kind ${evidence.kind}.`);
37
+ if (evidence.kind === 'change' && (!proposal.workflow || typeof proposal.workflow !== 'object'))
38
+ throw Error('The improvement proposal is a change without a workflow.');
39
+ if ((evidence.kind === 'case' || evidence.kind === 'rubric') && !evidence.case_suggestion)
40
+ throw Error(`The improvement proposal is a ${evidence.kind} fix without case_suggestion.`);
41
+ if (evidence.kind === 'script' && !evidence.script_change)
42
+ throw Error('The improvement proposal is a script change without script_change.');
43
+ return { cause: proposal.cause.trim(), workflow: evidence.kind === 'change' ? proposal.workflow : null, evidence };
44
+ }
45
+ const nextStep = (file, id, kind) => ({
46
+ change: `Read the proposal, then run method apply ${file} ${id}. It does not publish.`,
47
+ case: `Run method apply ${file} ${id} to see the case to record.`,
48
+ rubric: `Run method apply ${file} ${id} to see the case rubric to fix.`,
49
+ script: `Run method apply ${file} ${id} to see the script change.`,
50
+ none: 'No safe change was found.',
51
+ })[kind];
52
+ const print = (value) => process.stdout.write(JSON.stringify(value, null, 2) + '\n');
53
+ /**
54
+ * `method improve FILE`. A Method with account run data starts an improvement run in the account. A Method with device
55
+ * run data runs improve.method on this computer, so its run content stays here, and saves a local proposal.
56
+ */
57
+ export async function improveCommand(args, clientFactory, run) {
58
+ const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { case: { type: 'string' }, note: { type: 'string' }, step: { type: 'string' }, server: { type: 'string' } } });
59
+ if (positionals.length !== 1)
60
+ throw Error('Use method improve FILE [--case ID] [--note TEXT] [--step ID].');
61
+ const file = authoringPath(positionals[0]), document = readDocument(file), workflow = loadWorkflow(methodContent(document));
62
+ if (values.step && !Object.hasOwn(workflow.steps, values.step))
63
+ throw Error(`Step ${values.step} is not in ${positionals[0]}.`);
64
+ if (values.case && !/^[a-z0-9][a-z0-9-]{0,79}$/.test(values.case))
65
+ throw Error('Use a case ID: lowercase letters, digits, and hyphens.');
66
+ if (values.note !== undefined && !values.note.trim())
67
+ throw Error('Write the correction after --note.');
68
+ const request = { ...(values.step ? { step_id: values.step } : {}), ...(values.note ? { note: values.note.trim() } : {}), ...(values.case ? { case_id: values.case } : {}) };
69
+ // A note is about the newest run of the Method on this computer.
70
+ const newest = request.note ? (await localRuns(file))[0] : undefined;
71
+ const client = clientFactory(values.server ?? DEFAULT_SERVER);
72
+ if (!client.token())
73
+ await client.login();
74
+ if (document.run_data !== 'device') {
75
+ const id = document.id;
76
+ if (typeof id !== 'string' || !methodIdPattern.test(id))
77
+ throw Error(`${positionals[0]} has no id: line, so your account has no version of it. Run method run ${positionals[0]} once while signed in, then run method improve again.`);
78
+ try {
79
+ const { improvement } = await client.request(`/api/methods/${encodeURIComponent(id)}/improvements`, 'POST', { ...request, ...(newest?.account_run_id ? { run_id: newest.account_run_id } : {}) });
80
+ return print({ improvement, url: `${client.server}/methods/${id}`, next: `Method's improvement agent is working; it takes a few minutes. Run method proposals ${positionals[0]} --wait (give the command 10 minutes): it returns with the proposal. Then show it to the user.` });
81
+ }
82
+ catch (error) {
83
+ if (error.code !== 'device_data')
84
+ throw error;
85
+ }
86
+ }
87
+ return print(await improveOnDevice(client, file, { ...request, ...(newest ? { run_id: newest.dir } : {}) }, run));
88
+ }
89
+ /** Download the published improve.method and its files into the Method cache, once per version. */
90
+ export async function cachedImproveMethod(client) {
91
+ const saved = await client.request('/api/cli/improve/method');
92
+ if (!/^v_[a-f0-9]{32}$/.test(saved.version_id))
93
+ throw Error('Method sent an improvement Method without a version ID.');
94
+ const root = join(methodCache(), 'improve', saved.version_id);
95
+ mkdirSync(root, { recursive: true, mode: 0o700 });
96
+ if (saved.package) {
97
+ const pack = MethodPackageSchema.parse(saved.package);
98
+ if (packageDigest(saved.workflow, pack) !== pack.digest)
99
+ throw Error('The improvement Method package checksum does not match.');
100
+ for (const f of pack.files) {
101
+ const path = resolve(root, packagePath(f.path));
102
+ if (existsSync(path) && fileHash(readFileSync(path)) === f.sha256)
103
+ continue;
104
+ const bytes = await client.transfer(`/api/cli/improve/files/${f.sha256}`);
105
+ if (bytes.length !== f.size || fileHash(bytes) !== f.sha256)
106
+ throw Error(`The improvement Method file checksum does not match: ${f.path}`);
107
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
108
+ writeFileSync(`${path}.download`, bytes, { mode: 0o600 });
109
+ renameSync(`${path}.download`, path);
110
+ }
111
+ }
112
+ const file = join(root, 'improve.method');
113
+ writePrivateJson(file, saved.workflow);
114
+ return { file, root, version_id: saved.version_id };
115
+ }
116
+ /**
117
+ * Run improve.method on this computer and save its result as a local proposal of the file. The run gets the signed-in
118
+ * key and server as its IMPROVE_API_KEY and IMPROVE_SERVER secrets, for this run only: they stay in memory.
119
+ */
120
+ export async function improveOnDevice(client, file, request, run) {
121
+ const token = client.token();
122
+ if (!token)
123
+ throw Error('Sign in with method login, then run method improve again.');
124
+ const secrets = { IMPROVE_API_KEY: token, IMPROVE_SERVER: client.server };
125
+ const improve = await cachedImproveMethod(client);
126
+ const runDir = join(methodCache(), 'runs', randomUUID());
127
+ const inputs = join(runDir, 'improve-inputs.json');
128
+ writePrivateJson(inputs, { method_file: file, case_id: request.case_id ?? '', note: request.note ?? '', step_id: request.step_id ?? '', grant_id: '', run_id: request.run_id ?? '', make_case: false });
129
+ const runFile = run ?? (await import('./current-runtime.js')).runCurrentFile;
130
+ process.stderr.write(`Improving ${file} on this computer. Its run content stays here.\n`);
131
+ // The run prints its own result; send it to stderr so that stdout holds only the proposal.
132
+ const write = process.stdout.write;
133
+ process.stdout.write = ((chunk, ...rest) => process.stderr.write(chunk, ...rest));
134
+ let result;
135
+ try {
136
+ result = await runFile(improve.file, { inputs, 'run-dir': runDir, workspace: improve.root, server: client.server }, undefined, undefined, client, undefined, secrets);
137
+ }
138
+ finally {
139
+ process.stdout.write = write;
140
+ }
141
+ if (result.status !== 'completed')
142
+ throw Error(`The improvement run stopped with status ${result.status}. Its records are in ${runDir}.`);
143
+ let submitted;
144
+ try {
145
+ submitted = readImproveResult(result.result);
146
+ }
147
+ catch (error) {
148
+ throw Error(`${error.message} Its records are in ${runDir}.`);
149
+ }
150
+ const id = `lp_${randomBytes(8).toString('hex')}`, document = readDocument(file);
151
+ const path = saveLocalProposal(file, {
152
+ id, method_id: typeof document.id === 'string' ? document.id : null, base_version_id: (await currentVersion(file))?.version_id ?? null,
153
+ status: 'open', cause: submitted.cause, evidence: submitted.evidence, created_at: new Date().toISOString(),
154
+ base_workflow: methodContent(document), proposed_workflow: submitted.workflow,
155
+ improvement: { version_id: improve.version_id, run_dir: runDir },
156
+ });
157
+ const kind = submitted.evidence.kind;
158
+ return { proposal_id: id, source: 'local', file, kind, cause: submitted.cause, steps: submitted.evidence.steps ?? [], proposal_file: path, next: nextStep(file, id, kind) };
159
+ }
@@ -0,0 +1,13 @@
1
+ export { runMethod } from "./run-method.js";
2
+ export { methodSchema, configSchema } from "@withmethod/runtime/schema.js";
3
+ export { loadWorkflow as loadMethod, serializeWorkflow as serializeMethod } from "../../workflow-language/src/validate.js";
4
+ export { WorkflowSchema as MethodSchema, type Workflow as MethodDocument } from "../../workflow-language/src/schema.js";
5
+ export { Method, MethodApiError, verifyWebhook, type AskEvent, type AskHandler, type StartRunOptions, type StartedRun, type ProductionRun, type RunStatus } from "./production.js";
6
+ export { seal as sealRunData, open as openRunData, inputsDigest } from "./run-data.js";
7
+ export { ProductionWorker, cliExecutor, type WorkerOptions, type WorkerResult } from "./worker.js";
8
+ export { inspectRun } from "./inspect.js";
9
+ export { InspectionSchema, copyInstructions } from "../../workflow-language/src/inspection.js";
10
+ export { saveWorkflowLink as saveMethodLink, isWorkflowLink as isMethodLink } from "./link.js";
11
+ export { reportProgress, relayCodexProgress, type ProgressUpdate } from "./progress.js";
12
+ export { runProcess, type ProcessCommand } from "./process.js";
13
+ export { checkedFile, writePrivateJson } from "./files.js";
@@ -0,0 +1,13 @@
1
+ export { runMethod } from "./run-method.js";
2
+ export { methodSchema, configSchema } from "@withmethod/runtime/schema.js";
3
+ export { loadWorkflow as loadMethod, serializeWorkflow as serializeMethod } from "../../workflow-language/src/validate.js";
4
+ export { WorkflowSchema as MethodSchema } from "../../workflow-language/src/schema.js";
5
+ export { Method, MethodApiError, verifyWebhook } from "./production.js";
6
+ export { seal as sealRunData, open as openRunData, inputsDigest } from "./run-data.js";
7
+ export { ProductionWorker, cliExecutor } from "./worker.js";
8
+ export { inspectRun } from "./inspect.js";
9
+ export { InspectionSchema, copyInstructions } from "../../workflow-language/src/inspection.js";
10
+ export { saveWorkflowLink as saveMethodLink, isWorkflowLink as isMethodLink } from "./link.js";
11
+ export { reportProgress, relayCodexProgress } from "./progress.js";
12
+ export { runProcess } from "./process.js";
13
+ export { checkedFile, writePrivateJson } from "./files.js";
@@ -0,0 +1,6 @@
1
+ import { type RunInspection } from "../../workflow-language/src/inspection.js";
2
+ /** Export known run records. File previews are opt-in and must match saved hashes. */
3
+ export declare function inspectRun(directory: string, options?: {
4
+ includeFiles?: boolean | "references"; /** Internal: only called synchronously by the owning SDK process. */
5
+ activeSnapshot?: boolean;
6
+ }): RunInspection;
@@ -0,0 +1,17 @@
1
+ import { inspectCurrentRun } from "./current-inspection.js";
2
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ import { InspectionSchema } from "../../workflow-language/src/inspection.js";
5
+ /** Export known run records. File previews are opt-in and must match saved hashes. */
6
+ export function inspectRun(directory, options = {}) {
7
+ const requested = resolve(directory);
8
+ const root = realpathSync(requested);
9
+ if (!existsSync(join(root, "method.json")) && existsSync(join(root, "setup-inspection.json")) && existsSync(join(root, "request.json"))) {
10
+ const initial = JSON.parse(readFileSync(join(root, "setup-inspection.json"), "utf8"));
11
+ const failure = existsSync(join(root, "setup-error.json")) ? JSON.parse(readFileSync(join(root, "setup-error.json"), "utf8")) : null;
12
+ return InspectionSchema.parse({ ...initial, local_run_directory: root, ...(failure ? { status: 'needs_attention', error: failure.error } : {}), events: existsSync(join(root, "setup.json")) ? JSON.parse(readFileSync(join(root, "setup.json"), "utf8")) : [] });
13
+ }
14
+ if (existsSync(join(root, "method.json")))
15
+ return inspectCurrentRun(root, options.activeSnapshot, options.includeFiles);
16
+ throw Error("UNSUPPORTED_RUN: only current Method run records are supported.");
17
+ }
@@ -0,0 +1,12 @@
1
+ import type { Workflow } from "../../workflow-language/src/schema.js";
2
+ export declare function isWorkflowLink(value: string): boolean;
3
+ /**
4
+ * Download a signed workflow link and keep it as <id>.workflow in the directory.
5
+ * The saved file is reused when its bytes match; a different file is never overwritten.
6
+ */
7
+ export declare function saveWorkflowLink(link: string, directory: string, fetchImpl?: typeof fetch): Promise<{
8
+ path: string;
9
+ reused: boolean;
10
+ source: string;
11
+ workflow: Workflow;
12
+ }>;
@@ -0,0 +1,53 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { loadWorkflow } from "../../workflow-language/src/validate.js";
4
+ export function isWorkflowLink(value) { return /^https?:\/\//iu.test(value); }
5
+ const message = (error) => error instanceof Error ? error.message : String(error);
6
+ async function failure(response) {
7
+ const text = await response.text().catch(() => "");
8
+ let code = "";
9
+ try {
10
+ code = String(JSON.parse(text).error ?? "");
11
+ }
12
+ catch { /* Not JSON. */ }
13
+ if (code === "link_expired")
14
+ return "LINK_EXPIRED: this link has expired. Open the method page, copy the command again, and run it.";
15
+ if (code === "link_invalid")
16
+ return "LINK_INVALID: this link is not valid. Copy the whole command from the method page and run it again.";
17
+ if (code === "workflow_source_not_ready")
18
+ return "WORKFLOW_NOT_READY: this method is still being built. When the method page shows it is ready, run the command again.";
19
+ if (response.status === 404)
20
+ return "LINK_NOT_FOUND: no method exists at this link. Copy the command from the method page again.";
21
+ return `LINK_FAILED: the method link returned ${response.status}${text.trim() ? `: ${text.trim().slice(0, 200)}` : ""}.`;
22
+ }
23
+ /**
24
+ * Download a signed workflow link and keep it as <id>.workflow in the directory.
25
+ * The saved file is reused when its bytes match; a different file is never overwritten.
26
+ */
27
+ export async function saveWorkflowLink(link, directory, fetchImpl = fetch) {
28
+ let response;
29
+ try {
30
+ response = await fetchImpl(link, { headers: { accept: "application/json" } });
31
+ }
32
+ catch (error) {
33
+ throw new Error(`LINK_UNREACHABLE: could not download ${link}: ${message(error)}`);
34
+ }
35
+ if (!response.ok)
36
+ throw new Error(await failure(response));
37
+ const source = await response.text();
38
+ let workflow;
39
+ try {
40
+ workflow = loadWorkflow(source);
41
+ }
42
+ catch (error) {
43
+ throw new Error(`LINK_INVALID: the link did not return a valid method: ${message(error)}`);
44
+ }
45
+ const path = resolve(directory, `${workflow.name.toLowerCase().replace(/[^a-z0-9]+/g, "-")}.method`);
46
+ if (existsSync(path)) {
47
+ if (readFileSync(path, "utf8") === source)
48
+ return { path, reused: true, source, workflow };
49
+ throw new Error(`WORKFLOW_FILE_CONFLICT: ${path} already exists with different content. Move or rename it, then run the command again.`);
50
+ }
51
+ writeFileSync(path, source, { flag: "wx", mode: 0o600 });
52
+ return { path, reused: false, source, workflow };
53
+ }
@@ -0,0 +1,24 @@
1
+ import type { MethodSync } from "./method-sync.js";
2
+ export declare function parse(args: string[]): {
3
+ values: {
4
+ server?: string;
5
+ agent?: string;
6
+ background?: boolean;
7
+ state?: string;
8
+ out?: string;
9
+ inputs?: string;
10
+ workspace?: string;
11
+ "run-dir"?: string;
12
+ fresh?: boolean;
13
+ rerun?: string[];
14
+ resume?: boolean;
15
+ human?: string;
16
+ retry?: string[];
17
+ "include-files"?: boolean;
18
+ verbose?: boolean;
19
+ help?: boolean;
20
+ };
21
+ positionals: string[];
22
+ };
23
+ export declare function run(target: string, flags: ReturnType<typeof parse>["values"], syncFactory?: () => MethodSync): Promise<void>;
24
+ export declare function localMain(args?: string[]): Promise<void>;
@@ -0,0 +1,146 @@
1
+ import { runCurrentFile } from "./current-runtime.js";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import { executionLabel } from "../../workflow-language/src/schema.js";
6
+ import { loadWorkflow } from "../../workflow-language/src/validate.js";
7
+ import { renderPrompt } from "../../method-document/src/conversion-report.js";
8
+ import { checkNode } from "./doctor.js";
9
+ import { writePrivateJson } from "./files.js";
10
+ import { isWorkflowLink, saveWorkflowLink } from "./link.js";
11
+ import { inspectRun } from "./inspect.js";
12
+ import { accountNeeds, checkConfiguration, resolveAgentProfiles } from './capabilities.js';
13
+ import { MethodClient } from "./method-client.js";
14
+ import { MethodSync as Sync } from "./method-sync.js";
15
+ import { prepareVersion, savedLine, methodContent } from "./versions.js";
16
+ import { Outbox, savedVersions } from "./outbox.js";
17
+ import { readComputerSettings } from "./computer-settings.js";
18
+ import { localSetup } from "./local-setup.js";
19
+ import { readDocument } from "./authoring.js";
20
+ import { join } from "node:path";
21
+ import { randomUUID } from "node:crypto";
22
+ const help = "Use method run, steps, prompt, inspect, or doctor. See method help.";
23
+ export function parse(args) {
24
+ return parseArgs({ args, allowPositionals: true, options: {
25
+ server: { type: "string" }, agent: { type: "string" }, background: { type: "boolean" }, state: { type: "string" }, out: { type: "string" }, inputs: { type: "string" }, workspace: { type: "string" },
26
+ "run-dir": { type: "string" }, fresh: { type: "boolean" }, rerun: { type: "string", multiple: true }, resume: { type: "boolean" }, human: { type: "string" }, retry: { type: "string", multiple: true },
27
+ "include-files": { type: "boolean" }, verbose: { type: "boolean" }, help: { type: "boolean" }
28
+ } });
29
+ }
30
+ export async function run(target, flags, syncFactory) {
31
+ const path = isWorkflowLink(target) ? (await saveWorkflowLink(target, process.cwd())).path : resolve(target);
32
+ const legacy = (await import("./method-issues.js")).legacyIssues(path);
33
+ if (legacy.length)
34
+ throw Error(legacy.map(issue => `${issue.code}: ${issue.message} ${issue.fix}`).join('\n'));
35
+ loadWorkflow(methodContent(readDocument(path)));
36
+ const notice = await (await import("./quality.js")).casesNotice(path);
37
+ if (notice)
38
+ process.stderr.write(notice + "\n");
39
+ const update = await (await import("./update.js")).updateNotice();
40
+ if (update)
41
+ process.stderr.write(update + "\n");
42
+ (await import("./prepare.js")).pruneCachedRuns();
43
+ flags = { ...flags, "run-dir": flags["run-dir"] ?? join(process.cwd(), ".method-runs", randomUUID()) };
44
+ const account = syncFactory ? undefined : await accountSync(path, flags);
45
+ try {
46
+ await runCurrentFile(path, flags, syncFactory ?? account?.sync);
47
+ }
48
+ finally {
49
+ if (account) {
50
+ // The run's records were sent when it finished; this sends what is left and says where the version is.
51
+ await account.outbox.drain();
52
+ process.stderr.write(savedLine(account.client, account.outbox, account.version) + "\n");
53
+ // Script cards are made after the run, so that this run's inputs can be replayed. They never delay or fail it.
54
+ if (savedVersions(account.client.server)[account.version.version_id])
55
+ (await import("./explain.js")).startBackgroundExplain(path, account.version.workflow, account.version.version_id, account.client.server);
56
+ }
57
+ }
58
+ }
59
+ /**
60
+ * When this computer is signed in, each run of a local file belongs to the version of its content. Saving sends no
61
+ * request before the run: the version ID comes from the content, and the outbox uploads the version and the run's
62
+ * records while and after it runs. A save failure never stops the run. A run that needs the account starts sign-in.
63
+ */
64
+ async function accountSync(path, flags) {
65
+ const client = new MethodClient(flags.server);
66
+ const runDir = resolve(flags["run-dir"]), linked = join(runDir, "method-sync.json");
67
+ try {
68
+ const outbox = new Outbox(client);
69
+ if (flags.resume) {
70
+ if (!existsSync(linked) || !client.token())
71
+ return undefined;
72
+ const state = JSON.parse(readFileSync(linked, "utf8"));
73
+ const version = await prepareVersion(client, outbox, path);
74
+ if (version.version_id !== state.version_id)
75
+ throw Error("The file changed since this run started. Resume runs the version it started with; its records stay on this computer.");
76
+ return { client, outbox, version, sync: () => new Sync(client, runDir, state.workflow_id, state.version_id, state.id, readDocument(path).run_data === "device", outbox) };
77
+ }
78
+ const method = readDocument(path);
79
+ const setup = await localSetup(path, flags);
80
+ const needs = accountNeeds(method, setup.config, setup.agent);
81
+ if (needs.classification && !client.token())
82
+ await client.login();
83
+ if (!client.token()) {
84
+ process.stderr.write(`Sign in to keep versions and runs in your account${needs.models ? " and to use hosted models" : ""}: method login\n`);
85
+ return undefined;
86
+ }
87
+ const version = await prepareVersion(client, outbox, path);
88
+ return { client, outbox, version, sync: () => new Sync(client, runDir, version.method_id, version.version_id, undefined, method.run_data === "device", outbox) };
89
+ }
90
+ catch (error) {
91
+ process.stderr.write(`Not saved to your Method account: ${error.message} The run continues on this computer.\n`);
92
+ return undefined;
93
+ }
94
+ }
95
+ export async function localMain(args = process.argv.slice(2)) {
96
+ const parsed = parse(args);
97
+ const [command, target] = parsed.positionals;
98
+ const flags = parsed.values;
99
+ if (flags.help || !command) {
100
+ process.stdout.write(help);
101
+ return;
102
+ }
103
+ if (command === "inspect") {
104
+ if (!target || parsed.positionals.length !== 2 || !flags.out)
105
+ throw new Error("Use method inspect RUN_DIRECTORY --out inspection.json.");
106
+ const output = resolve(flags.out);
107
+ if (existsSync(output))
108
+ throw new Error("INSPECTION_EXISTS: choose a new output file.");
109
+ writePrivateJson(output, inspectRun(target, { includeFiles: flags["include-files"] ?? false }));
110
+ process.stdout.write(`Saved run evidence: ${output}\nContains run inputs and results. Load it in the method viewer; no upload occurs.\n`);
111
+ return;
112
+ }
113
+ if (command === "doctor") {
114
+ if (parsed.positionals.length !== 1)
115
+ throw new Error(help);
116
+ const node = checkNode();
117
+ process.stdout.write(node.detail + "\n");
118
+ if (!node.ok) {
119
+ process.exitCode = 1;
120
+ return;
121
+ }
122
+ const config = { allow_local_processes: true }, agent = flags.agent ?? readComputerSettings().agent;
123
+ // Without a local agent, model steps use hosted models after method login; scripts need no agent.
124
+ try {
125
+ config.models = await resolveAgentProfiles({ steps: { agent: { do: { kind: 'agent', model: 'default' } } } }, config, agent);
126
+ }
127
+ catch (error) {
128
+ if (agent || error.code !== 'needs_input')
129
+ throw error;
130
+ process.stdout.write('No local agent found. Model steps use hosted models after method login.\n');
131
+ }
132
+ await checkConfiguration(config);
133
+ process.stdout.write('Runtime configuration checked. No method was run. Use method validate FILE to check the Method and its declared dependencies.\n');
134
+ return;
135
+ }
136
+ if (!["steps", "prompt", "run"].includes(command) || !target || parsed.positionals.length !== 2)
137
+ throw new Error(help);
138
+ if (command === "run")
139
+ return run(target, flags);
140
+ const workflow = loadWorkflow(methodContent(readDocument(resolve(target))));
141
+ if (command === "steps") {
142
+ process.stdout.write(Object.entries(workflow.steps).map(([id, step], index) => `${index + 1}. ${id}: ${step.name ?? id.replaceAll("_", " ")} (${executionLabel(step).toLowerCase()}; ${step.check ? "checked" : "unchecked"})`).join("\n") + "\n");
143
+ return;
144
+ }
145
+ process.stdout.write(renderPrompt(workflow) + "\n");
146
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The runtime configuration for a local Method. No file beside the Method is read: models come from the Method,
3
+ * limits and tools from the Method (tools are copied into the configuration), connections and an own classifier key from this computer (computer.json), and
4
+ * runtimes from PATH. A files connection with no
5
+ * binding uses the folder of the same name beside the Method, when it exists.
6
+ * `base` is a configuration that the SDK made itself (a saved version's package); bindings still apply.
7
+ */
8
+ export declare function localSetup(file: string, flags: {
9
+ workspace?: string;
10
+ agent?: string;
11
+ }, base?: any): Promise<{
12
+ config: any;
13
+ sourceRoot: string;
14
+ agent: string | undefined;
15
+ }>;