@method-ai-hq/sdk 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  MIT-licensed JavaScript API and the `method` CLI. Source and releases: https://github.com/method-ai-hq/method-sdk
4
4
 
5
5
  ```sh
6
- npm install https://github.com/method-ai-hq/method-sdk/releases/download/v0.17.0/method-ai-hq-sdk-0.17.0.tgz
6
+ npm install https://github.com/method-ai-hq/method-sdk/releases/download/v0.17.1/method-ai-hq-sdk-0.17.1.tgz
7
7
  npx method --version
8
8
  ```
9
9
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@method-ai-hq/sdk",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Build and run reusable .method files with checked steps and saved results.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -3,7 +3,6 @@ import { type MethodClient } from './method-client.js';
3
3
  export type ImproveRequest = {
4
4
  step_id?: string;
5
5
  note?: string;
6
- case_id?: string;
7
6
  run_id?: string;
8
7
  };
9
8
  /** Runs a local Method file; the default is the runtime that `method run FILE` uses. */
@@ -21,10 +20,10 @@ export type ImproveProposal = {
21
20
  [key: string]: unknown;
22
21
  };
23
22
  };
24
- type ProposalKind = 'change' | 'case' | 'rubric' | 'script' | 'none';
23
+ type ProposalKind = 'change' | 'none';
25
24
  /**
26
25
  * 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.
26
+ * tested workflow; none has no workflow.
28
27
  */
29
28
  export declare function readImproveResult(result: unknown): ImproveProposal;
30
29
  export declare const judgmentsLine = "Method fixes this Method from your judgments. Record the person's reaction: method judge RUN_ID wrong --note \"...\".";
@@ -11,10 +11,10 @@ import { methodCache } from './prepare.js';
11
11
  import { writePrivateJson } from './files.js';
12
12
  import { currentVersion, methodContent } from './versions.js';
13
13
  import { localRuns, saveLocalProposal } from './proposals.js';
14
- const kinds = ['change', 'case', 'rubric', 'script', 'none'];
14
+ const kinds = ['change', 'none'];
15
15
  /**
16
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.
17
+ * tested workflow; none has no workflow.
18
18
  */
19
19
  export function readImproveResult(result) {
20
20
  const value = result;
@@ -36,18 +36,11 @@ export function readImproveResult(result) {
36
36
  throw Error(`The improvement run says kind ${String(value.kind)}, but its proposal is kind ${evidence.kind}.`);
37
37
  if (evidence.kind === 'change' && (!proposal.workflow || typeof proposal.workflow !== 'object'))
38
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
39
  return { cause: proposal.cause.trim(), workflow: evidence.kind === 'change' ? proposal.workflow : null, evidence };
44
40
  }
45
41
  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.',
42
+ change: `Read the change, then run method apply ${file} ${id}. It does not publish.`,
43
+ none: 'No change passed the tests.',
51
44
  })[kind];
52
45
  const print = (value) => process.stdout.write(JSON.stringify(value, null, 2) + '\n');
53
46
  export const judgmentsLine = 'Method fixes this Method from your judgments. Record the person\'s reaction: method judge RUN_ID wrong --note "...".';
@@ -58,17 +51,15 @@ export const judgmentsLine = 'Method fixes this Method from your judgments. Reco
58
51
  * and saves a local proposal.
59
52
  */
60
53
  export async function improveCommand(args, clientFactory, run) {
61
- const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { case: { type: 'string' }, note: { type: 'string' }, step: { type: 'string' }, server: { type: 'string' } } });
54
+ const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { note: { type: 'string' }, step: { type: 'string' }, server: { type: 'string' } } });
62
55
  if (positionals.length !== 1)
63
- throw Error('Use method improve FILE [--case ID] [--note TEXT] [--step ID].');
56
+ throw Error('Use method improve FILE [--note TEXT] [--step ID].');
64
57
  const file = authoringPath(positionals[0]), document = readDocument(file), workflow = loadWorkflow(methodContent(document));
