@foldrun/core 1.1.3 → 1.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.
package/LICENSE CHANGED
@@ -1,202 +1,39 @@
1
+ foldrun proprietary licence
1
2
 
2
- Apache License
3
- Version 2.0, January 2004
4
- http://www.apache.org/licenses/
3
+ Copyright (c) 2026 foldrun. All rights reserved.
5
4
 
6
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
+ This software, its source code and its documentation are the property of
6
+ foldrun. They are licensed, not sold.
7
7
 
8
- 1. Definitions.
8
+ You may install and run the foldrun packages published to npm (`foldrun`
9
+ and `@foldrun/core`) to write, check, run and deploy your own agents,
10
+ flows and workspaces, on your own machines and with the foldrun platform.
11
+ That includes the copies installing and running need, for your own use:
12
+ package caches and mirrors, CI and build machines, container images and
13
+ backups.
9
14
 
10
- "License" shall mean the terms and conditions for use, reproduction,
11
- and distribution as defined by Sections 1 through 9 of this document.
15
+ You may not, except where the law allows it despite this restriction:
16
+ copy, modify, merge, publish, distribute, sublicense, rent or sell the
17
+ software or any part of it; reverse engineer, decompile or disassemble it;
18
+ or use it to build a product or service that competes with foldrun.
12
19
 
13
- "Licensor" shall mean the copyright owner or entity authorized by
14
- the copyright owner that is granting the License.
20
+ What you write with the software (your agents, flows, knowledge and other
21
+ files) is yours.
15
22
 
16
- "Legal Entity" shall mean the union of the acting entity and all
17
- other entities that control, are controlled by, or are under common
18
- control with that entity. For the purposes of this definition,
19
- "control" means (i) the power, direct or indirect, to cause the
20
- direction or management of such entity, whether by contract or
21
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
- outstanding shares, or (iii) beneficial ownership of such entity.
23
+ Third-party components the software includes or installs (its npm
24
+ dependencies) remain under their own licences.
23
25
 
24
- "You" (or "Your") shall mean an individual or Legal Entity
25
- exercising permissions granted by this License.
26
+ This licence ends automatically if you break its terms, and you must then
27
+ stop using the software.
26
28
 
27
- "Source" form shall mean the preferred form for making modifications,
28
- including but not limited to software source code, documentation
29
- source, and configuration files.
29
+ Versions published before 17 October 2026 under the Apache License 2.0
30
+ remain available under that licence for those versions only.
30
31
 
31
- "Object" form shall mean any form resulting from mechanical
32
- transformation or translation of a Source form, including but
33
- not limited to compiled object code, generated documentation,
34
- and conversions to other media types.
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. TO THE EXTENT THE
35
+ LAW ALLOWS, IN NO EVENT SHALL FOLDRUN BE LIABLE FOR ANY CLAIM, DAMAGES OR
36
+ OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
37
+ ITS USE.
35
38
 
