@foldrun/core 0.2.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 (166) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +239 -0
  3. package/dist/index.d.ts +32 -0
  4. package/dist/index.js +43 -0
  5. package/dist/src/agent-tools.d.ts +31 -0
  6. package/dist/src/agent-tools.js +99 -0
  7. package/dist/src/agents-md.d.ts +9 -0
  8. package/dist/src/agents-md.js +83 -0
  9. package/dist/src/api-tools.d.ts +38 -0
  10. package/dist/src/api-tools.js +313 -0
  11. package/dist/src/approvals.d.ts +39 -0
  12. package/dist/src/approvals.js +103 -0
  13. package/dist/src/arrange.d.ts +8 -0
  14. package/dist/src/arrange.js +40 -0
  15. package/dist/src/catalog.d.ts +108 -0
  16. package/dist/src/catalog.js +255 -0
  17. package/dist/src/completions.d.ts +61 -0
  18. package/dist/src/completions.js +578 -0
  19. package/dist/src/confine.d.ts +31 -0
  20. package/dist/src/confine.js +298 -0
  21. package/dist/src/container.d.ts +30 -0
  22. package/dist/src/container.js +172 -0
  23. package/dist/src/context-tools.d.ts +81 -0
  24. package/dist/src/context-tools.js +347 -0
  25. package/dist/src/deploy.d.ts +100 -0
  26. package/dist/src/deploy.js +377 -0
  27. package/dist/src/egress.d.ts +75 -0
  28. package/dist/src/egress.js +133 -0
  29. package/dist/src/evals.d.ts +150 -0
  30. package/dist/src/evals.js +651 -0
  31. package/dist/src/flow-lint.d.ts +16 -0
  32. package/dist/src/flow-lint.js +177 -0
  33. package/dist/src/git-hook.d.ts +1 -0
  34. package/dist/src/git-hook.js +70 -0
  35. package/dist/src/git.d.ts +37 -0
  36. package/dist/src/git.js +101 -0
  37. package/dist/src/gitrepo.d.ts +95 -0
  38. package/dist/src/gitrepo.js +355 -0
  39. package/dist/src/history.d.ts +82 -0
  40. package/dist/src/history.js +259 -0
  41. package/dist/src/kinds.d.ts +95 -0
  42. package/dist/src/kinds.js +421 -0
  43. package/dist/src/library.d.ts +94 -0
  44. package/dist/src/library.js +341 -0
  45. package/dist/src/linkable.d.ts +20 -0
  46. package/dist/src/linkable.js +113 -0
  47. package/dist/src/model-probe.d.ts +21 -0
  48. package/dist/src/model-probe.js +81 -0
  49. package/dist/src/notify.d.ts +61 -0
  50. package/dist/src/notify.js +252 -0
  51. package/dist/src/oauth-presets.d.ts +13 -0
  52. package/dist/src/oauth-presets.js +39 -0
  53. package/dist/src/okf.d.ts +220 -0
  54. package/dist/src/okf.js +656 -0
  55. package/dist/src/openapi.d.ts +66 -0
  56. package/dist/src/openapi.js +342 -0
  57. package/dist/src/paths.d.ts +33 -0
  58. package/dist/src/paths.js +78 -0
  59. package/dist/src/platform.d.ts +32 -0
  60. package/dist/src/platform.js +48 -0
  61. package/dist/src/providers.d.ts +47 -0
  62. package/dist/src/providers.js +114 -0
  63. package/dist/src/refs.d.ts +20 -0
  64. package/dist/src/refs.js +78 -0
  65. package/dist/src/run-container.d.ts +227 -0
  66. package/dist/src/run-container.js +760 -0
  67. package/dist/src/runner.d.ts +241 -0
  68. package/dist/src/runner.js +3215 -0
  69. package/dist/src/runtime.d.ts +41 -0
  70. package/dist/src/runtime.js +357 -0
  71. package/dist/src/script-tools.d.ts +62 -0
  72. package/dist/src/script-tools.js +296 -0
  73. package/dist/src/secret-files.d.ts +12 -0
  74. package/dist/src/secret-files.js +92 -0
  75. package/dist/src/secrets.d.ts +147 -0
  76. package/dist/src/secrets.js +626 -0
  77. package/dist/src/starter.d.ts +21 -0
  78. package/dist/src/starter.js +399 -0
  79. package/dist/src/step-exec.d.ts +136 -0
  80. package/dist/src/step-exec.js +391 -0
  81. package/dist/src/storage.d.ts +123 -0
  82. package/dist/src/storage.js +640 -0
  83. package/dist/src/store.d.ts +1052 -0
  84. package/dist/src/store.js +2378 -0
  85. package/dist/src/tar.d.ts +30 -0
  86. package/dist/src/tar.js +111 -0
  87. package/dist/src/tool-names.d.ts +39 -0
  88. package/dist/src/tool-names.js +79 -0
  89. package/dist/src/tool-programs.d.ts +18 -0
  90. package/dist/src/tool-programs.js +52 -0
  91. package/dist/src/tool-test.d.ts +19 -0
  92. package/dist/src/tool-test.js +335 -0
  93. package/dist/src/translator.d.ts +159 -0
  94. package/dist/src/translator.js +986 -0
  95. package/dist/src/triggers.d.ts +60 -0
  96. package/dist/src/triggers.js +270 -0
  97. package/dist/src/webhook.d.ts +47 -0
  98. package/dist/src/webhook.js +148 -0
  99. package/index.ts +44 -0
  100. package/package.json +64 -0
  101. package/src/agent-tools.ts +138 -0
  102. package/src/agents-md.ts +81 -0
  103. package/src/api-tools.ts +389 -0
  104. package/src/approvals.ts +129 -0
  105. package/src/arrange.ts +42 -0
  106. package/src/catalog.ts +321 -0
  107. package/src/completions.ts +652 -0
  108. package/src/confine.ts +350 -0
  109. package/src/container.ts +220 -0
  110. package/src/context-tools.ts +435 -0
  111. package/src/deploy.ts +458 -0
  112. package/src/egress.ts +176 -0
  113. package/src/evals.ts +812 -0
  114. package/src/flow-lint.ts +215 -0
  115. package/src/git-hook.ts +73 -0
  116. package/src/git.ts +117 -0
  117. package/src/gitrepo.ts +391 -0
  118. package/src/history.ts +329 -0
  119. package/src/kinds.ts +507 -0
  120. package/src/library.ts +419 -0
  121. package/src/linkable.ts +123 -0
  122. package/src/model-probe.ts +112 -0
  123. package/src/notify.ts +281 -0
  124. package/src/oauth-presets.ts +54 -0
  125. package/src/okf.ts +768 -0
  126. package/src/openapi.ts +383 -0
  127. package/src/paths.ts +79 -0
  128. package/src/platform.ts +87 -0
  129. package/src/providers.ts +147 -0
  130. package/src/refs.ts +83 -0
  131. package/src/run-container.ts +883 -0
  132. package/src/runner.ts +3446 -0
  133. package/src/runtime.ts +404 -0
  134. package/src/script-tools.ts +383 -0
  135. package/src/secret-files.ts +101 -0
  136. package/src/secrets.ts +799 -0
  137. package/src/starter.ts +415 -0
  138. package/src/step-exec.ts +498 -0
  139. package/src/storage.ts +771 -0
  140. package/src/store.ts +2985 -0
  141. package/src/tar.ts +124 -0
  142. package/src/tool-names.ts +91 -0
  143. package/src/tool-programs.ts +65 -0
  144. package/src/tool-test.ts +401 -0
  145. package/src/translator.ts +1029 -0
  146. package/src/triggers.ts +287 -0
  147. package/src/webhook.ts +183 -0
  148. package/templates/blog-desk/AGENTS.md +13 -0
  149. package/templates/blog-desk/agents/researcher/agent.md +11 -0
  150. package/templates/blog-desk/agents/writer/agent.md +8 -0
  151. package/templates/blog-desk/evals/writer-quality.md +10 -0
  152. package/templates/blog-desk/flows/publish.md +10 -0
  153. package/templates/blog-desk/knowledge/house-style.md +9 -0
  154. package/templates/blog-desk/knowledge/index.md +9 -0
  155. package/templates/hello/AGENTS.md +18 -0
  156. package/templates/hello/agents/curator/agent.md +32 -0
  157. package/templates/hello/agents/notetaker/agent.md +24 -0
  158. package/templates/hello/evals/house-style.md +16 -0
  159. package/templates/hello/flows/memory-review.md +7 -0
  160. package/templates/hello/flows/note.md +7 -0
  161. package/templates/hello/knowledge/house-style.md +15 -0
  162. package/templates/hello/knowledge/index.md +9 -0
  163. package/templates/hello/skills/plain-english/SKILL.md +11 -0
  164. package/templates/hello/state/publishing.md +7 -0
  165. package/templates/hello/tools/wordcount/run.py +13 -0
  166. package/templates/hello/tools/wordcount/tool.md +22 -0