65
58
  if (values.step && !Object.hasOwn(workflow.steps, values.step))
66
59
  throw Error(`Step ${values.step} is not in ${positionals[0]}.`);
67
- if (values.case && !/^[a-z0-9][a-z0-9-]{0,79}$/.test(values.case))
68
- throw Error('Use a case ID: lowercase letters, digits, and hyphens.');
69
60
  if (values.note !== undefined && !values.note.trim())
70
61
  throw Error('Write the correction after --note.');
71
- const request = { ...(values.step ? { step_id: values.step } : {}), ...(values.note ? { note: values.note.trim() } : {}), ...(values.case ? { case_id: values.case } : {}) };
62
+ const request = { ...(values.step ? { step_id: values.step } : {}), ...(values.note ? { note: values.note.trim() } : {}) };
72
63
  const client = clientFactory(values.server ?? DEFAULT_SERVER);
73
64
  if (!client.token())
74
65
  await client.login();
@@ -119,7 +110,7 @@ export async function improveOnDevice(client, file, request, run) {
119
110
  const improve = await cachedImproveMethod(client);
120
111
  const runDir = join(methodCache(), 'runs', randomUUID());
121
112
  const inputs = join(runDir, 'improve-inputs.json');
122
- 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 });
113
+ writePrivateJson(inputs, { method_file: file, note: request.note ?? '', step_id: request.step_id ?? '', grant_id: '', judgment_id: '', run_id: request.run_id ?? '' });
123
114
  const runFile = run ?? (await import('./current-runtime.js')).runCurrentFile;
124
115
  process.stderr.write(`Improving ${file} on this computer. Its run content stays here.\n`);
125
116
  // The run prints its own result; send it to stderr so that stdout holds only the proposal.
