@farmslot/recipe-cli 0.5.0 → 0.7.0

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 (53) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +11 -11
  3. package/dist/harness/acceptance-ledger.d.ts +18 -0
  4. package/dist/harness/acceptance-ledger.d.ts.map +1 -0
  5. package/dist/harness/acceptance-ledger.js +119 -0
  6. package/dist/harness/acceptance-ledger.js.map +1 -0
  7. package/dist/harness/adapter-plugins.d.ts +105 -0
  8. package/dist/harness/adapter-plugins.d.ts.map +1 -0
  9. package/dist/harness/adapter-plugins.js +388 -0
  10. package/dist/harness/adapter-plugins.js.map +1 -0
  11. package/dist/harness/command-contract.d.ts +69 -0
  12. package/dist/harness/command-contract.d.ts.map +1 -0
  13. package/dist/harness/command-contract.js +243 -0
  14. package/dist/harness/command-contract.js.map +1 -0
  15. package/dist/harness/commands/call.d.ts.map +1 -1
  16. package/dist/harness/commands/call.js +131 -127
  17. package/dist/harness/commands/call.js.map +1 -1
  18. package/dist/harness/commands/run.d.ts.map +1 -1
  19. package/dist/harness/commands/run.js +158 -125
  20. package/dist/harness/commands/run.js.map +1 -1
  21. package/dist/harness/harness-cli.d.ts +82 -0
  22. package/dist/harness/harness-cli.d.ts.map +1 -0
  23. package/dist/harness/harness-cli.js +319 -0
  24. package/dist/harness/harness-cli.js.map +1 -0
  25. package/dist/harness/index.d.ts +6 -3
  26. package/dist/harness/index.d.ts.map +1 -1
  27. package/dist/harness/index.js +5 -2
  28. package/dist/harness/index.js.map +1 -1
  29. package/dist/harness/live-adapter-contract.d.ts +9 -0
  30. package/dist/harness/live-adapter-contract.d.ts.map +1 -1
  31. package/dist/harness/live-adapter-contract.js +38 -7
  32. package/dist/harness/live-adapter-contract.js.map +1 -1
  33. package/dist/harness/network-observation.d.ts +1 -4
  34. package/dist/harness/network-observation.d.ts.map +1 -1
  35. package/dist/harness/network-observation.js +3 -8
  36. package/dist/harness/network-observation.js.map +1 -1
  37. package/dist/harness/plugin-imports.d.ts +23 -0
  38. package/dist/harness/plugin-imports.d.ts.map +1 -0
  39. package/dist/harness/plugin-imports.js +126 -0
  40. package/dist/harness/plugin-imports.js.map +1 -0
  41. package/dist/harness/recipe-validation.d.ts +2 -0
  42. package/dist/harness/recipe-validation.d.ts.map +1 -1
  43. package/dist/harness/recipe-validation.js +42 -0
  44. package/dist/harness/recipe-validation.js.map +1 -1
  45. package/dist/harness/run-engine.d.ts +27 -8
  46. package/dist/harness/run-engine.d.ts.map +1 -1
  47. package/dist/harness/run-engine.js +86 -86
  48. package/dist/harness/run-engine.js.map +1 -1
  49. package/dist/harness/run-observers.d.ts +1 -4
  50. package/dist/harness/run-observers.d.ts.map +1 -1
  51. package/dist/harness/run-observers.js +6 -3
  52. package/dist/harness/run-observers.js.map +1 -1
  53. package/package.json +3 -3