@@ -0,0 +1,241 @@
1
+ import { type FlowStep, type RunRecord } from "./store.ts";
2
+ /** How much of the earlier groups' output a step is handed, in characters.
3
+ * Newest groups are kept when the total is over it. */
4
+ export declare const CONTEXT_CHARS = 30000;
5
+ /** tools: [desks] — how many other-workspace runs cross into a step, in all. */
6
+ export declare const DESK_RUNS_CAP = 100;
7
+ /**
8
+ * What a group is handed from the groups before it: all of them, oldest
9
+ * first, so a group-3 reporter sees what group 1 measured and not only what
10
+ * group 2 diagnosed. When the total is over the cap, the oldest groups are
11
+ * dropped whole before anything is cut mid-text — the newest is the one the
12
+ * step is most likely to be about.
13
+ */
14
+ export declare function joinEarlierGroups(groupResults: (string | null)[], gi: number, cap?: number): string | null;
15
+ export interface DiscoveredSkill {
16
+ name: string;
17
+ description: string;
18
+ /** Tags that must be present on the run for this skill to load. A skill
19
+ * with none always loads. Mirrors "apply when this check failed". */
20
+ when: string[];
21
+ /** Path to SKILL.md (or the flat .md), relative to the agent directory. */
22
+ path: string;
23
+ /** Skill folder relative to the agent directory, or null for flat skills. */
24
+ dir: string | null;
25
+ hasScripts: boolean;
26
+ /** The rest of the Agent Skills layout: references/ and assets/. */
27
+ hasReferences: boolean;
28
+ hasAssets: boolean;
29
+ }
30
+ export declare function discoverSkills(agentDir: string, subdir?: string): DiscoveredSkill[];
31
+ /**
32
+ * AGENTS.md, at both scopes it can live at.
33
+ *
34
+ * `AGENTS.md` is the Linux Foundation name; `project.md` is still read so
35
+ * nothing written before the rename breaks.
36
+ *
37
+ * Returns null rather than throwing on unparseable YAML: a broken shared file
38
+ * must not take down every agent under it.
39
+ */
40
+ export declare function readAgentsMd(dir: string): {
41
+ data: Record<string, unknown>;
42
+ body: string;
43
+ } | null;
44
+ /**
45
+ * The calendar an agent works to. `timezone:` in AGENTS.md, nearest-wins like
46
+ * every other key there; a flow's cron already means its own timezone, this
47
+ * makes "today" mean it too. Unset is UTC — what the pods run — which for a
48
+ * Sydney desk made an article dated today "one day in the future" until 10am.
49
+ * An unknown name falls back to UTC rather than failing every step.
50
+ */
51
+ export declare function resolveTimezone(front: Record<string, unknown>): string;
52
+ /** YYYY-MM-DD in a timezone — the date the workspace believes it is. */
53
+ export declare function localDate(timeZone: string, now?: Date): string;
54
+ /**
55
+ * The prose from AGENTS.md, outermost first.
56
+ *
57
+ * This was written by every scaffold, shown in the dashboard, described in the
58
+ * template as "context every agent here shares" — and never read. Only the
59
+ * frontmatter was, so the instructions people actually wrote reached no model.
60
+ */
61
+ export declare function sharedInstructions(agentDir: string, tenant: string): string | null;
62
+ /**
63
+ * Which of an agent's in-scope skills load for this run.
64
+ *
65
+ * Two independent gates: `skills:` in the agent's frontmatter is an allowlist
66
+ * (absent means everything in scope), and a skill's own `when:` names the run
67
+ * tags it is for (absent means every run).
68
+ *
69
+ * Note what an empty `tags` means — a skill with `when:` matches nothing, so
70
+ * an untagged run gets none of them. That is the intent, and it is also why
71
+ * failing to thread the run's tags this far made every `when:` skill
72
+ * permanently invisible instead of conditionally loaded.
73
+ */
74
+ export declare function applicableSkills<T extends {
75
+ name: string;
76
+ when: string[];
77
+ }>(skills: T[], only: string[], tags: string[]): T[];
78
+ /**
79
+ * [[name]] as a reference to a document or file — the Obsidian instinct,
80
+ * honoured where it is safe. A prompt is text the model acts on, and a
81
+ * model cannot open "[[sources-of-conveyancers]]"; it can open
82
+ * `../../knowledge/sources-of-conveyancers.md`. So links resolve to real
83
+ * agent-relative paths BEFORE the prompt is built, matching by filename or
84
+ * OKF title, hyphen/underscore/case-blind. Anything unmatched — agent
85
+ * names, flow links, prose in brackets — passes through untouched: this is
86
+ * sugar over paths, never a gate in front of them.
87
+ */
88
+ /**
89
+ * Whether an evaluator's reply actually carries its `until:` marker.
90
+ *
91
+ * Not a substring test. A reviewer that writes "APPROVED once the tribunal
92
+ * sentence is corrected" contains the word, and a substring match reads that
93
+ * conditional as a pass — the loop ends, the correction is never made, and the
94
+ * step after it inherits the problem the loop existed to catch. That happened:
95
+ * a factual error rode a conditional approval past the gate.
96
+ *
97
+ * So the marker has to stand alone on its own line, which is a thing a model
98
+ * does deliberately and cannot do by accident mid-sentence. Trailing
99
+ * punctuation is allowed ("APPROVED." is still a decision), and the line may
100
+ * sit anywhere in the reply, so an approval followed by notes still passes —
101
+ * the point is that the word is a switch, not a clause.
102
+ */
103
+ export declare function saysUntilMarker(result: string | null, until: string): boolean;
104
+ export declare function resolveDocLinks(text: string, workspaceRoot: string): string;
105
+ /**
106
+ * Copy a directory tree by reading and writing the bytes.
107
+ *
108
+ * Not fs.cpSync: that copies through the kernel's clone/copy_file_range
109
+ * path, which on a bind-mounted or network volume — exactly where a hosted
110
+ * install keeps its data — can report success and leave a zero-length file
111
+ * behind. Every archived run output was empty, and nothing failed to say
112
+ * so, which is the worst shape a bug can take. This works on every
113
+ * filesystem, and normalises the mode while it is here: what an agent
114
+ * produced belongs to the platform, not to the container umask that
115
+ * happened to create it.
116
+ */
117
+ export declare function copyTreeBytes(from: string, to: string): void;
118
+ /** How many times a busy provider is given another moment, and the longest
119
+ * any one wait may be. Three is the industry's habit and the point where
120
+ * waiting longer stops being kinder than failing. */
121
+ export declare const OVERLOAD_RETRIES = 3;
122
+ /**
123
+ * A refusal the SAME supply may answer in a moment — the provider is busy,
124
+ * not the account broken.
125
+ *
126
+ * The distinction is the whole point. 429 means "too many requests", and a
127
+ * provider says it for two unrelated reasons: the endpoint is momentarily
128
+ * saturated (wait, and it works), or the account is out of credit or over
129
+ * its quota (wait forever, it never works). Money words decide it: a 429
130
+ * that mentions credit, quota or billing is the account, and belongs to the
131
+ * fallback provider, not to a retry that can only fail again.
132
+ */
133
+ export declare function isTransientOverload(text: string): boolean;
134
+ export declare function backoffMs(attempt: number, text?: string, random?: () => number): number;
135
+ export declare function createFlowRun(tenant: string, workspace: string, steps: FlowStep[], flowName: string, status: "queued" | "running", tags?: string[]): RunRecord;
136
+ export declare function startFlowRun(tenant: string, workspace: string, steps: FlowStep[], flowName: string, modelOverride?: string | null, tags?: string[], effortOverride?: string | null): RunRecord;
137
+ /**
138
+ * Drive a run to completion: groups in order, approval gates, retries.
139
+ *
140
+ * Separate from starting one so a run can be picked up again. The loop reads
141
+ * every decision off the run record — `pending` steps are the work left, and
142
+ * a completed group's results are already on it — so re-entering it on a
143
+ * partly-finished record continues rather than restarts.
144
+ *
145
+ * `parkOnApproval` — a queue worker's slot is too expensive to spend polling
146
+ * a file for a person who may answer tomorrow. With it set, an approval gate
147
+ * saves the run as parked and returns; the approval API re-enqueues it and a
148
+ * worker re-enters this loop, which continues where the record says it
149
+ * stopped. Without it (the CLI, whose process belongs to the person waiting)
150
+ * the gate blocks in place exactly as before.
151
+ */
152
+ /**
153
+ * Turn a gate's `preview:` patterns into the files under storage/ that
154
+ * exist right now, relative to storage/. `*` matches within a segment,
155
+ * `**` across segments; a pattern with no wildcard is kept only if the file
156
+ * is there. Sorted, deduplicated, capped — a preview is a handful of files,
157
+ * not a directory dump.
158
+ */
159
+ export declare function resolvePreview(storageDir: string, patterns: string[], cap?: number): string[];
160
+ /** Store what a run has left in storage/ so far. Never fails the run: a
161
+ * store that is down costs the gate its thumbnail, not the run its step. */
162
+ /**
163
+ * Copy onto the in-memory run any gate decision that reached the record on
164
+ * disk while this driver was busy — status, stamps, note, the event line —
165
+ * so the driver's next save keeps it. Returns whether anything landed. Only
166
+ * steps this copy still shows as asking are touched: everything else on the
167
+ * record is this driver's own, and newer in memory than on disk.
168
+ */
169
+ export declare function adoptDecisions(run: RunRecord, disk: RunRecord | null): boolean;
170
+ /**
171
+ * The runs this process is driving right now. The one fact reconcile needs:
172
+ * a run in here is alive however quiet its step is, and a `running` run not
173
+ * in here has no driver — this is the only process that drives.
174
+ */
175
+ export declare const drivingRuns: Set<string>;
176
+ export declare function driveRun(tenant: string, workspace: string, run: RunRecord, modelOverride?: string | null, tags?: string[], opts?: {
177
+ parkOnApproval?: boolean;
178
+ effortOverride?: string | null;
179
+ }): Promise<void>;
180
+ export declare function loadFlow(tenant: string, workspace: string, flowName: string): import("./store.ts").FlowInfo | null;
181
+ export interface Reconciliation {
182
+ runId: string;
183
+ tenant: string;
184
+ workspace: string;
185
+ /** What was done about it: closed as dead, or picked back up. */
186
+ action: "closed" | "resumed";
187
+ /** Steps that were mid-flight when the process went away. */
188
+ interrupted: string[];
189
+ }
190
+ /**
191
+ * Close out runs abandoned by a process that is no longer here.
192
+ *
193
+ * Runs execute in the server process, and nothing writes a terminal status
194
+ * when that process goes away — so a deploy, a crash or a Ctrl-C during a run
195
+ * leaves `status: "running"` on disk forever. The run history then contains
196
+ * entries that are not merely stale but false: they claim to be in progress,
197
+ * the dashboard renders them as live, and no one can tell them apart from a
198
+ * step that is genuinely still thinking.
199
+ *
200
+ * Called at startup, before anything reads run history. A run still being
201
+ * worked on by a live process is protected by the idle window, not by a lock —
202
+ * so this is safe to call while runs are in flight, and deliberately
203
+ * conservative about what it declares dead.
204
+ *
205
+ * A run genuinely waiting for a person is left alone: that state legitimately
206
+ * outlives any process. A run whose person already answered is not waiting,
207
+ * and is picked back up — see below.
208
+ */
209
+ export declare function reconcileRuns(tenant: string, now?: number): Reconciliation[];
210
+ /**
211
+ * The same, for every account this installation holds.
212
+ *
213
+ * A server reconciles on boot, and it boots for everyone — reconciling only
214
+ * one hard-coded account left every other account's interrupted runs marked
215
+ * `running` forever, with no process left to finish them.
216
+ */
217
+ export declare function reconcileAllRuns(now?: number): Reconciliation[];
218
+ /**
219
+ * Wait for a run to stop being in progress.
220
+ *
221
+ * Runs start and return immediately, which is right for a schedule and wrong
222
+ * for a caller putting an agent behind their own request: they want the
223
+ * answer, not a receipt. Polls the run record rather than holding a callback,
224
+ * so it works from a different process than the one doing the work.
225
+ *
226
+ * `awaiting-approval` counts as stopping. It is not finished, but it is not
227
+ * going to progress without a person, and a caller blocked on it would hang
228
+ * for as long as the approval window allows.
229
+ */
230
+ export declare function waitForRun(tenant: string, workspace: string, runId: string, timeoutMs?: number): Promise<{
231
+ run: RunRecord | null;
232
+ timedOut: boolean;
233
+ }>;
234
+ /**
235
+ * What a run produced, for a caller that wanted an answer.
236
+ *
237
+ * The last step that actually returned something: a flow's final step is the
238
+ * conclusion, and skipping back past steps that were skipped or produced
239
+ * nothing is what makes `?wait=true` useful rather than merely blocking.
240
+ */
241
+ export declare function runResult(run: RunRecord): string | null;