@foldrun/core 0.4.0 → 0.6.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.
- package/README.md +7 -4
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/src/account.d.ts +45 -0
- package/dist/src/account.js +130 -0
- package/dist/src/api-tools.d.ts +8 -0
- package/dist/src/api-tools.js +22 -4
- package/dist/src/browser-pod.d.ts +148 -0
- package/dist/src/browser-pod.js +333 -0
- package/dist/src/catalog.js +2 -1
- package/dist/src/clock.d.ts +49 -0
- package/dist/src/clock.js +121 -0
- package/dist/src/completions.js +17 -8
- package/dist/src/confine.d.ts +22 -0
- package/dist/src/confine.js +218 -3
- package/dist/src/container.d.ts +9 -0
- package/dist/src/container.js +115 -5
- package/dist/src/context-tools.d.ts +1 -1
- package/dist/src/deploy.d.ts +33 -0
- package/dist/src/deploy.js +145 -6
- package/dist/src/egress.d.ts +7 -0
- package/dist/src/egress.js +6 -0
- package/dist/src/eol.d.ts +2 -0
- package/dist/src/eol.js +7 -0
- package/dist/src/evals.d.ts +5 -0
- package/dist/src/evals.js +9 -2
- package/dist/src/flow-lint.d.ts +8 -0
- package/dist/src/flow-lint.js +223 -1
- package/dist/src/flow-patterns.d.ts +141 -0
- package/dist/src/flow-patterns.js +568 -0
- package/dist/src/gitrepo.d.ts +18 -0
- package/dist/src/gitrepo.js +49 -0
- package/dist/src/host-env.js +5 -0
- package/dist/src/kinds.js +1 -1
- package/dist/src/language.d.ts +17 -0
- package/dist/src/language.js +55 -0
- package/dist/src/layout.d.ts +69 -0
- package/dist/src/layout.js +200 -0
- package/dist/src/library.d.ts +9 -0
- package/dist/src/library.js +30 -3
- package/dist/src/limits.d.ts +84 -0
- package/dist/src/limits.js +287 -0
- package/dist/src/locale.d.ts +47 -0
- package/dist/src/locale.js +177 -0
- package/dist/src/mail.d.ts +88 -0
- package/dist/src/mail.js +247 -0
- package/dist/src/model-credential.d.ts +14 -0
- package/dist/src/model-credential.js +58 -0
- package/dist/src/model-probe.d.ts +3 -0
- package/dist/src/model-probe.js +1 -0
- package/dist/src/notify.d.ts +53 -7
- package/dist/src/notify.js +194 -126
- package/dist/src/openapi.js +5 -3
- package/dist/src/operator.d.ts +201 -0
- package/dist/src/operator.js +251 -0
- package/dist/src/paths.d.ts +28 -0
- package/dist/src/paths.js +55 -0
- package/dist/src/platform.d.ts +43 -3
- package/dist/src/platform.js +9 -1
- package/dist/src/provider-health.js +3 -2
- package/dist/src/providers.d.ts +481 -0
- package/dist/src/providers.js +1105 -6
- package/dist/src/refusal.d.ts +83 -0
- package/dist/src/refusal.js +281 -0
- package/dist/src/run-container.d.ts +149 -13
- package/dist/src/run-container.js +424 -43
- package/dist/src/runner.d.ts +177 -9
- package/dist/src/runner.js +1146 -154
- package/dist/src/runtime.d.ts +52 -0
- package/dist/src/runtime.js +493 -58
- package/dist/src/script-tools.d.ts +17 -2
- package/dist/src/script-tools.js +82 -10
- package/dist/src/secret-files.d.ts +6 -5
- package/dist/src/secret-files.js +24 -11
- package/dist/src/secret-health.d.ts +30 -6
- package/dist/src/secret-health.js +42 -20
- package/dist/src/secrets.d.ts +19 -0
- package/dist/src/secrets.js +155 -86
- package/dist/src/starter.d.ts +9 -0
- package/dist/src/starter.js +92 -11
- package/dist/src/step-exec.d.ts +72 -2
- package/dist/src/step-exec.js +431 -37
- package/dist/src/step-removal.d.ts +15 -0
- package/dist/src/step-removal.js +49 -0
- package/dist/src/storage.d.ts +23 -4
- package/dist/src/storage.js +125 -23
- package/dist/src/store.d.ts +222 -37
- package/dist/src/store.js +349 -62
- package/dist/src/subagents.d.ts +75 -0
- package/dist/src/subagents.js +149 -0
- package/dist/src/test-mode.d.ts +17 -2
- package/dist/src/test-mode.js +53 -13
- package/dist/src/tool-names.d.ts +13 -1
- package/dist/src/tool-names.js +38 -11
- package/dist/src/tool-programs.d.ts +26 -0
- package/dist/src/tool-programs.js +172 -0
- package/dist/src/tool-test.js +104 -12
- package/dist/src/translator.d.ts +8 -2
- package/dist/src/translator.js +69 -23
- package/dist/src/trigger-log.d.ts +1 -1
- package/dist/src/triggers.d.ts +3 -0
- package/dist/src/triggers.js +10 -2
- package/dist/src/untrusted-fetch.d.ts +11 -0
- package/dist/src/untrusted-fetch.js +77 -0
- package/dist/src/web-actions.d.ts +91 -0
- package/dist/src/web-actions.js +199 -0
- package/dist/src/webhook.d.ts +4 -0
- package/dist/src/webhook.js +39 -0
- package/index.ts +4 -0
- package/package.json +3 -3
- package/src/account.ts +149 -0
- package/src/api-tools.ts +32 -4
- package/src/browser-pod.ts +350 -0
- package/src/catalog.ts +2 -1
- package/src/clock.ts +149 -0
- package/src/completions.ts +17 -8
- package/src/confine.ts +218 -3
- package/src/container.ts +112 -5
- package/src/context-tools.ts +1 -1
- package/src/deploy.ts +137 -6
- package/src/egress.ts +13 -1
- package/src/eol.ts +7 -0
- package/src/evals.ts +14 -2
- package/src/flow-lint.ts +253 -1
- package/src/flow-patterns.ts +597 -0
- package/src/gitrepo.ts +48 -0
- package/src/host-env.ts +5 -0
- package/src/kinds.ts +1 -1
- package/src/language.ts +62 -0
- package/src/layout.ts +228 -0
- package/src/library.ts +37 -3
- package/src/limits.ts +290 -0
- package/src/locale.ts +217 -0
- package/src/mail.ts +318 -0
- package/src/model-credential.ts +71 -0
- package/src/model-probe.ts +4 -0
- package/src/notify.ts +189 -103
- package/src/openapi.ts +5 -3
- package/src/operator.ts +300 -0
- package/src/paths.ts +54 -0
- package/src/platform.ts +52 -3
- package/src/provider-health.ts +3 -2
- package/src/providers.ts +1368 -6
- package/src/refusal.ts +320 -0
- package/src/run-container.ts +460 -44
- package/src/runner.ts +1168 -155
- package/src/runtime.ts +487 -55
- package/src/script-tools.ts +81 -10
- package/src/secret-files.ts +22 -10
- package/src/secret-health.ts +64 -19
- package/src/secrets.ts +149 -87
- package/src/starter.ts +93 -11
- package/src/step-exec.ts +447 -38
- package/src/step-removal.ts +59 -0
- package/src/storage.ts +141 -22
- package/src/store.ts +506 -70
- package/src/subagents.ts +189 -0
- package/src/test-mode.ts +51 -11
- package/src/tool-names.ts +40 -11
- package/src/tool-programs.ts +179 -0
- package/src/tool-test.ts +110 -12
- package/src/translator.ts +72 -22
- package/src/trigger-log.ts +1 -0
- package/src/triggers.ts +10 -2
- package/src/untrusted-fetch.ts +88 -0
- package/src/web-actions.ts +237 -0
- package/src/webhook.ts +41 -0
- package/templates/blog-desk/agents/writer/agent.md +1 -1
- package/templates/hello/agents/curator/agent.md +4 -4
- package/templates/hello/agents/notetaker/agent.md +3 -3
package/dist/src/runner.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
import { type SubagentSpec } from "./subagents.ts";
|
|
1
2
|
import { type FlowStep, type RunRecord, type StepRecord } from "./store.ts";
|
|
3
|
+
import { type Catalog } from "./catalog.ts";
|
|
4
|
+
import { type ScriptSpec } from "./script-tools.ts";
|
|
5
|
+
import { type RuntimeSpec } from "./runtime.ts";
|
|
6
|
+
import { type LanguageChoice } from "./language.ts";
|
|
7
|
+
import { type RegionChoice } from "./locale.ts";
|
|
8
|
+
import { type ClockChoice } from "./clock.ts";
|
|
9
|
+
export { localDate } from "./clock.ts";
|
|
2
10
|
/** How much of the earlier groups' output a step is handed, in characters.
|
|
3
11
|
* Newest groups are kept when the total is over it. */
|
|
4
12
|
export declare const CONTEXT_CHARS = 30000;
|
|
@@ -48,20 +56,73 @@ export declare function discoverSkills(agentDir: string, subdir?: string): Disco
|
|
|
48
56
|
* Returns null rather than throwing on unparseable YAML: a broken shared file
|
|
49
57
|
* must not take down every agent under it.
|
|
50
58
|
*/
|
|
59
|
+
/**
|
|
60
|
+
* AGENTS.md without the block a coding tool reads.
|
|
61
|
+
*
|
|
62
|
+
* AGENTS.md is two things in a foldrun folder: the account's (or
|
|
63
|
+
* workspace's) own context, which every running agent is given, and — the
|
|
64
|
+
* convention Next.js set — the file a coding agent (Claude Code, Cursor,
|
|
65
|
+
* Codex) reads before it edits the folder. The CLI writes a short managed
|
|
66
|
+
* block for the second reader between these markers; it is about editing
|
|
67
|
+
* the files, not about doing the work, so no running agent is shown it.
|
|
68
|
+
*/
|
|
69
|
+
export declare const AGENT_RULES_START = "<!-- BEGIN:foldrun-agent-rules -->";
|
|
70
|
+
export declare const AGENT_RULES_END = "<!-- END:foldrun-agent-rules -->";
|
|
71
|
+
export declare function withoutAgentRules(body: string): string;
|
|
51
72
|
export declare function readAgentsMd(dir: string): {
|
|
52
73
|
data: Record<string, unknown>;
|
|
53
74
|
body: string;
|
|
54
75
|
} | null;
|
|
55
76
|
/**
|
|
56
|
-
* The
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
77
|
+
* The runtime one agent's steps are built with: its own declaration (else its
|
|
78
|
+
* workspace's), merged with every script tool it grants. The runner builds
|
|
79
|
+
* exactly this for a step; the platform builds it ahead of time when the
|
|
80
|
+
* workspace is deployed, so a package that will not install is reported at
|
|
81
|
+
* deploy and a scheduled step finds its environment ready. One function, so
|
|
82
|
+
* the two can never disagree about what an agent needs.
|
|
83
|
+
*/
|
|
84
|
+
export declare function agentRuntimeSpec(tenant: string, workspace: string, agentDir: string): RuntimeSpec | null;
|
|
85
|
+
/** Every distinct runtime a workspace's agents need, with who needs it. */
|
|
86
|
+
export declare function workspaceRuntimePlan(tenant: string, workspace: string): {
|
|
87
|
+
fingerprint: string;
|
|
88
|
+
spec: RuntimeSpec;
|
|
89
|
+
agents: string[];
|
|
90
|
+
}[];
|
|
91
|
+
/**
|
|
92
|
+
* The calendar a set of frontmatter asks for, with no cascade around it —
|
|
93
|
+
* one merged record in, one zone out. The full cascade lives in
|
|
94
|
+
* `agentClock` below and in clock.ts; this is what the account-level parts
|
|
95
|
+
* of the platform (a wallet's month, a budget window) call.
|
|
61
96
|
*/
|
|
62
97
|
export declare function resolveTimezone(front: Record<string, unknown>): string;
|
|
63
|
-
/**
|
|
64
|
-
|
|
98
|
+
/**
|
|
99
|
+
* The clock this step works to: agent, then flow, then workspace, then
|
|
100
|
+
* account, then FOLDRUN_TIMEZONE, then UTC. Nearest wins, and a value that
|
|
101
|
+
* is not a zone falls through to the next level with a line to say so —
|
|
102
|
+
* see clock.ts for why this exists at all.
|
|
103
|
+
*/
|
|
104
|
+
export declare function agentClock(agentDir: string, tenant: string, agentFront: Record<string, unknown>, flowTimezone?: string | null): ClockChoice;
|
|
105
|
+
/**
|
|
106
|
+
* The language this step works in: agent, then workspace, then account, then
|
|
107
|
+
* FOLDRUN_LANGUAGE, then English. The flow level is not read yet — a flow's
|
|
108
|
+
* timezone: travels through three signatures to get here, and this will
|
|
109
|
+
* take the same road when a flow needs it.
|
|
110
|
+
*/
|
|
111
|
+
export declare function agentLanguage(agentDir: string, tenant: string, agentFront: Record<string, unknown>): LanguageChoice;
|
|
112
|
+
/**
|
|
113
|
+
* The country this step works for, on the same road as the language, then
|
|
114
|
+
* FOLDRUN_REGION, then whatever the language tag carried (`en-AU` says AU).
|
|
115
|
+
* Everything a country changes — currency, units, calendar, weekend, text
|
|
116
|
+
* direction — is derived from it in locale.ts; the three overrides
|
|
117
|
+
* (`currency:`, `calendar:`, `units:`) are read at the nearest level that
|
|
118
|
+
* wrote them.
|
|
119
|
+
*/
|
|
120
|
+
export declare function agentRegion(agentDir: string, tenant: string, agentFront: Record<string, unknown>, languageTag: string): RegionChoice;
|
|
121
|
+
export declare function agentLocaleOverrides(agentDir: string, tenant: string, agentFront: Record<string, unknown>): {
|
|
122
|
+
currency?: unknown;
|
|
123
|
+
calendar?: unknown;
|
|
124
|
+
units?: unknown;
|
|
125
|
+
};
|
|
65
126
|
/**
|
|
66
127
|
* The prose from AGENTS.md, outermost first.
|
|
67
128
|
*
|
|
@@ -69,6 +130,23 @@ export declare function localDate(timeZone: string, now?: Date): string;
|
|
|
69
130
|
* template as "context every agent here shares" — and never read. Only the
|
|
70
131
|
* frontmatter was, so the instructions people actually wrote reached no model.
|
|
71
132
|
*/
|
|
133
|
+
/**
|
|
134
|
+
* The sub-agents a step may delegate to (`subagents:`), as the SDK will get
|
|
135
|
+
* them: each resolved through agentContext exactly as its own step would be
|
|
136
|
+
* (grants only — no runtime; it runs inside its parent's), then cut to what
|
|
137
|
+
* the parent holds. Problems are lines on the step, never a failed step.
|
|
138
|
+
*/
|
|
139
|
+
export declare function buildSubagentSpecs(o: {
|
|
140
|
+
names: unknown;
|
|
141
|
+
self: string;
|
|
142
|
+
workspaceRoot: string;
|
|
143
|
+
tenant: string;
|
|
144
|
+
tags?: string[];
|
|
145
|
+
runId?: string;
|
|
146
|
+
flowTimezone?: string | null;
|
|
147
|
+
parentAllowed: string[];
|
|
148
|
+
push: (type: "info" | "error", text: string) => void;
|
|
149
|
+
}): SubagentSpec[];
|
|
72
150
|
export declare function sharedInstructions(agentDir: string, tenant: string): string | null;
|
|
73
151
|
/**
|
|
74
152
|
* Which of an agent's in-scope skills load for this run.
|
|
@@ -113,6 +191,14 @@ export declare function applicableSkills<T extends {
|
|
|
113
191
|
*/
|
|
114
192
|
export declare function saysUntilMarker(result: string | null, until: string): boolean;
|
|
115
193
|
export declare function resolveDocLinks(text: string, workspaceRoot: string): string;
|
|
194
|
+
export declare function repriced(catalog: Catalog | null, model: string, usage: {
|
|
195
|
+
inputTokens: number;
|
|
196
|
+
outputTokens: number;
|
|
197
|
+
} | null, sdkCost: number | null, push: (type: "info" | "error", text: string) => void,
|
|
198
|
+
/** The step's turns each priced at its own model — set when a sub-agent
|
|
199
|
+
* ran on a different model (ExecOutcome.turnsCostUsd). The lump `usage`
|
|
200
|
+
* priced at the step's model would bill those turns at the wrong rate. */
|
|
201
|
+
turnsCostUsd?: number | null): number | null;
|
|
116
202
|
/**
|
|
117
203
|
* Write one attempt onto the step's history and re-total the step.
|
|
118
204
|
*
|
|
@@ -123,10 +209,29 @@ export declare function resolveDocLinks(text: string, workspaceRoot: string): st
|
|
|
123
209
|
* step used to carry only its last attempt's cost, so a `retry: 2` step
|
|
124
210
|
* could spend three shares while reporting one.
|
|
125
211
|
*/
|
|
126
|
-
export declare function recordAttempt(step: StepRecord,
|
|
212
|
+
export declare function recordAttempt(step: StepRecord,
|
|
213
|
+
/** The step's attempt (`attempts`) these rows belong to. */
|
|
214
|
+
attempt: number, status: "completed" | "failed", startedAt: string, eventsBefore: number,
|
|
127
215
|
/** The attempt re-attached to a sandbox a previous driver left: same
|
|
128
216
|
* attempt, so its row is replaced rather than repeated. */
|
|
129
217
|
reattach?: boolean): void;
|
|
218
|
+
/**
|
|
219
|
+
* Did this attempt call its tools and then fail only on the check after —
|
|
220
|
+
* `verify:`, `output: json`, a schema? For a step whose tools act outward
|
|
221
|
+
* that is the one failure a retry must not answer: the email went, the post
|
|
222
|
+
* is up, and the check failing says nothing about whether they happened. A
|
|
223
|
+
* second attempt sends them again. Read off the attempt's own events, which
|
|
224
|
+
* both executors write the same way (step-exec.ts): every event a failed
|
|
225
|
+
* check writes carries `check: true`. It used to read only the LAST error's
|
|
226
|
+
* wording, and a failed shell verify or judge writes its detail after its
|
|
227
|
+
* headline — so the step was retried and the email went twice. The wording
|
|
228
|
+
* is still honoured, for a driver image older than the tag.
|
|
229
|
+
*/
|
|
230
|
+
export declare function actedThenFailedCheck(events: {
|
|
231
|
+
type: string;
|
|
232
|
+
text: string;
|
|
233
|
+
check?: boolean;
|
|
234
|
+
}[]): boolean;
|
|
130
235
|
/**
|
|
131
236
|
* Copy a directory tree by reading and writing the bytes.
|
|
132
237
|
*
|
|
@@ -140,6 +245,13 @@ reattach?: boolean): void;
|
|
|
140
245
|
* happened to create it.
|
|
141
246
|
*/
|
|
142
247
|
export declare function copyTreeBytes(from: string, to: string): void;
|
|
248
|
+
/**
|
|
249
|
+
* Wait, briefly, for the mounted credential to become one we have not
|
|
250
|
+
* already been refused on. Returns the new value, or null when the window
|
|
251
|
+
* passes without a change — which is the answer that means "this key is
|
|
252
|
+
* wrong", not "this key is stale".
|
|
253
|
+
*/
|
|
254
|
+
export declare function awaitRotatedCredential(before: string | undefined, now?: () => number, read?: () => string | undefined, waitMs?: number, pollMs?: number): Promise<string | null>;
|
|
143
255
|
/** How many times a busy provider is given another moment, and the longest
|
|
144
256
|
* any one wait may be. Three is the industry's habit and the point where
|
|
145
257
|
* waiting longer stops being kinder than failing. */
|
|
@@ -157,9 +269,31 @@ export declare const OVERLOAD_RETRIES = 3;
|
|
|
157
269
|
*/
|
|
158
270
|
export declare function isTransientOverload(text: string): boolean;
|
|
159
271
|
export declare function backoffMs(attempt: number, text?: string, random?: () => number): number;
|
|
272
|
+
/**
|
|
273
|
+
* The platform's model credential, read at the moment a step needs it.
|
|
274
|
+
*
|
|
275
|
+
* It used to come only from this process's environment, which meant the
|
|
276
|
+
* worker held whatever token it was started with. Refreshing an OAuth token
|
|
277
|
+
* REVOKES the old one, so a refresh without a restart left every run
|
|
278
|
+
* answering 401 — on 2026-09-18 that took every desk down for two hours, and
|
|
279
|
+
* nothing said so until a person read a failed run. The refresher's own
|
|
280
|
+
* comment had named the fix years of incidents earlier: stop shipping the
|
|
281
|
+
* token as an env var.
|
|
282
|
+
*
|
|
283
|
+
* So: when `FOLDRUN_MODEL_KEY_FILE` names a file (the Kubernetes secret,
|
|
284
|
+
* mounted rather than injected), it is read fresh every time. The kubelet
|
|
285
|
+
* updates a mounted secret in place within about a minute of it changing, so
|
|
286
|
+
* a refreshed token reaches the next step on its own, with no restart, no
|
|
287
|
+
* timing window, and nothing to skip while work is in flight.
|
|
288
|
+
*
|
|
289
|
+
* A missing or empty file falls back to the environment, which is what a
|
|
290
|
+
* local install, the CLI and every compose setup use.
|
|
291
|
+
*/
|
|
292
|
+
export declare function platformModelCredential(env?: NodeJS.ProcessEnv): string | undefined;
|
|
293
|
+
export declare function platformModelEnv(): Record<string, string | undefined>;
|
|
160
294
|
/**
|
|
161
295
|
* `schema: <path>` — the file, read and parsed, or null. Agent-relative like
|
|
162
|
-
* every other path in a flow (
|
|
296
|
+
* every other path in a flow (`workspace/schemas/lead.json`), confined to the
|
|
163
297
|
* workspace: a schema is the author's document, never something a step
|
|
164
298
|
* can point outside.
|
|
165
299
|
*/
|
|
@@ -275,3 +409,37 @@ export declare function waitForRun(tenant: string, workspace: string, runId: str
|
|
|
275
409
|
* nothing is what makes `?wait=true` useful rather than merely blocking.
|
|
276
410
|
*/
|
|
277
411
|
export declare function runResult(run: RunRecord): string | null;
|
|
412
|
+
/**
|
|
413
|
+
* What a Docker-run script sees of the workspace and the account: their
|
|
414
|
+
* scripts/ and their tools/, read-only. A folder tool's code lives in its
|
|
415
|
+
* tools/<name>/ folder, not in scripts/ — without those two mounts every
|
|
416
|
+
* folder tool (the hello template's wordcount among them) was handed a host
|
|
417
|
+
* path the container did not have, and failed on every call. A gallery tool
|
|
418
|
+
* nobody installed runs from the gallery's own shelf, so that is mounted too
|
|
419
|
+
* when there is one. A folder that does not exist is skipped by the copy.
|
|
420
|
+
*/
|
|
421
|
+
export declare function scriptMounts(agentDir: string, tenant: string): Record<string, string>;
|
|
422
|
+
/**
|
|
423
|
+
* The skills an agent can see, nearest first, each with the path the agent
|
|
424
|
+
* is told to read it at. Own skills, then the workspace's, then the
|
|
425
|
+
* workspace's `.agents/skills/` (the cross-client convention, scanned after
|
|
426
|
+
* the native location so a foldrun-native skill wins a name clash), then the
|
|
427
|
+
* account library. The nearest definition of a name wins.
|
|
428
|
+
*
|
|
429
|
+
* The workspace's are written `workspace/skills/…`, the one spelling for the
|
|
430
|
+
* workspace root, which the file tools expand themselves. `../../skills/…`
|
|
431
|
+
* left the model to resolve it against a path it had to guess, and on the
|
|
432
|
+
* hello template it climbed one level too far and was refused.
|
|
433
|
+
*/
|
|
434
|
+
export declare function skillsInScope(agentDir: string, tenant: string): DiscoveredSkill[];
|
|
435
|
+
/**
|
|
436
|
+
* The interpreters a set of scripts needs, read from what they are: the
|
|
437
|
+
* extension of `run:` (or of inline code), or an explicit `interpreter:`.
|
|
438
|
+
* Docker's script image is built from the runtime spec, and the base one is
|
|
439
|
+
* Python only, so a JavaScript tool that declared no `runtime:` (the demo's
|
|
440
|
+
* inline crm-upload, any folder tool's run.mjs) failed with no node to run
|
|
441
|
+
* it. Python is named too whenever a .py script is present, because asking
|
|
442
|
+
* for node alone builds on node:22-slim, which has no python3. Null when
|
|
443
|
+
* nothing beyond the default is needed.
|
|
444
|
+
*/
|
|
445
|
+
export declare function scriptLanguages(scripts: ScriptSpec[]): RuntimeSpec | null;
|