@farmslot/recipe-cli 0.1.2 → 0.3.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 (99) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +14 -10
  3. package/dist/cli.js +3 -3
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands.js +2 -2
  6. package/dist/commands.js.map +1 -1
  7. package/dist/composition.d.ts +1 -1
  8. package/dist/composition.d.ts.map +1 -1
  9. package/dist/composition.js +1 -1
  10. package/dist/composition.js.map +1 -1
  11. package/dist/discovery-index.d.ts +1 -1
  12. package/dist/discovery-index.d.ts.map +1 -1
  13. package/dist/discovery-index.js +1 -1
  14. package/dist/discovery-index.js.map +1 -1
  15. package/dist/harness/adapters.d.ts +25 -0
  16. package/dist/harness/adapters.d.ts.map +1 -0
  17. package/dist/harness/adapters.js +87 -0
  18. package/dist/harness/adapters.js.map +1 -0
  19. package/dist/harness/artifact-files.d.ts +11 -0
  20. package/dist/harness/artifact-files.d.ts.map +1 -0
  21. package/dist/harness/artifact-files.js +75 -0
  22. package/dist/harness/artifact-files.js.map +1 -0
  23. package/dist/harness/checkout-lock.d.ts +13 -0
  24. package/dist/harness/checkout-lock.d.ts.map +1 -0
  25. package/dist/harness/checkout-lock.js +211 -0
  26. package/dist/harness/checkout-lock.js.map +1 -0
  27. package/dist/harness/cli-color.d.ts +25 -0
  28. package/dist/harness/cli-color.d.ts.map +1 -0
  29. package/dist/harness/cli-color.js +101 -0
  30. package/dist/harness/cli-color.js.map +1 -0
  31. package/dist/harness/command-journal.d.ts +25 -0
  32. package/dist/harness/command-journal.d.ts.map +1 -0
  33. package/dist/harness/command-journal.js +322 -0
  34. package/dist/harness/command-journal.js.map +1 -0
  35. package/dist/harness/commands/last.d.ts +3 -0
  36. package/dist/harness/commands/last.d.ts.map +1 -0
  37. package/dist/harness/commands/last.js +59 -0
  38. package/dist/harness/commands/last.js.map +1 -0
  39. package/dist/harness/commands/launch.d.ts +2 -0
  40. package/dist/harness/commands/launch.d.ts.map +1 -0
  41. package/dist/harness/commands/launch.js +105 -0
  42. package/dist/harness/commands/launch.js.map +1 -0
  43. package/dist/harness/commands/reload.d.ts +2 -0
  44. package/dist/harness/commands/reload.d.ts.map +1 -0
  45. package/dist/harness/commands/reload.js +24 -0
  46. package/dist/harness/commands/reload.js.map +1 -0
  47. package/dist/harness/commands/stop.d.ts +9 -0
  48. package/dist/harness/commands/stop.d.ts.map +1 -0
  49. package/dist/harness/commands/stop.js +60 -0
  50. package/dist/harness/commands/stop.js.map +1 -0
  51. package/dist/harness/heal-bounds.d.ts +15 -0
  52. package/dist/harness/heal-bounds.d.ts.map +1 -0
  53. package/dist/harness/heal-bounds.js +194 -0
  54. package/dist/harness/heal-bounds.js.map +1 -0
  55. package/dist/harness/host.d.ts +37 -0
  56. package/dist/harness/host.d.ts.map +1 -0
  57. package/dist/harness/host.js +48 -0
  58. package/dist/harness/host.js.map +1 -0
  59. package/dist/harness/index.d.ts +19 -0
  60. package/dist/harness/index.d.ts.map +1 -0
  61. package/dist/harness/index.js +22 -0
  62. package/dist/harness/index.js.map +1 -0
  63. package/dist/harness/json-stream.d.ts +19 -0
  64. package/dist/harness/json-stream.d.ts.map +1 -0
  65. package/dist/harness/json-stream.js +59 -0
  66. package/dist/harness/json-stream.js.map +1 -0
  67. package/dist/harness/leaf-invoke.d.ts +8 -0
  68. package/dist/harness/leaf-invoke.d.ts.map +1 -0
  69. package/dist/harness/leaf-invoke.js +31 -0
  70. package/dist/harness/leaf-invoke.js.map +1 -0
  71. package/dist/harness/library-provenance.d.ts +3 -0
  72. package/dist/harness/library-provenance.d.ts.map +1 -0
  73. package/dist/harness/library-provenance.js +31 -0
  74. package/dist/harness/library-provenance.js.map +1 -0
  75. package/dist/harness/overlay.d.ts +17 -0
  76. package/dist/harness/overlay.d.ts.map +1 -0
  77. package/dist/harness/overlay.js +415 -0
  78. package/dist/harness/overlay.js.map +1 -0
  79. package/dist/harness/parse-args.d.ts +35 -0
  80. package/dist/harness/parse-args.d.ts.map +1 -0
  81. package/dist/harness/parse-args.js +249 -0
  82. package/dist/harness/parse-args.js.map +1 -0
  83. package/dist/harness/paths.d.ts +15 -0
  84. package/dist/harness/paths.d.ts.map +1 -0
  85. package/dist/harness/paths.js +29 -0
  86. package/dist/harness/paths.js.map +1 -0
  87. package/dist/harness/shared.d.ts +43 -0
  88. package/dist/harness/shared.d.ts.map +1 -0
  89. package/dist/harness/shared.js +414 -0
  90. package/dist/harness/shared.js.map +1 -0
  91. package/dist/libraries.d.ts +1 -1
  92. package/dist/libraries.d.ts.map +1 -1
  93. package/dist/libraries.js +1 -1
  94. package/dist/libraries.js.map +1 -1
  95. package/dist/search.d.ts +1 -1
  96. package/dist/search.d.ts.map +1 -1
  97. package/dist/types.d.ts +1 -1
  98. package/dist/types.d.ts.map +1 -1
  99. package/package.json +10 -3