36
- "Work" shall mean the work of authorship, whether in Source or
37
- Object form, made available under the License, as indicated by a
38
- copyright notice that is included in or attached to the work
39
- (an example is provided in the Appendix below).
40
-
41
- "Derivative Works" shall mean any work, whether in Source or Object
42
- form, that is based on (or derived from) the Work and for which the
43
- editorial revisions, annotations, elaborations, or other modifications
44
- represent, as a whole, an original work of authorship. For the purposes
45
- of this License, Derivative Works shall not include works that remain
46
- separable from, or merely link (or bind by name) to the interfaces of,
47
- the Work and Derivative Works thereof.
48
-
49
- "Contribution" shall mean any work of authorship, including
50
- the original version of the Work and any modifications or additions
51
- to that Work or Derivative Works thereof, that is intentionally
52
- submitted to Licensor for inclusion in the Work by the copyright owner
53
- or by an individual or Legal Entity authorized to submit on behalf of
54
- the copyright owner. For the purposes of this definition, "submitted"
55
- means any form of electronic, verbal, or written communication sent
56
- to the Licensor or its representatives, including but not limited to
57
- communication on electronic mailing lists, source code control systems,
58
- and issue tracking systems that are managed by, or on behalf of, the
59
- Licensor for the purpose of discussing and improving the Work, but
60
- excluding communication that is conspicuously marked or otherwise
61
- designated in writing by the copyright owner as "Not a Contribution."
62
-
63
- "Contributor" shall mean Licensor and any individual or Legal Entity
64
- on behalf of whom a Contribution has been received by Licensor and
65
- subsequently incorporated within the Work.
66
-
67
- 2. Grant of Copyright License. Subject to the terms and conditions of
68
- this License, each Contributor hereby grants to You a perpetual,
69
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
- copyright license to reproduce, prepare Derivative Works of,
71
- publicly display, publicly perform, sublicense, and distribute the
72
- Work and such Derivative Works in Source or Object form.
73
-
74
- 3. Grant of Patent License. Subject to the terms and conditions of
75
- this License, each Contributor hereby grants to You a perpetual,
76
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
- (except as stated in this section) patent license to make, have made,
78
- use, offer to sell, sell, import, and otherwise transfer the Work,
79
- where such license applies only to those patent claims licensable
80
- by such Contributor that are necessarily infringed by their
81
- Contribution(s) alone or by combination of their Contribution(s)
82
- with the Work to which such Contribution(s) was submitted. If You
83
- institute patent litigation against any entity (including a
84
- cross-claim or counterclaim in a lawsuit) alleging that the Work
85
- or a Contribution incorporated within the Work constitutes direct
86
- or contributory patent infringement, then any patent licenses
87
- granted to You under this License for that Work shall terminate
88
- as of the date such litigation is filed.
89
-
90
- 4. Redistribution. You may reproduce and distribute copies of the
91
- Work or Derivative Works thereof in any medium, with or without
92
- modifications, and in Source or Object form, provided that You
93
- meet the following conditions:
94
-
95
- (a) You must give any other recipients of the Work or
96
- Derivative Works a copy of this License; and
97
-
98
- (b) You must cause any modified files to carry prominent notices
99
- stating that You changed the files; and
100
-
101
- (c) You must retain, in the Source form of any Derivative Works
102
- that You distribute, all copyright, patent, trademark, and
103
- attribution notices from the Source form of the Work,
104
- excluding those notices that do not pertain to any part of
105
- the Derivative Works; and
106
-
107
- (d) If the Work includes a "NOTICE" text file as part of its
108
- distribution, then any Derivative Works that You distribute must
109
- include a readable copy of the attribution notices contained
110
- within such NOTICE file, excluding those notices that do not
111
- pertain to any part of the Derivative Works, in at least one
112
- of the following places: within a NOTICE text file distributed
113
- as part of the Derivative Works; within the Source form or
114
- documentation, if provided along with the Derivative Works; or,
115
- within a display generated by the Derivative Works, if and
116
- wherever such third-party notices normally appear. The contents
117
- of the NOTICE file are for informational purposes only and
118
- do not modify the License. You may add Your own attribution
119
- notices within Derivative Works that You distribute, alongside
120
- or as an addendum to the NOTICE text from the Work, provided
121
- that such additional attribution notices cannot be construed
122
- as modifying the License.
123
-
124
- You may add Your own copyright statement to Your modifications and
125
- may provide additional or different license terms and conditions
126
- for use, reproduction, or distribution of Your modifications, or
127
- for any such Derivative Works as a whole, provided Your use,
128
- reproduction, and distribution of the Work otherwise complies with
129
- the conditions stated in this License.
130
-
131
- 5. Submission of Contributions. Unless You explicitly state otherwise,
132
- any Contribution intentionally submitted for inclusion in the Work
133
- by You to the Licensor shall be under the terms and conditions of
134
- this License, without any additional terms or conditions.
135
- Notwithstanding the above, nothing herein shall supersede or modify
136
- the terms of any separate license agreement you may have executed
137
- with Licensor regarding such Contributions.
138
-
139
- 6. Trademarks. This License does not grant permission to use the trade
140
- names, trademarks, service marks, or product names of the Licensor,
141
- except as required for reasonable and customary use in describing the
142
- origin of the Work and reproducing the content of the NOTICE file.
143
-
144
- 7. Disclaimer of Warranty. Unless required by applicable law or
145
- agreed to in writing, Licensor provides the Work (and each
146
- Contributor provides its Contributions) on an "AS IS" BASIS,
147
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
- implied, including, without limitation, any warranties or conditions
149
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
- PARTICULAR PURPOSE. You are solely responsible for determining the
151
- appropriateness of using or redistributing the Work and assume any
152
- risks associated with Your exercise of permissions under this License.
153
-
154
- 8. Limitation of Liability. In no event and under no legal theory,
155
- whether in tort (including negligence), contract, or otherwise,
156
- unless required by applicable law (such as deliberate and grossly
157
- negligent acts) or agreed to in writing, shall any Contributor be
158
- liable to You for damages, including any direct, indirect, special,
159
- incidental, or consequential damages of any character arising as a
160
- result of this License or out of the use or inability to use the
161
- Work (including but not limited to damages for loss of goodwill,
162
- work stoppage, computer failure or malfunction, or any and all
163
- other commercial damages or losses), even if such Contributor
164
- has been advised of the possibility of such damages.
165
-
166
- 9. Accepting Warranty or Additional Liability. While redistributing
167
- the Work or Derivative Works thereof, You may choose to offer,
168
- and charge a fee for, acceptance of support, warranty, indemnity,
169
- or other liability obligations and/or rights consistent with this
170
- License. However, in accepting such obligations, You may act only
171
- on Your own behalf and on Your sole responsibility, not on behalf
172
- of any other Contributor, and only if You agree to indemnify,
173
- defend, and hold each Contributor harmless for any liability
174
- incurred by, or claims asserted against, such Contributor by reason
175
- of your accepting any such warranty or additional liability.
176
-
177
- END OF TERMS AND CONDITIONS
178
-
179
- APPENDIX: How to apply the Apache License to your work.
180
-
181
- To apply the Apache License to your work, attach the following
182
- boilerplate notice, with the fields enclosed by brackets "[]"
183
- replaced with your own identifying information. (Don't include
184
- the brackets!) The text should be enclosed in the appropriate
185
- comment syntax for the file format. We also recommend that a
186
- file or class name and description of purpose be included on the
187
- same "printed page" as the copyright notice for easier
188
- identification within third-party archives.
189
-
190
- Copyright 2026 foldrun contributors
191
-
192
- Licensed under the Apache License, Version 2.0 (the "License");
193
- you may not use this file except in compliance with the License.
194
- You may obtain a copy of the License at
195
-
196
- http://www.apache.org/licenses/LICENSE-2.0
197
-
198
- Unless required by applicable law or agreed to in writing, software
199
- distributed under the License is distributed on an "AS IS" BASIS,
200
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
- See the License for the specific language governing permissions and
202
- limitations under the License.
39
+ Questions: hello@foldrun.io
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # foldrun
2
2
 