@@ -0,0 +1,243 @@
1
+ // The strict public grammar a host CLI checks before commander can consume a
2
+ // typo as a value: each public command declares its options and positionals,
3
+ // and a mismatch becomes a stable, machine-readable usage error.
4
+ import { harnessHost } from './host.js';
5
+ import { closest } from './suggest.js';
6
+ export const booleanOption = () => ({ kind: 'boolean' });
7
+ export const valueOption = (choices) => ({
8
+ kind: 'value',
9
+ ...(choices ? { choices } : {}),
10
+ });
11
+ export const optionalValueOption = (choices) => ({
12
+ kind: 'optional-value',
13
+ ...(choices ? { choices } : {}),
14
+ });
15
+ export const contractOptions = (...groups) => Object.assign({}, ...groups);
16
+ /**
17
+ * The usage error for `argv`, or null when it is valid. `commands` is the
18
+ * host's public table; its order is the order "Valid commands" lists.
19
+ */
20
+ export function validatePublicInvocation(argv, commands, validation = {}) {
21
+ const host = harnessHost().name;
22
+ const examples = Object.fromEntries(commands.map((command) => [command.name, command.example]));
23
+ const token = argv[0];
24
+ if (!token || token === '--help' || token === '-h' || token === '--version' || token === '-v')
25
+ return null;
26
+ const resolved = resolveContractedCommand(token, commands);
27
+ if (!resolved) {
28
+ const suggestion = closest(token, publicCommandTokens(commands));
29
+ if (token.startsWith('-')) {
30
+ return {
31
+ code: 'CLI_UNKNOWN_OPTION',
32
+ command: host,
33
+ message: `unknown top-level option '${token}'. Valid top-level options: --help, --version.`,
34
+ userAction: actionFor(token, closest(token, ['--help', '--version']), `${host} --help`),
35
+ };
36
+ }
37
+ return {
38
+ code: 'CLI_UNKNOWN_COMMAND',
39
+ command: token,
40
+ message: `unknown command '${token}'. Valid commands: ${commands.map((command) => command.name).join(', ')}.`,
41
+ userAction: actionFor(token, suggestion, suggestion
42
+ ? exampleFor(host, resolveContractedCommand(suggestion, commands)?.name, examples)
43
+ : `${host} --help`),
44
+ };
45
+ }
46
+ const { name, contract } = resolved;
47
+ const tokens = argv.slice(1);
48
+ if (contract.bypass?.(tokens))
49
+ return null;
50
+ const fail = {
51
+ usage: (code, message) => usageFailure(host, code, name, message, examples),
52
+ missingPositional: (message) => missingPositionalFailure(host, name, message, contract, examples),
53
+ };
54
+ const positionals = [];
55
+ const seenOptions = new Set();
56
+ const validOptions = Object.keys(contract.options);
57
+ for (let index = 0; index < tokens.length; index += 1) {
58
+ const argument = tokens[index] ?? '';
59
+ if (argument === '--') {
60
+ if (!contract.allowPassthrough) {
61
+ return fail.usage('CLI_UNEXPECTED_PASSTHROUGH', 'this command does not accept `--` passthrough.');
62
+ }
63
+ break;
64
+ }
65
+ if (!argument.startsWith('-') || argument === '-') {
66
+ positionals.push(argument);
67
+ continue;
68
+ }
69
+ const equals = argument.indexOf('=');
70
+ const optionName = equals === -1 ? argument : argument.slice(0, equals);
71
+ const inlineValue = equals === -1 ? undefined : argument.slice(equals + 1);
72
+ const spec = contract.options[optionName];
73
+ if (!spec) {
74
+ const suggestion = validation.replacedOptions?.[optionName] ?? closest(optionName, validOptions);
75
+ return {
76
+ code: 'CLI_UNKNOWN_OPTION',
77
+ command: name,
78
+ message: `unknown option '${optionName}'.`,
79
+ userAction: actionFor(optionName, suggestion, exampleFor(host, name, examples)),
80
+ };
81
+ }
82
+ seenOptions.add(optionName);
83
+ if (spec.kind === 'boolean') {
84
+ if (inlineValue !== undefined) {
85
+ return fail.usage('CLI_INVALID_OPTION_VALUE', `${optionName} is a flag and does not take a value.`);
86
+ }
87
+ continue;
88
+ }
89
+ if (spec.kind === 'optional-value' && inlineValue === undefined)
90
+ continue;
91
+ const optionValue = inlineValue ?? tokens[index + 1];
92
+ const nextTokenIsOption = inlineValue === undefined &&
93
+ (optionValue === '-h' || optionValue === '--' || optionValue?.startsWith('--'));
94
+ if (optionValue === undefined ||
95
+ (spec.kind === 'value' && optionValue === '') ||
96
+ nextTokenIsOption) {
97
+ return fail.usage('CLI_MISSING_OPTION_VALUE', `${optionName} requires a value.`);
98
+ }
99
+ if (inlineValue === undefined)
100
+ index += 1;
101
+ const choices = typeof spec.choices === 'function' ? spec.choices(tokens) : spec.choices;
102
+ if (choices && !choices.includes(optionValue)) {
103
+ const suggestion = closest(optionValue, choices);
104
+ return {
105
+ code: 'CLI_INVALID_OPTION_VALUE',
106
+ command: name,
107
+ message: `${optionName} must be ${formatChoiceList(choices)}; received '${optionValue}'.`,
108
+ userAction: actionFor(optionValue, suggestion, exampleFor(host, name, examples)),
109
+ };
110
+ }
111
+ }
112
+ if (seenOptions.has('--help') || seenOptions.has('-h'))
113
+ return null;
114
+ const refined = contract.refine?.(positionals, seenOptions, fail);
115
+ if (refined)
116
+ return refined;
117
+ if (contract.leadingPositionals &&
118
+ !contract.requiredUnless?.some((option) => seenOptions.has(option)) &&
119
+ tokens
120
+ .slice(0, contract.leadingPositionals)
121
+ .some((argument) => !argument || argument.startsWith('-'))) {
122
+ const missing = contract.positionals?.[0]?.label ?? 'argument';
123
+ return fail.missingPositional(`${name} requires <${missing}> first.`);
124
+ }
125
+ const forbiddingOption = contract.noPositionalsWith?.find((option) => seenOptions.has(option));
126
+ if (forbiddingOption && positionals.length > 0) {
127
+ return fail.usage('CLI_EXCESS_POSITIONAL', `${forbiddingOption} does not accept positional '${positionals[0]}'.`);
128
+ }
129
+ const minimum = contract.requiredUnless?.some((option) => seenOptions.has(option))
130
+ ? 0
131
+ : (contract.minimumPositionals ?? 0);
132
+ if (positionals.length < minimum) {
133
+ const missingSpec = contract.positionals?.[positionals.length];
134
+ const missing = missingSpec?.label ?? 'argument';
135
+ const valid = missingSpec?.choices?.length
136
+ ? ` Choose one: ${missingSpec.choices.join('|')}.`
137
+ : '';
138
+ const usage = contract.usage ? ` Usage: ${contract.usage}.` : '';
139
+ return fail.missingPositional(`missing required <${missing}>.${valid}${usage}`);
140
+ }
141
+ const fixed = contract.positionals ?? [];
142
+ for (let index = 0; index < Math.min(positionals.length, fixed.length); index += 1) {
143
+ if (invalidPositional(positionals[index] ?? '', fixed[index]))
144
+ return positionalFailure(host, name, positionals[index] ?? '', fixed[index], examples);
145
+ }
146
+ if (positionals.length > fixed.length && !contract.variadic) {
147
+ const unexpected = positionals[fixed.length] ?? '';
148
+ return fail.usage('CLI_EXCESS_POSITIONAL', `unexpected positional '${unexpected}'; this command accepts ${formatPositionals(contract)}.`);
149
+ }
150
+ if (contract.variadic) {
151
+ for (const positional of positionals.slice(fixed.length)) {
152
+ if (invalidPositional(positional, contract.variadic)) {
153
+ return positionalFailure(host, name, positional, contract.variadic, examples);
154
+ }
155
+ }
156
+ }
157
+ return null;
158
+ }
159
+ /** Every value `option` takes in `tokens` before any `--`, separate (`--x v`) or inline (`--x=v`). */
160
+ export function optionValues(tokens, option) {
161
+ const values = [];
162
+ const divider = tokens.indexOf('--');
163
+ const scope = divider === -1 ? tokens : tokens.slice(0, divider);
164
+ for (let index = 0; index < scope.length; index += 1) {
165
+ const token = scope[index] ?? '';
166
+ if (token === option && index + 1 < scope.length)
167
+ values.push(scope[(index += 1)] ?? '');
168
+ else if (token.startsWith(`${option}=`))
169
+ values.push(token.slice(option.length + 1));
170
+ }
171
+ return values;
172
+ }
173
+ /** Every public command name and alias, in table order. */
174
+ export function publicCommandTokens(commands) {
175
+ return commands.flatMap((command) => [command.name, ...(command.aliases ?? [])]);
176
+ }
177
+ function resolveContractedCommand(token, commands) {
178
+ return (commands.find((command) => command.name === token) ??
179
+ commands.find((command) => command.aliases?.includes(token)));
180
+ }
181
+ function usageFailure(host, code, command, message, examples) {
182
+ return {
183
+ code,
184
+ command,
185
+ message,
186
+ userAction: `Try: ${exampleFor(host, command, examples)}. Inspect options: ${host} ${command} --help`,
187
+ };
188
+ }
189
+ function missingPositionalFailure(host, command, message, contract, examples) {
190
+ if (contract.missingPositionalAction) {
191
+ return {
192
+ code: 'CLI_MISSING_POSITIONAL',
193
+ command,
194
+ message,
195
+ userAction: contract.missingPositionalAction(exampleFor(host, command, examples)),
196
+ };
197
+ }
198
+ return usageFailure(host, 'CLI_MISSING_POSITIONAL', command, message, examples);
199
+ }
200
+ function positionalFailure(host, command, received, spec, examples) {
201
+ const valid = spec.validDescription ??
202
+ (spec.choices
203
+ ? spec.choices.join(', ')
204
+ : spec.pattern || spec.validate
205
+ ? `a valid <${spec.label}>`
206
+ : `<${spec.label}>`);
207
+ const suggestion = spec.choices ? closest(received, spec.choices) : undefined;
208
+ return {
209
+ code: 'CLI_INVALID_POSITIONAL',
210
+ command,
211
+ message: `invalid <${spec.label}> '${received}'. Valid values: ${valid}.`,
212
+ userAction: actionFor(received, suggestion, exampleFor(host, command, examples)),
213
+ };
214
+ }
215
+ function invalidPositional(value, spec) {
216
+ if (!spec)
217
+ return true;
218
+ if (spec.choices && !spec.choices.includes(value))
219
+ return true;
220
+ if (spec.validate && !spec.validate(value))
221
+ return true;
222
+ return Boolean(spec.pattern && !spec.pattern.test(value));
223
+ }
224
+ function formatChoiceList(choices) {
225
+ if (choices.length === 1)
226
+ return choices[0] ?? '';
227
+ if (choices.length === 2)
228
+ return `${choices[0]} or ${choices[1]}`;
229
+ return `${choices.slice(0, -1).join(', ')}, or ${choices[choices.length - 1]}`;
230
+ }
231
+ function formatPositionals(contract) {
232
+ const fixed = (contract.positionals ?? []).map((spec) => `<${spec.label}>`);
233
+ if (contract.variadic)
234
+ fixed.push(`[<${contract.variadic.label}> ...]`);
235
+ return fixed.length > 0 ? fixed.join(' ') : 'no positionals';
236
+ }
237
+ function actionFor(received, suggestion, example) {
238
+ return `${suggestion ? `Did you mean '${suggestion}' instead of '${received}'? ` : ''}Try: ${example}`;
239
+ }
240
+ function exampleFor(host, command, examples) {
241
+ return command ? (examples[command] ?? `${host} ${command} --help`) : `${host} --help`;
242
+ }
243
+ //# sourceMappingURL=command-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-contract.js","sourceRoot":"","sources":["../../src/harness/command-contract.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../../src/harness/commands/call.ts"],"names":[],"mappings":"AAaA,OAAO,EAKL,KAAK,aAAa,EAGnB,MAAM,eAAe,CAAC;AAsBvB,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAOL,KAAK,YAAY,EAIlB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,KAAK,eAAe,EAAyC,MAAM,UAAU,CAAC;AAEvF,MAAM,WAAW,kBAAkB,CAAC,SAAS,EAAE,UAAU,SAAS,gBAAgB;IAChF,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC5C,YAAY,CAAC,EAAE,eAAe,CAAC;IAG/B,aAAa,CAAC,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;CAC9D;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,UAAU,SAAS,gBAAgB,EAC7E,IAAI,EAAE,MAAM,EAAE,EACd,cAAc,EAAE,kBAAkB,CAAC,SAAS,EAAE,UAAU,CAAC,GACxD,OAAO,CAAC,MAAM,CAAC,CAmfjB;AAoGD,+EAA+E;AAC/E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG9E;AA0BD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAK,GAAG,OAAO,CAKjE;AAOD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE;IAAE,OAAO,EAAE,aAAa,CAAA;CAAE,GACzC,OAAO,CAAC,MAAM,CAAC,CA+CjB"}
1
+ {"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../../src/harness/commands/call.ts"],"names":[],"mappings":"AAaA,OAAO,EAKL,KAAK,aAAa,EAGnB,MAAM,eAAe,CAAC;AAsBvB,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAQL,KAAK,YAAY,EAIlB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,KAAK,eAAe,EAAyC,MAAM,UAAU,CAAC;AAEvF,MAAM,WAAW,kBAAkB,CAAC,SAAS,EAAE,UAAU,SAAS,gBAAgB;IAChF,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC5C,YAAY,CAAC,EAAE,eAAe,CAAC;IAG/B,aAAa,CAAC,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;CAC9D;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,UAAU,SAAS,gBAAgB,EAC7E,IAAI,EAAE,MAAM,EAAE,EACd,cAAc,EAAE,kBAAkB,CAAC,SAAS,EAAE,UAAU,CAAC,GACxD,OAAO,CAAC,MAAM,CAAC,CA0fjB;AAoGD,+EAA+E;AAC/E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG9E;AA0BD,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAK,GAAG,OAAO,CAKjE;AAOD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE;IAAE,OAAO,EAAE,aAAa,CAAA;CAAE,GACzC,OAAO,CAAC,MAAM,CAAC,CA+CjB"}
@@ -18,7 +18,7 @@ import { isRecord, optionFlag, optionString, parseArgs, resolveAdapter, shellQuo
18
18
  import { resolveCommandManifest } from '../recipe-library.js';
19
19
  import { validateRecipeAdapterAware } from '../recipe-validation.js';
20
20
  import { formatRunDiagnosticsForHuman, readRunDiagnosticsDocument, } from '../run-diagnostics.js';
21
- import { emitHealViolation, executeWithHealBounds, persistRunEffects, preflightRecipe, prepareHeal, runRecipe, synthesizeOneNodeRecipe, } from '../run-engine.js';
21
+ import { activateRecipeRuntimeEnvironment, emitHealViolation, executeWithHealBounds, persistRunEffects, preflightRecipe, prepareHeal, runRecipe, synthesizeOneNodeRecipe, } from '../run-engine.js';
22
22
  import { startRunObservers } from '../run-observers.js';
23
23
  import { recipeRunOptionsFromCli } from '../run-options.js';
24
24
  import { checkoutBusyOut, EXIT, usageOut } from '../shared.js';
@@ -273,145 +273,149 @@ export async function handleCall(argv, commandOptions) {
273
273
  },
274
274
  }),