@@ -0,0 +1,60 @@
1
+ // stop — stop the dev server this checkout owns, through the platform's
2
+ // `devServer`, plus any companion processes the host started for it.
3
+ import { adapterPortEnv, harnessAdapter } from '../adapters.js';
4
+ import { color } from '../cli-color.js';
5
+ import { harnessHost } from '../host.js';
6
+ import { optionFlag, optionString, parseArgs, resolveAdapter, shellQuote } from '../parse-args.js';
7
+ import { usageOut } from '../shared.js';
8
+ export async function handleStop(argv, commandOptions = {}) {
9
+ const { options } = parseArgs(argv);
10
+ const json = optionFlag(options, 'json');
11
+ const { adapter, target } = resolveAdapter(options);
12
+ const surface = harnessAdapter(adapter);
13
+ surface.resolveSlotPorts(target);
14
+ const explicitPort = optionString(options, 'port') ?? optionString(options, 'watcherPort');
15
+ if (explicitPort) {
16
+ process.env.WATCHER_PORT = explicitPort;
17
+ for (const name of adapterPortEnv())
18
+ process.env[name] = explicitPort;
19
+ }
20
+ const stop = surface.devServer.stop(target);
21
+ if (stop.kind === 'headless') {
22
+ return usageOut(json, 'stop', stop.message, stop.userAction);
23
+ }
24
+ const companions = (await commandOptions.companions?.(target)) ?? [];
25
+ const signalled = (stop.signalled ?? 0) + companions.length;
26
+ const summary = [
27
+ stop.summary,
28
+ ...companions.map((companion) => `stopped ${companion.label} ${companion.pid}`),
29
+ ].join('; ');
30
+ // A platform whose dev server serves several targets has no one truthful
31
+ // relaunch, so the hint is optional.
32
+ const next = surface.devServer.afterStop?.(target);
33
+ const userAction = `${harnessHost().name} status --target ${shellQuote(target)} --json`;
34
+ if (json) {
35
+ console.log(JSON.stringify({
36
+ schemaVersion: 1,
37
+ command: 'stop',
38
+ adapter,
39
+ target,
40
+ status: stop.status === 0 ? 'pass' : 'fail',
41
+ ...(stop.signalled !== undefined || companions.length > 0 ? { signalled } : {}),
42
+ exitCode: stop.status,
43
+ ...(stop.output ? { output: stop.output } : {}),
44
+ ...(stop.status === 0
45
+ ? next
46
+ ? { next }
47
+ : {}
48
+ : { error: { code: 'DEV_SERVER_STOP_FAILED', message: summary, userAction } }),
49
+ }, null, 2));
50
+ }
51
+ else {
52
+ if (stop.output)
53
+ process.stderr.write(`${stop.output}\n`);
54
+ console.error(`${color(stop.status === 0 ? 'ok' : 'err', stop.status === 0 ? '✓' : '✗')} ${summary}`);
55
+ if (stop.status !== 0 || next)
56
+ console.error(` Next: ${stop.status === 0 ? next : userAction}`);
57
+ }
58
+ return stop.status;
59
+ }
60
+ //# sourceMappingURL=stop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../../src/harness/commands/stop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { HealBoundViolation, HealPolicy, HealState } from '@farmslot/adapter-sdk';
2
+ export declare function newHealState(): HealState;
3
+ export declare function conciseFailureForHuman(output: string): string;
4
+ export declare function parseHeal(options: Record<string, string | boolean>, fallback: HealPolicy): HealPolicy | {
5
+ error: string;
6
+ };
7
+ export declare function ensureOverlay(adapter: string, target: string, heal: HealPolicy, state: HealState, json: boolean): Promise<{
8
+ ok: boolean;
9
+ error?: string;
10
+ }>;
11
+ export type FailureClass = 'capture-protected' | 'wallet' | 'infra' | 'app';
12
+ export declare function classifyFailure(output: string): FailureClass;
13
+ export declare function recipeRunning(target: string): boolean;
14
+ export declare function checkHealBounds(target: string, output: string, state: HealState): HealBoundViolation | null;
15
+ //# sourceMappingURL=heal-bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heal-bounds.d.ts","sourceRoot":"","sources":["../../src/harness/heal-bounds.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,kBAAkB,EAClB,UAAU,EACV,SAAS,EACV,MAAM,uBAAuB,CAAC;AAQ/B,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EACzC,QAAQ,EAAE,UAAU,GACnB,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAKhC;AAoCD,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6B1C;AAUD,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAE5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAM5D;AAwBD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGrD;AAKD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,GACf,kBAAkB,GAAG,IAAI,CAyD3B"}
@@ -0,0 +1,194 @@
1
+ // Healing policy + recovery bounds — shared by launch, run, and call (policy, not
2
+ // per-command). Owns: overlay auto-ensure, failure classification, the recovery
3
+ // bounds that stop blind retry loops, and the --heal parser.
4
+ //
5
+ // Overlay auto-ensure seam (overridable for CI/agents and contract tests):
6
+ // <envPrefix>_INSTALL_BIN — overlay installer (default: handleHarness install)
7
+ import { spawnSync } from 'node:child_process';
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { assertAdaptersRegistered, harnessAdapter, harnessAdapters } from './adapters.js';
11
+ import { harnessHost, hostEnvName } from './host.js';
12
+ import { handleHarness } from './overlay.js';
13
+ import { recipeHarnessPath, recipeRuntimePath } from './paths.js';
14
+ import { EXIT } from './shared.js';
15
+ export function newHealState() {
16
+ return { recovered: [], mutations: [], attemptedRecoveries: [] };
17
+ }
18
+ export function conciseFailureForHuman(output) {
19
+ const errors = output
20
+ .split(/\r?\n/u)
21
+ .map((line) => /^(?:[A-Za-z]*Error):\s*(.+)$/u.exec(line.trim())?.[1])
22
+ .filter((line) => Boolean(line));
23
+ return errors.at(-1) ?? output.trim();
24
+ }
25
+ export function parseHeal(options, fallback) {
26
+ const value = options.heal;
27
+ if (value === undefined)
28
+ return fallback;
29
+ if (value === 'off' || value === 'infra-only' || value === 'auto')
30
+ return value;
31
+ return { error: `--heal must be off, infra-only, or auto (got "${String(value)}").` };
32
+ }
33
+ function overlayDir(target, adapter) {
34
+ return recipeHarnessPath(target, adapter);
35
+ }
36
+ function overlayPresent(target, adapter) {
37
+ try {
38
+ return fs.statSync(overlayDir(target, adapter)).isDirectory();
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ // Validates that the installed overlay's runner-source stamp points to an existing
45
+ // runner directory whose binary is still present. Two failure modes are detected:
46
+ // 1. Stale stamp — runner dir moved or renamed since install (dir absent).
47
+ // 2. Stale exec target — runner dir exists but the host bin was removed
48
+ // (e.g. the package was unlinked/purged inside an otherwise-live dir).
49
+ // Either way the delegate binary will fail to exec; treat the overlay as absent
50
+ // so auto-ensure re-installs it from the current runner.
51
+ function overlayDelegateValid(target, adapter) {
52
+ if (harnessAdapter(adapter).headless)
53
+ return true;
54
+ const pointer = path.join(recipeHarnessPath(target, adapter), 'runner', '.runner-source');
55
+ if (!fs.existsSync(pointer))
56
+ return true; // no stamp = running from local runner, valid
57
+ const runnerPath = fs.readFileSync(pointer, 'utf8').trim();
58
+ if (!runnerPath || !fs.existsSync(runnerPath))
59
+ return false;
60
+ // Runner dir is present; verify the binary inside still exists — the directory
61
+ // can survive a package removal while the binary inside is deleted.
62
+ return fs.existsSync(path.join(runnerPath, harnessHost().bin));
63
+ }
64
+ // Auto-ensure the runtime overlay (install phase). Missing + heal != off →
65
+ // install inline, emit a first-install notice to stderr, and record the mutation.
66
+ // heal === off disables auto-install (repro-preserving); we proceed and let the
67
+ // porcelain surface any missing-overlay failure itself.
68
+ export async function ensureOverlay(adapter, target, heal, state, json) {
69
+ // A headless platform (core) needs no launch overlay for run/call.
70
+ if (harnessAdapter(adapter).headless)
71
+ return { ok: true };
72
+ if (overlayPresent(target, adapter) && overlayDelegateValid(target, adapter))
73
+ return { ok: true };
74
+ if (heal === 'off')
75
+ return { ok: true };
76
+ const installBin = process.env[hostEnvName('INSTALL_BIN')];
77
+ let code;
78
+ if (installBin) {
79
+ const result = spawnSync(installBin, ['install', '--platform', adapter, '--target', target], {
80
+ cwd: target,
81
+ stdio: ['ignore', 2, 'inherit'],
82
+ env: process.env,
83
+ });
84
+ code = result.status ?? 1;
85
+ }
86
+ else {
87
+ // Auto-install is an internal phase of the parent command. Keep the nested
88
+ // installer silent so human output has one progress owner and machine
89
+ // output remains one JSON document; the parent records the mutation below.
90
+ code = await handleHarness(['install', '--platform', adapter, '--target', target, '--quiet']);
91
+ }
92
+ if (code !== 0 || !overlayPresent(target, adapter)) {
93
+ return { ok: false, error: `runtime overlay install failed (exit ${code})` };
94
+ }
95
+ const dir = overlayDir(target, adapter);
96
+ state.mutations.push({ type: 'file', action: 'created', path: dir });
97
+ // First-install notice → stderr (human) / mutations[] only (json; stdout clean).
98
+ if (!json)
99
+ process.stderr.write(`installed ${harnessHost().name} overlay → ${dir}\n`);
100
+ return { ok: true };
101
+ }
102
+ export function classifyFailure(output) {
103
+ if (captureProtection(output))
104
+ return 'capture-protected';
105
+ if (matchesAny('transportFirst', output))
106
+ return 'infra';
107
+ if (matchesAny('walletState', output))
108
+ return 'wallet';
109
+ if (matchesAny('transport', output))
110
+ return 'infra';
111
+ return 'app';
112
+ }
113
+ function adapterPatterns() {
114
+ // With no adapters every failure would read as app logic and never heal.
115
+ assertAdaptersRegistered();
116
+ const registry = harnessAdapters();
117
+ return registry.list().flatMap((id) => {
118
+ const patterns = registry.get(id).failurePatterns;
119
+ return patterns ? [patterns] : [];
120
+ });
121
+ }
122
+ function matchesAny(kind, output) {
123
+ return adapterPatterns().some((patterns) => patterns[kind]?.test(output) ?? false);
124
+ }
125
+ function captureProtection(output) {
126
+ return adapterPatterns()
127
+ .map((patterns) => patterns.captureProtected)
128
+ .find((entry) => entry?.pattern.test(output));
129
+ }
130
+ // Refuse ALL recovery while a recipe is executing (mid-run recovery would corrupt
131
+ // state). Signalled by a lock file or <envPrefix>_RECIPE_RUNNING=1.
132
+ export function recipeRunning(target) {
133
+ if (process.env[hostEnvName('RECIPE_RUNNING')] === '1')
134
+ return true;
135
+ return fs.existsSync(recipeRuntimePath(target, 'recipe.lock'));
136
+ }
137
+ // Returns null (ok to proceed) or a violation descriptor when a bound is hit.
138
+ // Using null instead of { ok: true } keeps the return typeof-narrowable without
139
+ // relying on discriminated-union narrowing (avoids strict-mode tsconfig issues).
140
+ export function checkHealBounds(target, output, state) {
141
+ // Carry the original failure output verbatim on every violation so the caller
142
+ // can surface it (--json + human) alongside the classification note.
143
+ const originalError = output.trim() || undefined;
144
+ if (recipeRunning(target)) {
145
+ return {
146
+ code: 'RECIPE_RUNNING',
147
+ exitCode: EXIT.bounded,
148
+ message: 'a recipe is currently running — refusing recovery to avoid corrupting mid-run state.',
149
+ originalError,
150
+ };
151
+ }
152
+ const concise = conciseFailureForHuman(output);
153
+ const failureClass = classifyFailure(concise);
154
+ const protectedCapture = failureClass === 'capture-protected' ? captureProtection(concise) : undefined;
155
+ if (protectedCapture) {
156
+ return {
157
+ code: 'SCREENSHOT_PROTECTED',
158
+ exitCode: EXIT.runtime,
159
+ message: protectedCapture.message,
160
+ userAction: protectedCapture.userAction,
161
+ originalError,
162
+ };
163
+ }
164
+ if (failureClass === 'wallet') {
165
+ return {
166
+ code: 'WALLET_STATE_REQUIRED',
167
+ exitCode: EXIT.bounded,
168
+ message: 'wallet prerequisites need attention; healing never changes wallet state.',
169
+ userAction: /(?:^|\n)\s*Next:\s*([^\r\n]+)/u.exec(output)?.[1] ??
170
+ `run ${harnessHost().name} doctor --json`,
171
+ originalError,
172
+ };
173
+ }
174
+ if (failureClass === 'app') {
175
+ return {
176
+ code: 'APP_LOGIC_FAILURE',
177
+ exitCode: EXIT.runtime,
178
+ message: 'failure looks like app-logic — healing cannot help; surface verbatim.',
179
+ originalError,
180
+ };
181
+ }
182
+ if (state.attemptedRecoveries.length > 0) {
183
+ return {
184
+ code: 'SAME_RECOVERY_TWICE',
185
+ exitCode: EXIT.bounded,
186
+ message: state.recovered.length > 0
187
+ ? 'one recovery already succeeded this invocation — bounded policy refuses a second recovery.'
188
+ : 'one recovery was already attempted this invocation — refusing to loop.',
189
+ originalError,
190
+ };
191
+ }
192
+ return null;
193
+ }
194
+ //# sourceMappingURL=heal-bounds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heal-bounds.js","sourceRoot":"","sources":["../../src/harness/heal-bounds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Who is running the generic harness commands. A product harness (`mm-harness`)
3
+ * configures this once at startup, so every message and environment variable
4
+ * keeps that product's spelling; `farmslot-recipe` uses the defaults. Runtime
5
+ * paths are not per host: every host shares the checkout layout in paths.ts.
6
+ */
7
+ export interface HarnessHost {
8
+ /** The bin name used in messages and `Next:` lines. */
9
+ name: string;
10
+ /** What a checkout belongs to, in "could not detect the <product> repo type". */
11
+ product: string;
12
+ /** Prefix of the host's own environment variables: `<envPrefix>_OPERATION_ID`. */
13
+ envPrefix: string;
14
+ /** The npm package that ships the bin. */
15
+ packageName: string;
16
+ /** The installed package root. */
17
+ packageRoot: string;
18
+ /** The host executable, relative to `packageRoot`. */
19
+ bin: string;
20
+ /** Commands the resumability journal records. */
21
+ journaledCommands: readonly string[];
22
+ }
23
+ /** A host's identity; it journals nothing unless it lists commands. */
24
+ export type HarnessHostConfig = Omit<HarnessHost, 'journaledCommands'> & {
25
+ journaledCommands?: readonly string[];
26
+ };
27
+ /**
28
+ * Set the host identity. Call once, before any command runs. Every identity
29
+ * field is required, so a host can't silently inherit farmslot-recipe's names.
30
+ */
31
+ export declare function configureHarnessHost(host: HarnessHostConfig): HarnessHost;
32
+ export declare function harnessHost(): HarnessHost;
33
+ /** The host-owned environment variable `<envPrefix>_<suffix>`. */
34
+ export declare function hostEnvName(suffix: string): string;
35
+ /** Throws unless `value` is a non-empty, safe, checkout-relative path. */
36
+ export declare function validateRelativeRecipePath(name: string, value: string): string;
37
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/harness/host.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAeD,uEAAuE;AACvE,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,GAAG;IACvE,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,WAAW,CAOzE;AAED,wBAAgB,WAAW,IAAI,WAAW,CAEzC;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAa9E"}
@@ -0,0 +1,48 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ const defaultHost = {
4
+ name: 'farmslot-recipe',
5
+ product: 'project',
6
+ envPrefix: 'FARMSLOT_RECIPE',
7
+ packageName: '@farmslot/recipe-cli',
8
+ packageRoot: fileURLToPath(new URL('../..', import.meta.url)),
9
+ bin: 'bin/farmslot-recipe.mjs',
10
+ // farmslot-recipe journals nothing yet; a host lists the commands it journals.
11
+ journaledCommands: [],
12
+ };
13
+ let current = defaultHost;
14
+ /**
15
+ * Set the host identity. Call once, before any command runs. Every identity
16
+ * field is required, so a host can't silently inherit farmslot-recipe's names.
17
+ */
18
+ export function configureHarnessHost(host) {
19
+ const next = { ...host, journaledCommands: host.journaledCommands ?? [] };
20
+ if (!/^[A-Z][A-Z0-9_]*$/u.test(next.envPrefix)) {
21
+ throw new Error(`envPrefix must be an upper-case identifier: ${next.envPrefix}`);
22
+ }
23
+ current = next;
24
+ return current;
25
+ }
26
+ export function harnessHost() {
27
+ return current;
28
+ }
29
+ /** The host-owned environment variable `<envPrefix>_<suffix>`. */
30
+ export function hostEnvName(suffix) {
31
+ return `${current.envPrefix}_${suffix}`;
32
+ }
33
+ /** Throws unless `value` is a non-empty, safe, checkout-relative path. */
34
+ export function validateRelativeRecipePath(name, value) {
35
+ if (!value || path.isAbsolute(value)) {
36
+ throw new Error(`${name} must be a non-empty relative path: ${value}`);
37
+ }
38
+ if (!/^[A-Za-z0-9._/-]+$/u.test(value)) {
39
+ throw new Error(`${name} contains unsupported characters: ${value}`);
40
+ }
41
+ for (const part of value.split('/')) {
42
+ if (!part || part === '.' || part === '..') {
43
+ throw new Error(`${name} contains unsafe path component: ${value}`);
44
+ }
45
+ }
46
+ return value;
47
+ }
48
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/harness/host.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyBzC,MAAM,WAAW,GAAgB;IAC/B,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,iBAAiB;IAC5B,WAAW,EAAE,sBAAsB;IACnC,WAAW,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7D,GAAG,EAAE,yBAAyB;IAC9B,+EAA+E;IAC/E,iBAAiB,EAAE,EAAE;CACtB,CAAC;AAEF,IAAI,OAAO,GAAgB,WAAW,CAAC;AAOvC;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAuB;IAC1D,MAAM,IAAI,GAAgB,EAAE,GAAG,IAAI,EAAE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,IAAI,EAAE,EAAE,CAAC;IACvF,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,GAAG,IAAI,CAAC;IACf,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;AAC1C,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,0BAA0B,CAAC,IAAY,EAAE,KAAa;IACpE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,uCAAuC,KAAK,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,qCAAqC,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,oCAAoC,KAAK,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,19 @@
1
+ export { adapterDetectNext, adapterFlags, adapterForPlatform, assertAdapter, configureHarnessAdapters, detectAdapter, harnessAdapter, harnessAdapters, isPlatformTarget, undetectedAdapterMessage, } from './adapters.js';
2
+ export { type ArtifactManifestEntry, indexArtifactManifest, readContainedJsonArtifact, writeContainedArtifact, } from './artifact-files.js';
3
+ export { acquireCheckoutLock, type CheckoutLock, type CheckoutLockFailure, trackCheckoutChild, } from './checkout-lock.js';
4
+ export { classifyLogEvent, color, colorEnabled, colorHumanMessage, colorKv, colorLogEvent, colorStatusWord, stripAnsi, } from './cli-color.js';
5
+ export { COMMAND_JOURNAL_FILE, commandJournalPath, type CommandJournalRecord, isSensitiveKey, readCommandJournal, recordCommandEvidence, recordCommandOutput, recordCommandStage, redactCommandArgs, redactStructuredValue, withCommandJournal, } from './command-journal.js';
6
+ export { handleLast } from './commands/last.js';
7
+ export { handleLaunch } from './commands/launch.js';
8
+ export { handleReload } from './commands/reload.js';
9
+ export { handleStop, type StopCommandOptions, type StoppedCompanion } from './commands/stop.js';
10
+ export { checkHealBounds, classifyFailure, conciseFailureForHuman, ensureOverlay, type FailureClass, newHealState, parseHeal, recipeRunning, } from './heal-bounds.js';
11
+ export { configureHarnessHost, type HarnessHost, harnessHost, type HarnessHostConfig, hostEnvName, validateRelativeRecipePath, } from './host.js';
12
+ export { JsonStreamWriter } from './json-stream.js';
13
+ export { leafStartFailureMessage, missingShellLeafMessage, resolveLeafInvoke, shellLeafMissing, } from './leaf-invoke.js';
14
+ export { gitLibraryProvenance } from './library-provenance.js';
15
+ export { argValue, handleHarness, type HarnessAction, hasArg, type OverlayCommandOptions, type OverlayInstallContext, readRuntimeContextField, resolveRuntimeContextPath, } from './overlay.js';
16
+ export { actionManifestPathOption, adapterOption, applyRuntimeDirOption, applyWatcherPortOption, CliError, type CliOptions, type CliOptionValue, isRecord, optionFlag, optionString, optionStrings, parseArgs, type ParseArgsOptions, type ParsedArgs, parsePort, parseRecipeParamAssignments, requiredOption, resolveAdapter, shellQuote, shellQuoteArg, targetPath, usageError, } from './parse-args.js';
17
+ export { DEFAULT_RECIPE_HARNESS_ROOT, DEFAULT_RECIPE_RUNTIME_DIR, harnessExecutable, recipeHarnessPath, recipeHarnessRoot, recipeRuntimeDir, recipeRuntimePath, } from './paths.js';
18
+ export { checkoutBusyOut, EXIT, flag, type ParsedFlags, parseFlags, resolveFlagsAdapter, scriptOverride, type ScriptResult, spawnInherit, spawnScript, spawnScriptStreaming, str, type StreamingSpawnOptions, targetOf, usageOut, writeInteractiveProgress, } from './shared.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ // Generic harness support shared by every host CLI (`farmslot-recipe`, product
2
+ // presets such as `mm-harness`): host identity, runtime paths, the resumability
3
+ // journal, the checkout lock, JSON streaming and colour output.
4
+ export { adapterDetectNext, adapterFlags, adapterForPlatform, assertAdapter, configureHarnessAdapters, detectAdapter, harnessAdapter, harnessAdapters, isPlatformTarget, undetectedAdapterMessage, } from './adapters.js';
5
+ export { indexArtifactManifest, readContainedJsonArtifact, writeContainedArtifact, } from './artifact-files.js';
6
+ export { acquireCheckoutLock, trackCheckoutChild, } from './checkout-lock.js';
7
+ export { classifyLogEvent, color, colorEnabled, colorHumanMessage, colorKv, colorLogEvent, colorStatusWord, stripAnsi, } from './cli-color.js';
8
+ export { COMMAND_JOURNAL_FILE, commandJournalPath, isSensitiveKey, readCommandJournal, recordCommandEvidence, recordCommandOutput, recordCommandStage, redactCommandArgs, redactStructuredValue, withCommandJournal, } from './command-journal.js';
9
+ export { handleLast } from './commands/last.js';
10
+ export { handleLaunch } from './commands/launch.js';
11
+ export { handleReload } from './commands/reload.js';
12
+ export { handleStop } from './commands/stop.js';
13
+ export { checkHealBounds, classifyFailure, conciseFailureForHuman, ensureOverlay, newHealState, parseHeal, recipeRunning, } from './heal-bounds.js';
14
+ export { configureHarnessHost, harnessHost, hostEnvName, validateRelativeRecipePath, } from './host.js';
15
+ export { JsonStreamWriter } from './json-stream.js';
16
+ export { leafStartFailureMessage, missingShellLeafMessage, resolveLeafInvoke, shellLeafMissing, } from './leaf-invoke.js';
17
+ export { gitLibraryProvenance } from './library-provenance.js';
18
+ export { argValue, handleHarness, hasArg, readRuntimeContextField, resolveRuntimeContextPath, } from './overlay.js';
19
+ export { actionManifestPathOption, adapterOption, applyRuntimeDirOption, applyWatcherPortOption, CliError, isRecord, optionFlag, optionString, optionStrings, parseArgs, parsePort, parseRecipeParamAssignments, requiredOption, resolveAdapter, shellQuote, shellQuoteArg, targetPath, usageError, } from './parse-args.js';
20
+ export { DEFAULT_RECIPE_HARNESS_ROOT, DEFAULT_RECIPE_RUNTIME_DIR, harnessExecutable, recipeHarnessPath, recipeHarnessRoot, recipeRuntimeDir, recipeRuntimePath, } from './paths.js';
21
+ export { checkoutBusyOut, EXIT, flag, parseFlags, resolveFlagsAdapter, scriptOverride, spawnInherit, spawnScript, spawnScriptStreaming, str, targetOf, usageOut, writeInteractiveProgress, } from './shared.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gFAAgF;AAChF,gEAAgE;AAChE,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,mBAAmB,EAGnB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,EACL,YAAY,EACZ,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,eAAe,EACf,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAElB,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAkD,MAAM,oBAAoB,CAAC;AAChG,OAAO,EACL,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,aAAa,EAEb,YAAY,EACZ,SAAS,EACT,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EAEpB,WAAW,EAEX,WAAW,EACX,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EACL,QAAQ,EACR,aAAa,EAEb,MAAM,EAGN,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,QAAQ,EAGR,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EAGT,SAAS,EACT,2BAA2B,EAC3B,cAAc,EACd,cAAc,EACd,UAAU,EACV,aAAa,EACb,UAAU,EACV,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,IAAI,EACJ,IAAI,EAEJ,UAAU,EACV,mBAAmB,EACnB,cAAc,EAEd,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,GAAG,EAEH,QAAQ,EACR,QAAQ,EACR,wBAAwB,GACzB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { CommandEventStream } from '@farmslot/adapter-sdk';
2
+ type JsonFields = Record<string, unknown>;
3
+ export declare class JsonStreamWriter implements CommandEventStream {
4
+ readonly enabled: boolean;
5
+ readonly command: string;
6
+ private completed;
7
+ private readonly writeLine;
8
+ constructor(command: string, enabled: boolean, output?: Pick<NodeJS.WriteStream, 'write'>);
9
+ isolateStdout(): () => void;
10
+ emit(event: string, fields?: JsonFields): void;
11
+ phase(phase: string, fields?: JsonFields): void;
12
+ node(nodeId: string, action: string, status: 'running' | 'passed' | 'failed'): void;
13
+ mutation(mutation: JsonFields): void;
14
+ recovery(code: string): void;
15
+ error(error: JsonFields): void;
16
+ complete(status: 'pass' | 'fail' | 'unknown', exitCode: number, fields?: JsonFields): void;
17
+ }
18
+ export {};
19
+ //# sourceMappingURL=json-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-stream.d.ts","sourceRoot":"","sources":["../../src/harness/json-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,qBAAa,gBAAiB,YAAW,kBAAkB;IACzD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;gBAGjD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,MAAM,GAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAkB;IAU5D,aAAa,IAAI,MAAM,IAAI;IAc3B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,IAAI;IAalD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,IAAI;IAKnD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,IAAI;IAKnF,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAIpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI5B,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAI9B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,IAAI;CAK/F"}
@@ -0,0 +1,59 @@
1
+ import { recordCommandStage } from './command-journal.js';
2
+ export class JsonStreamWriter {
3
+ constructor(command, enabled, output = process.stdout) {
4
+ this.completed = false;
5
+ this.command = command;
6
+ this.enabled = enabled;
7
+ const write = output.write.bind(output);
8
+ this.writeLine = (line) => {
9
+ write(`${line}\n`);
10
+ };
11
+ }
12
+ isolateStdout() {
13
+ if (!this.enabled)
14
+ return () => undefined;
15
+ const original = process.stdout.write;
16
+ const redirect = ((chunk, encoding, callback) => process.stderr.write(chunk, encoding, callback));
17
+ process.stdout.write = redirect;
18
+ return () => {
19
+ if (process.stdout.write === redirect)
20
+ process.stdout.write = original;
21
+ };
22
+ }
23
+ emit(event, fields = {}) {
24
+ if (!this.enabled || this.completed)
25
+ return;
26
+ this.writeLine(JSON.stringify({
27
+ schemaVersion: 1,
28
+ command: this.command,
29
+ event,
30
+ ...fields,
31
+ ts: new Date().toISOString(),
32
+ }));
33
+ }
34
+ phase(phase, fields = {}) {
35
+ recordCommandStage(phase);
36
+ this.emit('phase', { phase, ...fields });
37
+ }
38
+ node(nodeId, action, status) {
39
+ if (status === 'running')
40
+ recordCommandStage(`${nodeId}: ${action}`);
41
+ this.emit('node', { nodeId, action, status });
42
+ }
43
+ mutation(mutation) {
44
+ this.emit('mutation', { mutation });
45
+ }
46
+ recovery(code) {
47
+ this.emit('recovery', { code });
48
+ }
49
+ error(error) {
50
+ this.emit('error', { error });
51
+ }
52
+ complete(status, exitCode, fields = {}) {
53
+ if (!this.enabled || this.completed)
54
+ return;
55
+ this.emit('complete', { status, exitCode, ...fields });
56
+ this.completed = true;
57
+ }
58
+ }
59
+ //# sourceMappingURL=json-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-stream.js","sourceRoot":"","sources":["../../src/harness/json-stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function resolveLeafInvoke(command: string, args: string[]): {
2
+ bin: string;
3
+ args: string[];
4
+ };
5
+ export declare function leafStartFailureMessage(leaf: string, code: string, kind?: string): string;
6
+ export declare function missingShellLeafMessage(leafPath: string): string;
7
+ export declare function shellLeafMissing(leafPath: string): boolean;
8
+ //# sourceMappingURL=leaf-invoke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaf-invoke.d.ts","sourceRoot":"","sources":["../../src/harness/leaf-invoke.ts"],"names":[],"mappings":"AAUA,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,GACb;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAGjC;AAID,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,SAAe,GAAG,MAAM,CAM/F;AAKD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhE;AAGD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D"}
@@ -0,0 +1,31 @@
1
+ // Interpreter routing for adapter shell and node leaves.
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { harnessHost } from './host.js';
5
+ // Returns the interpreter and args for invoking a leaf. Shell leaves (.sh) run
6
+ // through bash so the file mode does not need to be executable. Node leaves
7
+ // are already invoked through process.execPath by their callers and are
8
+ // returned unchanged.
9
+ export function resolveLeafInvoke(command, args) {
10
+ if (command.endsWith('.sh'))
11
+ return { bin: 'bash', args: [command, ...args] };
12
+ return { bin: command, args };
13
+ }
14
+ // Teaching diagnostic for a leaf that could not start: the host's own install
15
+ // is incomplete, so the next step reinstalls it.
16
+ export function leafStartFailureMessage(leaf, code, kind = 'shell leaf') {
17
+ const host = harnessHost();
18
+ return (`leaf could not start: ${leaf} (${code})\n` +
19
+ ` Next: reinstall ${host.name} (npm i -g ${host.packageName}) — the ${kind} is missing or not executable`);
20
+ }
21
+ // A shell leaf absent from disk. Bash exits 127 (not a Node spawn error) for a
22
+ // missing file, so callers pre-check and emit this rather than relying on
23
+ // result.error.
24
+ export function missingShellLeafMessage(leafPath) {
25
+ return leafStartFailureMessage(path.basename(leafPath), 'ENOENT');
26
+ }
27
+ // Returns true when a .sh leaf path does not exist on disk.
28
+ export function shellLeafMissing(leafPath) {
29
+ return leafPath.endsWith('.sh') && !fs.existsSync(leafPath);
30
+ }
31
+ //# sourceMappingURL=leaf-invoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaf-invoke.js","sourceRoot":"","sources":["../../src/harness/leaf-invoke.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,sBAAsB;AACtB,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAc;IAEd,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IAC9E,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,iDAAiD;AACjD,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,IAAY,EAAE,IAAI,GAAG,YAAY;IACrF,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,OAAO,CACL,yBAAyB,IAAI,KAAK,IAAI,KAAK;QAC3C,qBAAqB,IAAI,CAAC,IAAI,cAAc,IAAI,CAAC,WAAW,WAAW,IAAI,+BAA+B,CAC3G,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,0EAA0E;AAC1E,gBAAgB;AAChB,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,OAAO,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;AACpE,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { RecipeSourceProvenance } from '@farmslot/protocol';
2
+ export declare function gitLibraryProvenance(root: string): Promise<Pick<RecipeSourceProvenance, 'revision' | 'dirty'>>;
3
+ //# sourceMappingURL=library-provenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"library-provenance.d.ts","sourceRoot":"","sources":["../../src/harness/library-provenance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAIjE,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CA4B7D"}