3
- [![ci](https://github.com/foldrun-io/foldrun-core/actions/workflows/ci.yml/badge.svg)](https://github.com/foldrun-io/foldrun-core/actions/workflows/ci.yml)
4
3
  [![npm](https://img.shields.io/npm/v/@foldrun/core)](https://www.npmjs.com/package/@foldrun/core)
5
- [![licence](https://img.shields.io/badge/licence-Apache--2.0-blue)](LICENSE)
6
4
 
7
5
  **Agents are just folders. Write them, check them, run them.**
8
6
 
@@ -126,14 +124,14 @@ truth.
126
124
  webhook triggers, durable runs with full history, a secret store, team access,
127
125
  and containers you never touch. Push the folder, it runs.
128
126
 
129
- The format, the CLI and the runtime are open source (Apache-2.0), and the
130
- hosted platform imports the same core rather than a fork. Writing and checking
127
+ The CLI and the runtime are free to install from npm, and the hosted
128
+ platform imports the same core rather than a fork. Writing and checking
131
129
  an agent locally costs nothing and needs no account — that is the on-ramp to
132
130
  the host, not a competitor to it.
133
131
 
134
132
  Where the two differ is operations, not capability. Locally a run happens in
135
133
  your terminal; hosted, it survives a restart, retries a failed step, waits days
136
- for an approval and tells you what it cost. Nothing is held back from the open
134
+ for an approval and tells you what it cost. Nothing is held back from the local
137
135
  version to make the hosted one worth buying.
138
136
 
139
137
  ## This repo, and the others
@@ -150,11 +148,11 @@ Most people want the CLI, not this package — `npm install -g foldrun`.
150
148
  | `okf/WHITE-PAPER.md` | hosting OKF: what the spec leaves to hosts |
151
149
  | `tests/` | the runtime's tests (`npm test`) |
152
150
 
153
- The command-line tool is its own repository,
154
- [`foldrun-cli`](https://github.com/foldrun-io/foldrun-cli), and depends on
151
+ The command-line tool is its own package,
152
+ [`foldrun`](https://www.npmjs.com/package/foldrun), and depends on
155
153
  this package. The reference documentation is at
156
- [docs.foldrun.io](https://docs.foldrun.io). The hosted platform's own
157
- repositories are private; see "Hosting it" below.
154
+ [docs.foldrun.io](https://docs.foldrun.io). Every foldrun repository is
155
+ private; see "Hosting it" below.
158
156
 
159
157
  ### Templates and workspaces
160
158
 
@@ -191,13 +189,9 @@ This package is the framework: everything needed to read a workspace and
191
189
  run it on the machine you are on. The platform — the dashboard, a queue and
192
190
  its worker, one sandbox per step, a vault, metering, a team — is built on
193
191
  it, in a separate package that plugs in through `src/platform.ts`. Nothing
194
- in this repository imports it, so what is here is exactly what is open.
195
-
196
- **Run the platform yourself:** one container, one command —
197
- [self-hosting/](self-hosting/). Sign up at `localhost:3900`, and
198
- `foldrun deploy` moves a workspace from your machine to it unchanged. The
199
- images are the same builds that run foldrun's own installation, published
200
- under the same versions.
192
+ in this repository imports it. The platform is hosted by foldrun and is not
193
+ distributed; `foldrun deploy` moves a workspace from your machine to it
194
+ unchanged.
201
195
 
202
196
  ## Requirements
203
197
 
@@ -273,4 +267,7 @@ Known gaps: one platform replica per data directory (the web/worker role
273
267
  split needs RWX storage), and the dashboard's run lists re-read run files
274
268
  per request (fine to thousands of runs).
275
269
 
276
- Apache-2.0.
270
+ ## Licence
271
+
272
+ Proprietary; see [LICENSE](LICENSE). Versions published before 17 October
273
+ 2026 were Apache-2.0 and stay so.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- // @foldrun/core — the open-source runtime.
1
+ // @foldrun/core — the runtime.
2
2
  //
3
3
  // Everything needed to read a workspace of markdown files and run the agents
4
4
  // in it. No server, no database, no account: point it at a folder.
5
5
  //
6
6
  // The hosted platform imports these same modules. That is deliberate — if the
7
- // open version were a reduced copy it would rot, and self-hosting would feel
8
- // like a downgrade instead of a choice. What the platform adds — a queue and
7
+ // local version were a reduced copy it would rot, and running on a laptop
8
+ // would behave differently from running hosted. What the platform adds — a queue and
9
9
  // its worker, metering and billing, pods on a cluster, per-account keys in a
10
10
  // database, previews, share links, tenancy — lives in its own private package
11
11
  // and plugs in through platform.ts. Nothing here imports it.
@@ -1,4 +1,5 @@
1
1
  import { type DeployFile } from "./store.ts";
2
+ import { type ScanFinding, type ScanOptions } from "./scan.ts";
2
3
  /**
3
4
  * Is this path, relative to a workspace root, one `readTree` would carry?
4
5
  *
@@ -69,7 +70,22 @@ export declare function readTree(dir: string): DeployFile[];
69
70
  * Returns the problem, or null.
70
71
  */
71
72
  export declare function unopenedFrontmatter(raw: string): string | null;
73
+ /**
74
+ * What a deploy says but does not refuse: the structural warnings below, and
75
+ * the scanner's findings about what should not be in the files at all — a
76
+ * credential written in, text a reviewer cannot see. The scanner's design
77
+ * advice (an agent that could leak, an unpinned package) is for `foldrun
78
+ * check` and the Checks page, not for every deploy's output.
79
+ */
72
80
  export declare function deployWarnings(files: DeployFile[]): DeployIssue[];
81
+ /**
82
+ * Everything the platform can say about a workspace's files, as findings
83
+ * with rule ids: what a deploy refuses (errors), what it warns about, and the
84
+ * whole scanner. The Checks page and `GET …/check` answer with this; `foldrun
85
+ * check` asks more (it resolves every library and the platform's), so treat
86
+ * this as the server's view of the same rules, not a second set.
87
+ */
88
+ export declare function checkFiles(files: DeployFile[], options?: ScanOptions): ScanFinding[];
73
89
  export declare function deployIssues(files: DeployFile[]): DeployIssue[];
74
90
  /**
75
91
  * Runs that make this a bad moment to swap the files under them.
@@ -34,6 +34,7 @@ import { languageProblem } from "./language.js";
34
34
  import { localeProblems } from "./locale.js";
35
35
  import { repoDir } from "./gitrepo.js";
36
36
  import { entriesNoFollow } from "./paths.js";
37
+ import { filterIgnored, findingFingerprint, ruleForWhere, scanFiles } from "./scan.js";
37
38
  /** Directories a deploy never reads out of a source tree. */
38
39
  const NOT_SOURCE = new Set([".git", "node_modules", "runs", "outputs", ".foldrun", ".results"]);
39
40
  /** Files that are never part of a workspace, whatever directory they sit in. */
@@ -186,7 +187,40 @@ export function unopenedFrontmatter(raw) {
186
187
  return null;
187
188
  return "the frontmatter has no opening `---`, so none of it is read: the agent runs with no tools and the default model. Add `---` as the first line.";
188
189
  }
190
+ /**
191
+ * What a deploy says but does not refuse: the structural warnings below, and
192
+ * the scanner's findings about what should not be in the files at all — a
193
+ * credential written in, text a reviewer cannot see. The scanner's design
194
+ * advice (an agent that could leak, an unpinned package) is for `foldrun
195
+ * check` and the Checks page, not for every deploy's output.
196
+ */
189
197
  export function deployWarnings(files) {
198
+ const scanned = scanFiles(files, { only: ["secret", "content"] })
199
+ .filter((f) => f.level !== "info")
200
+ .map((f) => ({ where: `${f.file}${f.line ? `:${f.line}` : ""}`, message: `${f.message} [${f.rule}]` }));
201
+ return [...structuralWarnings(files), ...scanned];
202
+ }
203
+ /**
204
+ * Everything the platform can say about a workspace's files, as findings
205
+ * with rule ids: what a deploy refuses (errors), what it warns about, and the
206
+ * whole scanner. The Checks page and `GET …/check` answer with this; `foldrun
207
+ * check` asks more (it resolves every library and the platform's), so treat
208
+ * this as the server's view of the same rules, not a second set.
209
+ */
210
+ export function checkFiles(files, options = {}) {
211
+ const finding = (i, level, kind) => {
212
+ const m = /^(.*?)(?::(\d+))?(?: .*)?$/.exec(i.where);
213
+ const file = m?.[1] || i.where;
214
+ const rule = ruleForWhere(i.where, kind);
215
+ return { rule, level, file, ...(m?.[2] ? { line: Number(m[2]) } : {}), message: i.message, fingerprint: findingFingerprint(rule, file, i.message) };
216
+ };
217
+ const own = [
218
+ ...deployIssues(files).map((i) => finding(i, "error")),
219
+ ...structuralWarnings(files).map((i) => finding(i, "warn", i.kind)),
220
+ ];
221
+ return [...filterIgnored(own, files), ...scanFiles(files, options)].sort((a, b) => a.file.localeCompare(b.file) || (a.line ?? 0) - (b.line ?? 0) || a.rule.localeCompare(b.rule));
222
+ }
223
+ function structuralWarnings(files) {
190
224
  const front = (content) => {
191
225
  try {
192
226
  return matter(content).data;
@@ -244,7 +278,7 @@ export function deployWarnings(files) {
244
278
  }
245
279
  for (const w of lintFlow(flow, { agents: agentNames, outwardAgents })) {
246
280
  if (w.kind === "outward")
247
- out.push({ where: `${f.path}${w.line ? `:${w.line}` : ""}`, message: w.message });
281
+ out.push({ where: `${f.path}${w.line ? `:${w.line}` : ""}`, message: w.message, kind: "outward" });
248
282
  }
249
283
  }
250
284
  return out;
@@ -4,7 +4,7 @@ import type { EgressHooks } from "./egress.ts";
4
4
  export type IsolatedStepRunner = (args: RunInContainerArgs) => Promise<ContainerStepOutcome>;
5
5
  /** Who this install is for. `hosted` means someone is paying the operator
6
6
  * for it — a wallet, a plan, a bill. `self-hosted` is everything else: a
7
- * laptop, a company's own box, the open-source download. */
7
+ * laptop, a dev install, a box nobody bills on. */
8
8
  export type Edition = "self-hosted" | "hosted";
9
9
  /** What a trigger gate decided. `admit: false` is never an error: the
10
10
  * trigger was received and understood, and the flow's own file says this
@@ -23,9 +23,9 @@ export interface PlatformHooks {
23
23
  * the wallet, top-ups, plan limits, whatever is added next that assumes
24
24
  * a customer — asks before it renders or answers. Default: self-hosted,
25
25
  * which is what a process that never registered a platform is, and what
26
- * the open-source image is unless its operator configures billing. One
27
- * predicate, one place, so "does the community build show X" is a test
28
- * and not an audit. */
26
+ * any install is unless its operator configures billing. One predicate,
27
+ * one place, so "does an unbilled install show X" is a test and not an
28
+ * audit. */
29
29
  edition(): Edition;
30
30
  /** Put a flow run where a worker will pick it up. Default: start it here, now. */
31
31
  enqueueFlowRun(tenant: string, workspace: string, steps: FlowStep[], flowName: string, modelOverride?: string | null, tags?: string[],
@@ -239,7 +239,7 @@ export declare const SHARED_RUNTIMES = "/opt/foldrun-runtimes/shared/.runtimes";
239
239
  * as a trusted local file, which is precisely the path gVisor, the capability
240
240
  * drop and the egress policy all exist to close. Disk is the cheaper thing to
241
241
  * spend. One volume per tenant keeps that boundary; each carries a
242
- * `foldrun.io/tenant` label so it can be found and pruned (self-hosting/README.md).
242
+ * `foldrun.io/tenant` label so it can be found and pruned.
243
243
  *
244
244
  * The venvs inside carry the runner's own absolute paths, distinct from the
245
245
  * host's `<tenant>/.runtimes` cache — two roots, so a hit is always a real hit.
@@ -345,7 +345,7 @@ const DOCKER_VOLUME_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/;
345
345
  * as a trusted local file, which is precisely the path gVisor, the capability
346
346
  * drop and the egress policy all exist to close. Disk is the cheaper thing to
347
347
  * spend. One volume per tenant keeps that boundary; each carries a
348
- * `foldrun.io/tenant` label so it can be found and pruned (self-hosting/README.md).
348
+ * `foldrun.io/tenant` label so it can be found and pruned.
349
349
  *
350
350
  * The venvs inside carry the runner's own absolute paths, distinct from the
351
351
  * host's `<tenant>/.runtimes` cache — two roots, so a hit is always a real hit.
@@ -0,0 +1,174 @@
1
+ export type ScanLevel = "error" | "warn" | "info";
2
+ export type ScanCategory = "secret" | "security" | "content" | "supply-chain" | "config";
3
+ export interface ScanRule {
4
+ id: string;
5
+ category: ScanCategory;
6
+ level: ScanLevel;
7
+ /** One line, for a rule list. */
8
+ title: string;
9
+ /** Why it matters and what to do instead — the rule's docs, in short. */
10
+ help: string;
11
+ /** OWASP Top 10 for Agentic Applications (2026) ids it guards against. */
12
+ owasp?: string[];
13
+ }
14
+ export interface ScanFile {
15
+ /** Relative to the workspace root (`agents/x/agent.md`), or `library/…`. */
16
+ path: string;
17
+ content: string;
18
+ }
19
+ export interface ScanFinding {
20
+ rule: string;
21
+ level: ScanLevel;
22
+ file: string;
23
+ /** 1-indexed; absent for a finding about the whole file. */
24
+ line?: number;
25
+ message: string;
26
+ /** Stable across edits elsewhere in the file: rule + file + line text. */
27
+ fingerprint: string;
28
+ }
29
+ export interface ScanOptions {
30
+ /** Tool names whose definition says `outward: true` — the CLI and the
31
+ * deploy resolve these across the library; the scanner also finds the
32
+ * workspace's own among the files it is given. */
33
+ outwardTools?: Iterable<string>;
34
+ /** Only these rule ids (or categories, `secret`, `security`, …). */
35
+ only?: string[];
36
+ /** The account AGENTS.md's `network:` — the level above the workspace's,
37
+ * which the files of one workspace do not carry. */
38
+ accountNetwork?: unknown;
39
+ }
40
+ export declare const OWASP_URL = "https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026";
41
+ export declare const SCAN_RULES: readonly ScanRule[];
42
+ /**
43
+ * The rules `foldrun check` and the deploy have always had — "will this
44
+ * run?" — given ids so a finding from them can be filtered, ignored,
45
+ * baselined and carried in SARIF like the scanner's. Coarse on purpose, one
46
+ * per kind of file; the message says exactly what is wrong. Their level is
47
+ * each problem's own, so it is not fixed here.
48
+ */
49
+ export declare const CHECK_RULES: readonly (Omit<ScanRule, "level"> & {
50
+ level?: ScanLevel;
51
+ })[];
52
+ /** The rule id of a check or deploy problem, from where it was found and
53
+ * the flow lint's tag when it has one. */
54
+ export declare function ruleForWhere(where: string, kind?: string): string;
55
+ /** The rule behind an id — the scanner's or check's own — or undefined. */
56
+ export declare function scanRule(id: string): (Omit<ScanRule, "level"> & {
57
+ level?: ScanLevel;
58
+ }) | undefined;
59
+ /** Where a rule's docs live — one page, an anchor per rule. */
60
+ export declare function ruleDocsUrl(id: string): string;
61
+ /** rule + file + the text that was flagged, normalised. Not the line number:
62
+ * a baseline must survive a paragraph added above the finding. */
63
+ export declare function findingFingerprint(rule: string, file: string, text: string): string;
64
+ /** What a finding may show of a secret: enough to find it, not to use it. */
65
+ export declare function redactSecret(secret: string): string;
66
+ /** The text with every credential in it redacted — for a finding that
67
+ * quotes source, so no message ever carries a key whole. */
68
+ export declare function redactText(text: string): string;
69
+ /** The known field a key was probably meant to be, or null. */
70
+ export declare function nearestField(key: string, known: readonly string[]): string | null;
71
+ /**
72
+ * Every finding in these files, ignores applied. Findings are sorted by file
73
+ * then line, and one rule says one thing once per line.
74
+ */
75
+ export declare function scanFiles(files: ScanFile[], options?: ScanOptions): ScanFinding[];
76
+ /**
77
+ * Drop the findings a `foldrun-ignore` comment (with a reason) covers — for
78
+ * findings that did not come from scanFiles, such as check's own rules, so
79
+ * one comment syntax works for every rule. Ignores without a reason are
80
+ * reported by scanFiles itself, once.
81
+ */
82
+ export declare function filterIgnored<T extends {
83
+ rule: string;
84
+ file: string;
85
+ line?: number;
86
+ }>(findings: T[], files: ScanFile[]): T[];
87
+ export interface ScanBaseline {
88
+ version: 1;
89
+ /** When it was written — for a person reading the file, not for matching. */
90
+ created?: string;
91
+ findings: {
92
+ rule: string;
93
+ file: string;
94
+ fingerprint: string;
95
+ }[];
96
+ }
97
+ /** A baseline that accepts every finding here as known. */
98
+ export declare function makeBaseline(findings: Pick<ScanFinding, "rule" | "file" | "fingerprint">[], created?: string): ScanBaseline;
99
+ /** Findings not in the baseline, and how many it hid. A baseline that does
100
+ * not parse hides nothing — failing open would hide every new finding. */
101
+ export declare function applyBaseline<T extends Pick<ScanFinding, "rule" | "file" | "fingerprint">>(findings: T[], baseline: unknown): {
102
+ kept: T[];
103
+ baselined: number;
104
+ };
105
+ export interface SarifFinding {
106
+ rule: string;
107
+ level: ScanLevel;
108
+ file: string;
109
+ line?: number;
110
+ message: string;
111
+ fingerprint: string;
112
+ }
113
+ export declare function toSarif(findings: SarifFinding[], opts?: {
114
+ version?: string;
115
+ rules?: {
116
+ id: string;
117
+ title: string;
118
+ help?: string;
119
+ }[];
120
+ root?: string;
121
+ }): {
122
+ $schema: string;
123
+ version: string;
124
+ runs: {
125
+ tool: {
126
+ driver: {
127
+ name: string;
128
+ informationUri: string;
129
+ version?: string | undefined;
130
+ rules: {
131
+ id: string;
132
+ name: string;
133
+ shortDescription: {
134
+ text: string;
135
+ };
136
+ help?: {
137
+ text: string;
138
+ } | undefined;
139
+ helpUri: string;
140
+ properties: {
141
+ tags: string[];
142
+ };
143
+ }[];
144
+ };
145
+ };
146
+ originalUriBaseIds?: {
147
+ SRCROOT: {
148
+ uri: string;
149
+ };
150
+ } | undefined;
151
+ results: {
152
+ ruleId: string;
153
+ ruleIndex: number;
154
+ level: string;
155
+ message: {
156
+ text: string;
157
+ };
158
+ locations: {
159
+ physicalLocation: {
160
+ artifactLocation: {
161
+ uri: string;
162
+ uriBaseId?: string | undefined;
163
+ };
164
+ region?: {
165
+ startLine: number;
166
+ } | undefined;
167
+ };
168
+ }[];
169
+ partialFingerprints: {
170
+ "foldrun/v1": string;
171
+ };
172
+ }[];
173
+ }[];
174
+ };