275
275
  };
276
- let preflightedExecution;
276
+ // One environment scope for the call: preflight, the runtime check, the
277
+ // observers and the execution all see the same ports.
278
+ const restoreRuntimeEnvironment = activateRecipeRuntimeEnvironment(adapter, target, callRuntimeOptions);
277
279
  try {
278
- preflightedExecution = await preflightRecipe(engine, adapter, recipe, artifactsDir, target, actionManifestOverride, callRuntimeOptions);
279
- }
280
- catch (error) {
281
- const trustFailure = recipeTrustFailure(error);
282
- if (!trustFailure)
283
- throw error;
284
- const planDigest = trustFailure.details?.recipeDigest;
285
- if (planDigest) {
286
- trustFailure.userAction =
287
- `review the plan, then rerun this call with --artifacts-dir ${shellQuote(artifactsDir)} ` +
288
- `--approve-plan ${shellQuote(planDigest)}; managed callers must keep the same artifact ` +
289
- `directory and execution environment, then set ` +
290
- `FARMSLOT_RECIPE_APPROVE_PLAN=${shellQuote(planDigest)}`;
291
- }
292
- reportTrustFailure('call', trustFailure, json);
293
- return EXIT.validation;
294
- }
295
- const lock = acquireCheckoutLock(target, 'call');
296
- if ('message' in lock) {
297
- return checkoutBusyOut(json, 'call', lock.message, lock.path);
298
- }
299
- try {
300
- const prepared = await prepareHeal(adapter, target, options, json, {
301
- appRestartAuthored: resolvedAction === 'app.lifecycle' && args.command === 'restart',
302
- });
303
- if (typeof prepared === 'number')
304
- return prepared;
305
- const { state } = prepared;
306
- preflightedExecution = await preflightRecipe(engine, adapter, recipe, artifactsDir, target, actionManifestOverride, callRuntimeOptions);
307
- const ports = {
308
- cdpPort: callRuntimeOptions.cdpPort,
309
- watcherPort: callRuntimeOptions.watcherPort,
310
- };
311
- const started = await startRunObservers(adapter, target, artifactsDir, ports);
312
- observers = started;
313
- let executionResult;
280
+ let preflightedExecution;
314
281
  try {
315
- executionResult = await executeWithHealBounds(() => {
316
- const execution = preflightedExecution;
317
- preflightedExecution = undefined;
318
- return runRecipe(engine, adapter, recipe, artifactsDir, target, actionManifestOverride, callRuntimeOptions, execution, state);
319
- }, target, state);
282
+ preflightedExecution = await preflightRecipe(engine, adapter, recipe, artifactsDir, target, actionManifestOverride, callRuntimeOptions);
320
283
  }
321
284
  catch (error) {
322
- await started.abandon();
323
- observers = undefined;
324
- if (error instanceof ProvenanceDriftError) {
325
- const failure = provenanceFailure(error);
326
- if (json) {
327
- console.log(JSON.stringify({
328
- schemaVersion: 1,
329
- command: 'call',
330
- adapter,
331
- action: shortName,
332
- resolvedAction,
333
- status: 'fail',
334
- error: failure,
335
- exitCode: error.exitCode,
336
- }, null, 2));
337
- }
338
- else {
339
- console.error(`✗ ${host} call: ${error.message}`);
340
- console.error(` Next: ${error.userAction}`);
341
- }
342
- return error.exitCode;
285
+ const trustFailure = recipeTrustFailure(error);
286
+ if (!trustFailure)
287
+ throw error;
288
+ const planDigest = trustFailure.details?.recipeDigest;
289
+ if (planDigest) {
290
+ trustFailure.userAction =
291
+ `review the plan, then rerun this call with --artifacts-dir ${shellQuote(artifactsDir)} ` +
292
+ `--approve-plan ${shellQuote(planDigest)}; managed callers must keep the same artifact ` +
293
+ `directory and execution environment, then set ` +
294
+ `FARMSLOT_RECIPE_APPROVE_PLAN=${shellQuote(planDigest)}`;
343
295
  }
344
- throw error;
296
+ reportTrustFailure('call', trustFailure, json);
297
+ return EXIT.validation;
345
298
  }
346
- const { result, violation } = executionResult;
347
- await started.finalize(result.artifactManifestPath);
348
- observers = undefined;
349
- persistRunEffects(result.summaryPath, result.artifactManifestPath, state);
350
- if (violation !== null) {
351
- const conciseFailure = violation.originalError
352
- ? conciseFailureForHuman(violation.originalError)
353
- : '';
354
- const taughtViolation = violation.code === 'APP_LOGIC_FAILURE' &&
355
- conciseFailure.includes(' requires ') &&
356
- describedAction
357
- ? {
358
- ...violation,
359
- userAction: `${host} actions ${resolvedAction} --adapter ${adapter} --json`,
360
- }
361
- : violation;
362
- return emitHealViolation(json, 'call', result, taughtViolation, state, adapter);
299
+ const lock = acquireCheckoutLock(target, 'call');
300
+ if ('message' in lock) {
301
+ return checkoutBusyOut(json, 'call', lock.message, lock.path);
363
302
  }
364
- const callOutput = readCallOutput(result.tracePath);
365
- const safeArgs = redactCallValue(args);
366
- const safeCallOutput = redactCallValue(callOutput);
367
- const failureUserAction = `${host} last --target ${shellQuote(target)} --json`;
368
- if (json) {
369
- console.log(JSON.stringify({
370
- schemaVersion: 1,
371
- command: 'call',
372
- adapter,
373
- action: shortName,
374
- resolvedAction,
375
- args: safeArgs,
376
- ...(Object.keys(defaultsUsed).length > 0 ? { defaultsUsed } : {}),
377
- status: result.status,
378
- summaryPath: result.summaryPath,
379
- tracePath: result.tracePath,
380
- artifactManifestPath: result.artifactManifestPath,
381
- ...(result.diagnosticsPath ? { diagnosticsPath: result.diagnosticsPath } : {}),
382
- ...(result.sideFindings ? { sideFindings: result.sideFindings } : {}),
383
- ...(callOutput !== undefined ? { output: safeCallOutput } : {}),
384
- recovered: state.recovered,
385
- mutations: state.mutations,
386
- exitCode: result.status === 'pass' ? EXIT.ok : EXIT.runtime,
387
- ...(result.status === 'fail'
303
+ try {
304
+ const prepared = await prepareHeal(adapter, target, options, json, {
305
+ appRestartAuthored: resolvedAction === 'app.lifecycle' && args.command === 'restart',
306
+ });
307
+ if (typeof prepared === 'number')
308
+ return prepared;
309
+ const { state } = prepared;
310
+ preflightedExecution = await preflightRecipe(engine, adapter, recipe, artifactsDir, target, actionManifestOverride, callRuntimeOptions);
311
+ const started = await startRunObservers(adapter, target, artifactsDir);
312
+ observers = started;
313
+ let executionResult;
314
+ try {
315
+ executionResult = await executeWithHealBounds(() => {
316
+ const execution = preflightedExecution;
317
+ preflightedExecution = undefined;
318
+ return runRecipe(engine, adapter, recipe, artifactsDir, target, actionManifestOverride, callRuntimeOptions, execution, state);
319
+ }, target, state);
320
+ }
321
+ catch (error) {
322
+ await started.abandon();
323
+ observers = undefined;
324
+ if (error instanceof ProvenanceDriftError) {
325
+ const failure = provenanceFailure(error);
326
+ if (json) {
327
+ console.log(JSON.stringify({
328
+ schemaVersion: 1,
329
+ command: 'call',
330
+ adapter,
331
+ action: shortName,
332
+ resolvedAction,
333
+ status: 'fail',
334
+ error: failure,
335
+ exitCode: error.exitCode,
336
+ }, null, 2));
337
+ }
338
+ else {
339
+ console.error(`✗ ${host} call: ${error.message}`);
340
+ console.error(` Next: ${error.userAction}`);
341
+ }
342
+ return error.exitCode;
343
+ }
344
+ throw error;
345
+ }
346
+ const { result, violation } = executionResult;
347
+ await started.finalize(result.artifactManifestPath);
348
+ observers = undefined;
349
+ persistRunEffects(result.summaryPath, result.artifactManifestPath, state);
350
+ if (violation !== null) {
351
+ const conciseFailure = violation.originalError
352
+ ? conciseFailureForHuman(violation.originalError)
353
+ : '';
354
+ const taughtViolation = violation.code === 'APP_LOGIC_FAILURE' &&
355
+ conciseFailure.includes(' requires ') &&
356
+ describedAction
388
357
  ? {
389
- error: {
390
- code: 'ACTION_EXECUTION_FAILED',
391
- message: `${resolvedAction} failed; inspect the persisted result and evidence paths`,
392
- userAction: failureUserAction,
393
- },
358
+ ...violation,
359
+ userAction: `${host} actions ${resolvedAction} --adapter ${adapter} --json`,
394
360
  }
395
- : {}),
396
- }, null, 2));
361
+ : violation;
362
+ return emitHealViolation(json, 'call', result, taughtViolation, state, adapter);
363
+ }
364
+ const callOutput = readCallOutput(result.tracePath);
365
+ const safeArgs = redactCallValue(args);
366
+ const safeCallOutput = redactCallValue(callOutput);
367
+ const failureUserAction = `${host} last --target ${shellQuote(target)} --json`;
368
+ if (json) {
369
+ console.log(JSON.stringify({
370
+ schemaVersion: 1,
371
+ command: 'call',
372
+ adapter,
373
+ action: shortName,
374
+ resolvedAction,
375
+ args: safeArgs,
376
+ ...(Object.keys(defaultsUsed).length > 0 ? { defaultsUsed } : {}),
377
+ status: result.status,
378
+ summaryPath: result.summaryPath,
379
+ tracePath: result.tracePath,
380
+ artifactManifestPath: result.artifactManifestPath,
381
+ ...(result.diagnosticsPath ? { diagnosticsPath: result.diagnosticsPath } : {}),
382
+ ...(result.sideFindings ? { sideFindings: result.sideFindings } : {}),
383
+ ...(callOutput !== undefined ? { output: safeCallOutput } : {}),
384
+ recovered: state.recovered,
385
+ mutations: state.mutations,
386
+ exitCode: result.status === 'pass' ? EXIT.ok : EXIT.runtime,
387
+ ...(result.status === 'fail'
388
+ ? {
389
+ error: {
390
+ code: 'ACTION_EXECUTION_FAILED',
391
+ message: `${resolvedAction} failed; inspect the persisted result and evidence paths`,
392
+ userAction: failureUserAction,
393
+ },
394
+ }
395
+ : {}),
396
+ }, null, 2));
397
+ }
398
+ else {
399
+ const renderedInputs = Object.keys(args).length > 0 ? formatCallOutput(safeArgs) : '';
400
+ const out = (style, text) => color(style, text, { stream: process.stdout });
401
+ const diagnostics = formatRunDiagnosticsForHuman(readRunDiagnosticsDocument(result.diagnosticsPath), adapter);
402
+ const renderedDiagnostics = `${out('label', 'Diagnostics:')}\n${diagnostics.map((line) => ` ${line}`).join('\n')}\n`;
403
+ console.log(`${out('label', 'call')} ${out('cmd', resolvedAction)}: ${out(result.status === 'pass' ? 'ok' : 'err', result.status)}` +
404
+ `${renderedInputs ? `\n${out('label', 'Inputs:')}\n${renderedInputs}` : ''}` +
405
+ `${Object.keys(defaultsUsed).length > 0 ? `\n${renderDefaultsUsed(defaultsUsed, process.stdout)}` : ''}` +
406
+ `${callOutput !== undefined ? `\n${out('label', 'Result:')}\n${formatCallOutput(safeCallOutput)}` : ''}\n` +
407
+ renderedDiagnostics +
408
+ `${out('label', 'Artifacts:')} ${out('path', result.artifactManifestPath)}` +
409
+ (result.status === 'fail' ? `\n Next: ${failureUserAction}` : ''));
410
+ }
411
+ return result.status === 'pass' ? EXIT.ok : EXIT.runtime;
397
412
  }
398
- else {
399
- const renderedInputs = Object.keys(args).length > 0 ? formatCallOutput(safeArgs) : '';
400
- const out = (style, text) => color(style, text, { stream: process.stdout });
401
- const diagnostics = formatRunDiagnosticsForHuman(readRunDiagnosticsDocument(result.diagnosticsPath), adapter);
402
- const renderedDiagnostics = `${out('label', 'Diagnostics:')}\n${diagnostics.map((line) => ` ${line}`).join('\n')}\n`;
403
- console.log(`${out('label', 'call')} ${out('cmd', resolvedAction)}: ${out(result.status === 'pass' ? 'ok' : 'err', result.status)}` +
404
- `${renderedInputs ? `\n${out('label', 'Inputs:')}\n${renderedInputs}` : ''}` +
405
- `${Object.keys(defaultsUsed).length > 0 ? `\n${renderDefaultsUsed(defaultsUsed, process.stdout)}` : ''}` +
406
- `${callOutput !== undefined ? `\n${out('label', 'Result:')}\n${formatCallOutput(safeCallOutput)}` : ''}\n` +
407
- renderedDiagnostics +
408
- `${out('label', 'Artifacts:')} ${out('path', result.artifactManifestPath)}` +
409
- (result.status === 'fail' ? `\n Next: ${failureUserAction}` : ''));
413
+ finally {
414
+ lock.release();
410
415
  }
411
- return result.status === 'pass' ? EXIT.ok : EXIT.runtime;
412
416
  }
413
417
  finally {
414
- lock.release();
418
+ restoreRuntimeEnvironment();
415
419
  }
416
420
  }
417
421
  function parameterValidationHelp(action, findings, args) {