@@ -38,7 +38,7 @@ export const commandHelp = {
38
38
  publish: { usage: "method publish FILE [--reason TEXT] [--accept-failing-case ID[,ID]] [--cloud|--workers] [--env NAME] [--server URL]", purpose: "Mark a version as published, for sharing, schedules, and production runs.", arguments: "Runs the Method's cases first; a version that breaks an approved case is refused unless --accept-failing-case names it, and the version records that. Uses the version of the file's current content: it finishes that upload (no time limit while bytes move), checks the cases, then marks it published with the reason (default: Published.). --accept-failing-case needs --reason. The first save of a new file creates the Method. --cloud runs the production runs of the environment on Method Cloud; --workers runs them on your workers again. --env NAME selects the environment (default production).", result: "JSON with workflow_id, version_id, url, published_at, the cases line, and the open warnings and notes (issues). With --cloud or --workers: placement. Warnings and notes never block a publish.", errors: "An error issue (nothing is published), failing case, --accept-failing-case without --reason, or no network.", example: "method publish task.method --reason 'Shorter introduction'", remote: true },
39
39
  judge: { usage: "method judge RUN_ID right|wrong [--step STEP_ID] [--note TEXT] [--corrected FILE] [--json] [--server URL]", purpose: "Record the person's reaction to a run's result.", arguments: "RUN_ID is the run_id of the run's start line, or the run ID on the dashboard. right: the person used or approved the result. wrong: the person corrected it, or asked to change the Method because of it. --note: the person's words (at most 4000 characters). --corrected FILE: the result that the person says is right; JSON is sent as JSON, other text as text (at most 1 MB). --step: the step whose output was wrong. A wrong judgment makes Method fix the Method in the background: it applies a tested change that the person can undo, or changes nothing. Do not ask the person to confirm a judgment.", result: "One line, for example Recorded: wrong on step choose. Method is fixing it in the background. --json prints the judgment and fixing.", errors: "An unknown run, a run of a Method that is not in your account, or no sign-in.", example: "method judge 6f1c… wrong --step summary --note 'Name the customer in the first sentence.'", remote: true },
40
40
  changes: { usage: "method changes FILE [--json] [--server URL]", purpose: "List the changes that Method applied to a Method.", arguments: "Lists the changes that Method made from wrong judgments, newest first, and the local proposals applied on this computer. Commands that take a signed-in FILE merge a new change into the file first and print one line.", result: "One line per change: its date, its version, and its cause. --json prints {file, method_id, changes: [{id, source, cause, date, version_id, steps}]}. No changes.", errors: "No id: line and no local change.", example: "method changes task.method", remote: true },
41
- improve: { usage: "method improve FILE [--case ID] [--note TEXT] [--step ID] [--server URL]", purpose: "Improve a Method that keeps its run content on this computer.", arguments: "For a Method with run_data: device, or in an organization that keeps run content on devices: runs Method's improvement on this computer, so the run content stays here. --note: the correction, in the person's words; it is about the newest run of the Method on this computer, which the improvement reads and a suggested case records. --step: improve only this step. --case: the case the change must pass. For a Method that keeps run content in the account, it starts nothing and says to use method judge: Method fixes those Methods from the person's judgments.", result: "JSON with the local proposal ID and the next step; the proposal is in .method/proposals/. Nothing is published, and the file does not change. For an account Method, one line.", errors: "An unknown step, or a step of the improvement that fails.", example: "method improve task.method --step summary --note 'Name the customer in the first sentence.'", remote: true },
41
+ improve: { usage: "method improve FILE [--note TEXT] [--step ID] [--server URL]", purpose: "Improve a Method that keeps its run content on this computer.", arguments: "For a Method with run_data: device, or in an organization that keeps run content on devices: runs Method's improvement on this computer, so the run content stays here. --note: the correction, in the person's words; it is about the newest run of the Method on this computer, which the improvement reads. --step: improve only this step. For a Method that keeps run content in the account, it starts nothing and says to use method judge: Method fixes those Methods from the person's judgments.", result: "JSON with the local proposal ID and the next step; the proposal is in .method/proposals/. Nothing is published, and the file does not change. For an account Method, one line.", errors: "An unknown step, or a step of the improvement that fails.", example: "method improve task.method --step summary --note 'Name the customer in the first sentence.'", remote: true },
42
42
  apply: { usage: "method apply FILE [PROPOSAL_ID] [--resolved] [--server URL]", purpose: "Merge a local proposal from method improve into the file.", arguments: "Default: the newest open local proposal. The merge is per step: a part that only the proposal changed takes the change; a part that you and the proposal both changed is a conflict. --resolved: you merged a conflict by hand; this marks the proposal applied. When a change that Method applied conflicts with your edits, the line before the command names it; give its ID to see both versions.", result: "JSON with status applied and the changed steps; the file changes and the proposal is marked applied. Nothing is published. A conflict lists each part with the base, your, and the proposed value, changes nothing, and exits 1.", errors: "No open proposal, or a conflict.", example: "method apply task.method", remote: true },
43
43
  secret: { usage: "method secret find [FILE]\nmethod secret import FILE NAME...\nmethod secret set NAME\nmethod secret list [NAME...]", purpose: "Give this computer the values of a Method's declared secrets.", arguments: "find lists the KEY=VALUE files in this folder (3 levels down) and in the parent folder (2 levels down) with the key names in each, never values; for the Method FILE (or the only Method here) it says which declared secrets each file holds and prints the import command. import copies the named values from a KEY=VALUE file that the user names, without printing them. set opens a private form on 127.0.0.1 in the browser for one value. list shows names and where each value is found (shell, this computer, or missing), never values. Values are kept in ~/.config/method/secrets.json (mode 0600) and are never sent to Method. A value exported in the shell is used first. Every script of the Method receives all of its declared secrets.", result: "JSON with the saved names, or the list.", errors: "A name is missing from the file, or no value was entered.", example: "method secret find\nmethod secret import ../service/.env ARCHIVE_TOKEN" },
44
44
  connect: { usage: "method connect [APP_FOLDER] [--file METHOD_FILE]", purpose: "Connect an app to the Method in this folder, so the app runs it in production.", arguments: "Run it in the Method's folder. APP_FOLDER (default: this folder) is the app's folder. It makes a service key named after the app folder and writes METHOD_API_KEY to the app's .env (a new file, or a new or replaced line); it never prints the key. It adds .env to .gitignore in a git repository. When the Method has no published version, it publishes the current file. It detects Node (package.json) or Python (pyproject.toml, requirements.txt), and prints the install line and the code to add. Run it again: an app with a working key keeps it.", result: "JSON with the method_id, the published version, where the key is, install, code, secrets_to_set_on_the_host, and next.", errors: "No or several .method files (give --file), an app folder with no language marker, or a failing case at publish.", example: "method connect ../app", remote: true },
@@ -184,17 +184,6 @@ export async function localRuns(file) {
184
184
  }
185
185
  return runs;
186
186
  }
187
- /** What the coding agent does for a proposal that is not a change to the Method document. runFolder is the folder of the suggested case's run, when it is on this computer. */
188
- function manualStep(file, proposal, runFolder) {
189
- const evidence = proposal.evidence ?? {};
190
- if (evidence.case_suggestion) {
191
- const c = evidence.case_suggestion, quote = (value) => JSON.stringify(value);
192
- return `Record the case: method case new ${file} --id ${c.id} --note ${quote(c.note)} --run ${runFolder ? quote(runFolder) : 'RUN_FOLDER'}${(c.rubric ?? []).map((r) => ` --rubric ${quote(r)}`).join('')}${runFolder ? '' : ', where RUN_FOLDER is the folder of the run that went wrong'}. Then run method improve ${file} --case ${c.id}, show the proposal, apply it, and run again.`;
193
- }
194
- if (evidence.script_change)
195
- return `Change the script, then run method test ${file}: ${evidence.script_change}`;
196
- return 'This proposal has no change to apply.';
197
- }
198
187
  const print = (value) => process.stdout.write(JSON.stringify(value, null, 2) + '\n');
199
188
  const changeLine = (change) => `${change.date.slice(0, 10)} ${change.version_id ?? 'not saved as a version'} ${change.cause}`;
200
189
  /** `method changes FILE`: the changes that Method applied to the Method, newest first, and those applied on this computer. */
@@ -246,13 +235,8 @@ export async function proposalCommand(args, clientFactory) {
246
235
  throw Error(`Proposal ${proposal.id} is ${proposal.status}.`);
247
236
  if (values.resolved)
248
237
  return print({ status: 'applied', file, proposal_id: proposal.id, ...await markApplied(client, file, proposal), next: `Run method test ${target}. Publish it when it is right.` });
249
- if (!proposal.proposed_workflow) {
250
- // The suggested case's run is a local folder (a local improvement) or an account run ID (an account improvement).
251
- const runId = proposal.evidence?.case_suggestion?.run_id;
252
- const runFolder = runId ? (await localRuns(file)).find(run => run.dir === runId || run.account_run_id === runId)?.dir : undefined;
253
- process.exitCode = 1;
254
- return print({ status: 'manual', file, proposal_id: proposal.id, kind: proposal.evidence?.kind ?? null, cause: proposal.cause, next: manualStep(target, proposal, runFolder) });
255
- }
238
+ if (!proposal.proposed_workflow)
239
+ return print({ status: 'none', file, proposal_id: proposal.id, cause: proposal.cause, next: 'No change passed the tests; there is nothing to apply.' });
256
240
  const result = await applyProposal(client, file, proposal);
257
241
  if (result.status === 'applied')
258
242
  return print({ ...result, file, proposal_id: proposal.id, cause: proposal.cause, next: `Run method test ${target}. Publish it when it is right.` });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@method-ai-hq/sdk",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Build and run reusable .method files with checked steps and saved results.",
5
5
  "license": "MIT",
6
6
  "type": "module",