@gr8ful/spf 0.1.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 +21 -0
- package/README.md +321 -0
- package/assets/defaults/spf.config.yaml +141 -0
- package/assets/prompts/builder/system.md +13 -0
- package/assets/prompts/builder/user.md +34 -0
- package/assets/prompts/documenter/system.md +17 -0
- package/assets/prompts/documenter/user.md +48 -0
- package/assets/prompts/planner/system.md +21 -0
- package/assets/prompts/planner/user.md +45 -0
- package/assets/prompts/reviewer/system.md +16 -0
- package/assets/prompts/reviewer/user.md +44 -0
- package/assets/prompts/scout/system.md +20 -0
- package/assets/prompts/scout/user.md +34 -0
- package/assets/skill/SKILL.md +80 -0
- package/assets/skill/cookbooks/authoring_chains.md +193 -0
- package/assets/skill/cookbooks/how_to_prompt_for_the_eng.md +109 -0
- package/assets/skill/cookbooks/roster.md +197 -0
- package/assets/skill/cookbooks/run_adw.md +92 -0
- package/assets/skill/cookbooks/spf_overview.md +111 -0
- package/assets/skill/references/config.md +188 -0
- package/assets/skill/references/handoff.md +162 -0
- package/assets/skill/references/observability.md +184 -0
- package/dist/chains/adw_build.d.ts +12 -0
- package/dist/chains/adw_build.js +27 -0
- package/dist/chains/adw_build_review.d.ts +21 -0
- package/dist/chains/adw_build_review.js +55 -0
- package/dist/chains/adw_build_test.d.ts +21 -0
- package/dist/chains/adw_build_test.js +67 -0
- package/dist/chains/adw_document.d.ts +23 -0
- package/dist/chains/adw_document.js +59 -0
- package/dist/chains/adw_plan.d.ts +12 -0
- package/dist/chains/adw_plan.js +27 -0
- package/dist/chains/adw_plan_build.d.ts +12 -0
- package/dist/chains/adw_plan_build.js +30 -0
- package/dist/chains/adw_plan_build_test.d.ts +16 -0
- package/dist/chains/adw_plan_build_test.js +65 -0
- package/dist/chains/adw_plan_build_test_quality.d.ts +18 -0
- package/dist/chains/adw_plan_build_test_quality.js +66 -0
- package/dist/chains/adw_prompt.d.ts +12 -0
- package/dist/chains/adw_prompt.js +25 -0
- package/dist/chains/adw_quality.d.ts +12 -0
- package/dist/chains/adw_quality.js +32 -0
- package/dist/chains/adw_scout.d.ts +12 -0
- package/dist/chains/adw_scout.js +27 -0
- package/dist/chains/adw_simple_sdlc.d.ts +43 -0
- package/dist/chains/adw_simple_sdlc.js +147 -0
- package/dist/chains/context.d.ts +19 -0
- package/dist/chains/context.js +1 -0
- package/dist/chains/index.d.ts +19 -0
- package/dist/chains/index.js +116 -0
- package/dist/cli/bin.d.ts +15 -0
- package/dist/cli/bin.js +24 -0
- package/dist/cli/commands/abort.d.ts +1 -0
- package/dist/cli/commands/abort.js +42 -0
- package/dist/cli/commands/doctor.d.ts +1 -0
- package/dist/cli/commands/doctor.js +165 -0
- package/dist/cli/commands/eject.d.ts +1 -0
- package/dist/cli/commands/eject.js +55 -0
- package/dist/cli/commands/events.d.ts +1 -0
- package/dist/cli/commands/events.js +49 -0
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.js +62 -0
- package/dist/cli/commands/install-skill.d.ts +1 -0
- package/dist/cli/commands/install-skill.js +122 -0
- package/dist/cli/commands/list.d.ts +1 -0
- package/dist/cli/commands/list.js +13 -0
- package/dist/cli/commands/migrate.d.ts +1 -0
- package/dist/cli/commands/migrate.js +167 -0
- package/dist/cli/commands/phases.d.ts +1 -0
- package/dist/cli/commands/phases.js +25 -0
- package/dist/cli/commands/run.d.ts +3 -0
- package/dist/cli/commands/run.js +27 -0
- package/dist/cli/commands/sessions.d.ts +1 -0
- package/dist/cli/commands/sessions.js +20 -0
- package/dist/cli/commands/trace.d.ts +8 -0
- package/dist/cli/commands/trace.js +10 -0
- package/dist/cli/commands/ui.d.ts +1 -0
- package/dist/cli/commands/ui.js +35 -0
- package/dist/cli/commands/version.d.ts +1 -0
- package/dist/cli/commands/version.js +8 -0
- package/dist/cli/commands/watch.d.ts +8 -0
- package/dist/cli/commands/watch.js +210 -0
- package/dist/cli/gitignore.d.ts +1 -0
- package/dist/cli/gitignore.js +14 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +156 -0
- package/dist/core/agent_cc.d.ts +75 -0
- package/dist/core/agent_cc.js +322 -0
- package/dist/core/agent_flue.d.ts +66 -0
- package/dist/core/agent_flue.js +321 -0
- package/dist/core/agents.d.ts +64 -0
- package/dist/core/agents.js +456 -0
- package/dist/core/changes.d.ts +35 -0
- package/dist/core/changes.js +98 -0
- package/dist/core/console.d.ts +36 -0
- package/dist/core/console.js +156 -0
- package/dist/core/data_types.d.ts +562 -0
- package/dist/core/data_types.js +382 -0
- package/dist/core/gates.d.ts +33 -0
- package/dist/core/gates.js +144 -0
- package/dist/core/git_helper.d.ts +59 -0
- package/dist/core/git_helper.js +115 -0
- package/dist/core/issues/github_provider.d.ts +52 -0
- package/dist/core/issues/github_provider.js +211 -0
- package/dist/core/issues/provider.d.ts +90 -0
- package/dist/core/issues/provider.js +14 -0
- package/dist/core/paths.d.ts +78 -0
- package/dist/core/paths.js +108 -0
- package/dist/core/permissions.d.ts +78 -0
- package/dist/core/permissions.js +187 -0
- package/dist/core/prompts.d.ts +4 -0
- package/dist/core/prompts.js +17 -0
- package/dist/core/quality.d.ts +65 -0
- package/dist/core/quality.js +194 -0
- package/dist/core/runner.d.ts +72 -0
- package/dist/core/runner.js +168 -0
- package/dist/core/session.d.ts +16 -0
- package/dist/core/session.js +60 -0
- package/dist/core/sqlite.d.ts +55 -0
- package/dist/core/sqlite.js +106 -0
- package/dist/core/tracer.d.ts +56 -0
- package/dist/core/tracer.js +246 -0
- package/dist/core/utils.d.ts +40 -0
- package/dist/core/utils.js +108 -0
- package/dist/core/watch.d.ts +44 -0
- package/dist/core/watch.js +194 -0
- package/dist/test/agent_cc.test.d.ts +1 -0
- package/dist/test/agent_cc.test.js +95 -0
- package/dist/test/agent_flue.test.d.ts +1 -0
- package/dist/test/agent_flue.test.js +83 -0
- package/dist/test/data_types.test.d.ts +10 -0
- package/dist/test/data_types.test.js +49 -0
- package/dist/test/ui_server.test.d.ts +1 -0
- package/dist/test/ui_server.test.js +119 -0
- package/dist/test/watch.test.d.ts +1 -0
- package/dist/test/watch.test.js +227 -0
- package/dist/ui/server/app.d.ts +3 -0
- package/dist/ui/server/app.js +98 -0
- package/dist/ui/server/db.d.ts +82 -0
- package/dist/ui/server/db.js +333 -0
- package/dist/ui/server/serve.d.ts +13 -0
- package/dist/ui/server/serve.js +80 -0
- package/dist/ui/server/static.d.ts +5 -0
- package/dist/ui/server/static.js +55 -0
- package/dist/ui/shared/types.d.ts +263 -0
- package/dist/ui/shared/types.js +8 -0
- package/package.json +52 -0
- package/web/assets/index-C7nF068F.css +1 -0
- package/web/assets/index-mzSArcnQ.js +11 -0
- package/web/assets/play-latin-400-normal-GKW-4YV7.woff2 +0 -0
- package/web/assets/play-latin-700-normal-DyPlLDbb.woff2 +0 -0
- package/web/index.html +14 -0
- package/web/logo.svg +6 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Concrete data types for the SPF ADW system.
|
|
3
|
+
*
|
|
4
|
+
* RULE (four-param rule): any function that takes more than 4 parameters takes
|
|
5
|
+
* ONE of these objects instead. AgentCall and PhaseParams are the pattern.
|
|
6
|
+
*
|
|
7
|
+
* Every agent call declares a concrete output type — an envelope built with
|
|
8
|
+
* envelopeType() — that its final JSON response is parsed against. No untyped
|
|
9
|
+
* handoffs. Validation is Valibot's job here (zod's/Python's pydantic
|
|
10
|
+
* equivalent) — chosen because Flue's own structured-output wiring is built
|
|
11
|
+
* on Valibot, so an envelope type doubles as the tool schema handed to it
|
|
12
|
+
* with no second definition.
|
|
13
|
+
*/
|
|
14
|
+
import * as v from "valibot";
|
|
15
|
+
export type PhaseKind = "engineer" | "agent" | "code";
|
|
16
|
+
export type PhaseStatus = "queued" | "running" | "success" | "fail";
|
|
17
|
+
/** Everything run.phase() needs. Passed as one object, never loose params. */
|
|
18
|
+
declare const PhaseParamsShape: v.ObjectSchema<{
|
|
19
|
+
readonly name: v.StringSchema<undefined>;
|
|
20
|
+
readonly kind: v.PicklistSchema<["engineer", "agent", "code"], undefined>;
|
|
21
|
+
readonly owner: v.StringSchema<undefined>;
|
|
22
|
+
readonly description: v.StringSchema<undefined>;
|
|
23
|
+
readonly retries: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>]>, 0>;
|
|
24
|
+
}, undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* A phase name identifies; a description explains. Both are required.
|
|
27
|
+
*
|
|
28
|
+
* The description is the only sentence the trace, the console, and the
|
|
29
|
+
* phase block in the UI ever show about intent — everything else is ids,
|
|
30
|
+
* statuses, and timings. `commit_plan: "Commit the plan"` tells a reader
|
|
31
|
+
* nothing they could not already see, so an echo is rejected the same way
|
|
32
|
+
* a blank one is. This is a construction-time error on purpose: it fires
|
|
33
|
+
* before the phase opens, not after a run is already in the trace.
|
|
34
|
+
*/
|
|
35
|
+
export declare const PhaseParamsSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
|
|
36
|
+
readonly name: v.StringSchema<undefined>;
|
|
37
|
+
readonly kind: v.PicklistSchema<["engineer", "agent", "code"], undefined>;
|
|
38
|
+
readonly owner: v.StringSchema<undefined>;
|
|
39
|
+
readonly description: v.StringSchema<undefined>;
|
|
40
|
+
readonly retries: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>]>, 0>;
|
|
41
|
+
}, undefined>, v.RawTransformAction<{
|
|
42
|
+
name: string;
|
|
43
|
+
kind: "agent" | "code" | "engineer";
|
|
44
|
+
owner: string;
|
|
45
|
+
description: string;
|
|
46
|
+
retries: number;
|
|
47
|
+
}, {
|
|
48
|
+
name: string;
|
|
49
|
+
kind: "agent" | "code" | "engineer";
|
|
50
|
+
owner: string;
|
|
51
|
+
retries: number;
|
|
52
|
+
description: string;
|
|
53
|
+
}>]>;
|
|
54
|
+
export type PhaseParams = v.InferOutput<typeof PhaseParamsSchema>;
|
|
55
|
+
export declare function makePhaseParams(input: v.InferInput<typeof PhaseParamsShape>): PhaseParams;
|
|
56
|
+
/** The persisted phase record — PhaseParams plus lifecycle. */
|
|
57
|
+
export interface Phase {
|
|
58
|
+
phase_id: string;
|
|
59
|
+
adw_id: string;
|
|
60
|
+
seq: number;
|
|
61
|
+
params: PhaseParams;
|
|
62
|
+
status: PhaseStatus;
|
|
63
|
+
attempt: number;
|
|
64
|
+
error?: string | null;
|
|
65
|
+
started_at?: string | null;
|
|
66
|
+
ended_at?: string | null;
|
|
67
|
+
}
|
|
68
|
+
export declare const EnvelopeBaseSchema: v.ObjectSchema<{
|
|
69
|
+
status: v.PicklistSchema<["success", "fail"], undefined>;
|
|
70
|
+
summary: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
71
|
+
artifacts: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => never[]>;
|
|
72
|
+
notes_for_next_agent: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
73
|
+
}, undefined>;
|
|
74
|
+
export type EnvelopeBase = v.InferOutput<typeof EnvelopeBaseSchema>;
|
|
75
|
+
export interface EnvelopeType<T> {
|
|
76
|
+
name: string;
|
|
77
|
+
schema: v.GenericSchema<Record<string, unknown>, T>;
|
|
78
|
+
fields: string[];
|
|
79
|
+
}
|
|
80
|
+
export declare const GenericOutput: EnvelopeType<{
|
|
81
|
+
status: "fail" | "success";
|
|
82
|
+
summary: string;
|
|
83
|
+
artifacts: string[];
|
|
84
|
+
notes_for_next_agent: string;
|
|
85
|
+
}>;
|
|
86
|
+
export type GenericOutputT = v.InferOutput<typeof GenericOutput.schema>;
|
|
87
|
+
export declare const PlanOutput: EnvelopeType<{
|
|
88
|
+
status: "fail" | "success";
|
|
89
|
+
summary: string;
|
|
90
|
+
artifacts: string[];
|
|
91
|
+
notes_for_next_agent: string;
|
|
92
|
+
commit_message: string;
|
|
93
|
+
}>;
|
|
94
|
+
export type PlanOutputT = v.InferOutput<typeof PlanOutput.schema>;
|
|
95
|
+
export declare const BuildOutput: EnvelopeType<{
|
|
96
|
+
status: "fail" | "success";
|
|
97
|
+
summary: string;
|
|
98
|
+
artifacts: string[];
|
|
99
|
+
notes_for_next_agent: string;
|
|
100
|
+
changed_files: string[];
|
|
101
|
+
commit_message: string;
|
|
102
|
+
}>;
|
|
103
|
+
export type BuildOutputT = v.InferOutput<typeof BuildOutput.schema>;
|
|
104
|
+
export declare const ScoutFindingSchema: v.ObjectSchema<{
|
|
105
|
+
readonly file: v.StringSchema<undefined>;
|
|
106
|
+
readonly note: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
107
|
+
}, undefined>;
|
|
108
|
+
export type ScoutFinding = v.InferOutput<typeof ScoutFindingSchema>;
|
|
109
|
+
export declare const ScoutOutput: EnvelopeType<{
|
|
110
|
+
status: "fail" | "success";
|
|
111
|
+
summary: string;
|
|
112
|
+
artifacts: string[];
|
|
113
|
+
notes_for_next_agent: string;
|
|
114
|
+
findings: {
|
|
115
|
+
file: string;
|
|
116
|
+
note: string;
|
|
117
|
+
}[];
|
|
118
|
+
}>;
|
|
119
|
+
export type ScoutOutputT = v.InferOutput<typeof ScoutOutput.schema>;
|
|
120
|
+
/** One thing the request (or plan) asked for, and whether it is there. */
|
|
121
|
+
export declare const ReviewFindingSchema: v.ObjectSchema<{
|
|
122
|
+
readonly requirement: v.StringSchema<undefined>;
|
|
123
|
+
readonly met: v.BooleanSchema<undefined>;
|
|
124
|
+
readonly evidence: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
125
|
+
}, undefined>;
|
|
126
|
+
export type ReviewFinding = v.InferOutput<typeof ReviewFindingSchema>;
|
|
127
|
+
/** Confirmation that what was built is what was asked for — not a test run. */
|
|
128
|
+
export declare const ReviewOutput: EnvelopeType<{
|
|
129
|
+
status: "fail" | "success";
|
|
130
|
+
summary: string;
|
|
131
|
+
artifacts: string[];
|
|
132
|
+
notes_for_next_agent: string;
|
|
133
|
+
approved: boolean;
|
|
134
|
+
findings: {
|
|
135
|
+
requirement: string;
|
|
136
|
+
met: boolean;
|
|
137
|
+
evidence: string;
|
|
138
|
+
}[];
|
|
139
|
+
blocking: string[];
|
|
140
|
+
}>;
|
|
141
|
+
export type ReviewOutputT = v.InferOutput<typeof ReviewOutput.schema>;
|
|
142
|
+
/** Where the write-up of a completed change landed. */
|
|
143
|
+
export declare const DocumentOutput: EnvelopeType<{
|
|
144
|
+
status: "fail" | "success";
|
|
145
|
+
summary: string;
|
|
146
|
+
artifacts: string[];
|
|
147
|
+
notes_for_next_agent: string;
|
|
148
|
+
document_path: string;
|
|
149
|
+
documented_files: string[];
|
|
150
|
+
commit_message: string;
|
|
151
|
+
}>;
|
|
152
|
+
export type DocumentOutputT = v.InferOutput<typeof DocumentOutput.schema>;
|
|
153
|
+
export declare const QualityAreaSchema: v.PicklistSchema<["frontend", "backend"], undefined>;
|
|
154
|
+
export type QualityArea = v.InferOutput<typeof QualityAreaSchema>;
|
|
155
|
+
export declare const QualityOperationSchema: v.PicklistSchema<["lint", "typecheck", "build"], undefined>;
|
|
156
|
+
export type QualityOperation = v.InferOutput<typeof QualityOperationSchema>;
|
|
157
|
+
/** One deterministic quality command, as configured in spf.config.yaml's `quality.checks`. */
|
|
158
|
+
export declare const QualityCheckSpecSchema: v.ObjectSchema<{
|
|
159
|
+
readonly name: v.StringSchema<undefined>;
|
|
160
|
+
readonly area: v.OptionalSchema<v.PicklistSchema<["frontend", "backend"], undefined>, "backend">;
|
|
161
|
+
readonly operation: v.PicklistSchema<["lint", "typecheck", "build"], undefined>;
|
|
162
|
+
readonly argv: v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.MinLengthAction<string[], 1, "argv must name at least the binary to run">]>;
|
|
163
|
+
readonly timeout_seconds: v.OptionalSchema<v.NumberSchema<undefined>, 120>;
|
|
164
|
+
}, undefined>;
|
|
165
|
+
export type QualityCheckSpec = v.InferOutput<typeof QualityCheckSpecSchema>;
|
|
166
|
+
/**
|
|
167
|
+
* `quality.checks` names the deterministic commands; `quality.suites` groups
|
|
168
|
+
* them into what a chain actually runs (`test`, `all`, ...). An unconfigured
|
|
169
|
+
* suite is a hard error at validate() time — see agents.validate() — not a
|
|
170
|
+
* silent placeholder that reports green. There is deliberately no packaged
|
|
171
|
+
* default suite: "no quality commands configured yet" must fail loudly on
|
|
172
|
+
* the first quality-gated chain, not quietly pass one.
|
|
173
|
+
*/
|
|
174
|
+
export declare const QualityConfigSchema: v.ObjectSchema<{
|
|
175
|
+
readonly checks: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
176
|
+
readonly name: v.StringSchema<undefined>;
|
|
177
|
+
readonly area: v.OptionalSchema<v.PicklistSchema<["frontend", "backend"], undefined>, "backend">;
|
|
178
|
+
readonly operation: v.PicklistSchema<["lint", "typecheck", "build"], undefined>;
|
|
179
|
+
readonly argv: v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.MinLengthAction<string[], 1, "argv must name at least the binary to run">]>;
|
|
180
|
+
readonly timeout_seconds: v.OptionalSchema<v.NumberSchema<undefined>, 120>;
|
|
181
|
+
}, undefined>, undefined>, () => never[]>;
|
|
182
|
+
readonly suites: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, () => {}>;
|
|
183
|
+
}, undefined>;
|
|
184
|
+
export type QualityConfig = v.InferOutput<typeof QualityConfigSchema>;
|
|
185
|
+
/** Captured evidence from one quality command. */
|
|
186
|
+
export interface QualityCheckResult {
|
|
187
|
+
name: string;
|
|
188
|
+
area: QualityArea;
|
|
189
|
+
operation: QualityOperation;
|
|
190
|
+
command: string;
|
|
191
|
+
returncode: number;
|
|
192
|
+
passed: boolean;
|
|
193
|
+
duration_seconds: number;
|
|
194
|
+
output_artifact: string;
|
|
195
|
+
output_tail: string;
|
|
196
|
+
}
|
|
197
|
+
/** Aggregate result from a quality block: every check it ran, and the verdict. */
|
|
198
|
+
export interface QualityResult {
|
|
199
|
+
passed: boolean;
|
|
200
|
+
checks: QualityCheckResult[];
|
|
201
|
+
failures: string[];
|
|
202
|
+
artifacts: string[];
|
|
203
|
+
}
|
|
204
|
+
/** Everything changes.capture() needs. One object, never loose params. */
|
|
205
|
+
export interface ChangeCapture {
|
|
206
|
+
base: string;
|
|
207
|
+
max_diff_lines: number;
|
|
208
|
+
include_untracked: boolean;
|
|
209
|
+
}
|
|
210
|
+
export declare function makeChangeCapture(input: Partial<ChangeCapture> & {
|
|
211
|
+
base?: string;
|
|
212
|
+
}): ChangeCapture;
|
|
213
|
+
/**
|
|
214
|
+
* The commit a change is measured from, and why that one.
|
|
215
|
+
*
|
|
216
|
+
* `reason` is the line the trace shows. A diff is only as trustworthy as the
|
|
217
|
+
* thing it was taken against, so the ADW records that choice instead of
|
|
218
|
+
* leaving the reader to infer it.
|
|
219
|
+
*/
|
|
220
|
+
export declare class BaseRef {
|
|
221
|
+
ref: string;
|
|
222
|
+
commit: string;
|
|
223
|
+
reason: string;
|
|
224
|
+
constructor(ref: string, commit: string, reason?: string);
|
|
225
|
+
/** Display form — a named ref as itself, a pinned raw sha shortened. */
|
|
226
|
+
get label(): string;
|
|
227
|
+
}
|
|
228
|
+
/** What changed since the base commit — pure git facts, no judgement. */
|
|
229
|
+
export declare class ChangeSet {
|
|
230
|
+
base: BaseRef;
|
|
231
|
+
files: string[];
|
|
232
|
+
untracked: string[];
|
|
233
|
+
insertions: number;
|
|
234
|
+
deletions: number;
|
|
235
|
+
stat: string;
|
|
236
|
+
diff_path: string;
|
|
237
|
+
truncated: boolean;
|
|
238
|
+
constructor(base: BaseRef, files?: string[], untracked?: string[], insertions?: number, deletions?: number, stat?: string, diff_path?: string, // the full diff, written into context_handoff/
|
|
239
|
+
truncated?: boolean);
|
|
240
|
+
get empty(): boolean;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* A ChangeSet shaped as an envelope so an agent can be handed it directly.
|
|
244
|
+
*
|
|
245
|
+
* Same adapter idea as VerifyOutput: code computes the diff, the documenter
|
|
246
|
+
* consumes it through the one door every agent handoff uses.
|
|
247
|
+
*/
|
|
248
|
+
export declare const ChangesOutput: EnvelopeType<{
|
|
249
|
+
status: "fail" | "success";
|
|
250
|
+
summary: string;
|
|
251
|
+
artifacts: string[];
|
|
252
|
+
notes_for_next_agent: string;
|
|
253
|
+
base: string;
|
|
254
|
+
changed_files: string[];
|
|
255
|
+
insertions: number;
|
|
256
|
+
deletions: number;
|
|
257
|
+
stat: string;
|
|
258
|
+
diff_path: string;
|
|
259
|
+
}>;
|
|
260
|
+
export type ChangesOutputT = v.InferOutput<typeof ChangesOutput.schema>;
|
|
261
|
+
/**
|
|
262
|
+
* A deterministic result, shaped as an envelope so an agent can consume it.
|
|
263
|
+
*
|
|
264
|
+
* Agents hand each other typed envelopes; code blocks return QualityResult.
|
|
265
|
+
* This is the adapter, so a failing lint or test run flows back into the
|
|
266
|
+
* builder through exactly the same door a tester agent's report used to —
|
|
267
|
+
* the ADW script is the only thing that knows the difference.
|
|
268
|
+
*/
|
|
269
|
+
export declare const VerifyOutput: EnvelopeType<{
|
|
270
|
+
status: "fail" | "success";
|
|
271
|
+
summary: string;
|
|
272
|
+
artifacts: string[];
|
|
273
|
+
notes_for_next_agent: string;
|
|
274
|
+
passed: boolean;
|
|
275
|
+
failures: string[];
|
|
276
|
+
}>;
|
|
277
|
+
export type VerifyOutputT = v.InferOutput<typeof VerifyOutput.schema>;
|
|
278
|
+
/**
|
|
279
|
+
* One thing a gate looked at, and what it found.
|
|
280
|
+
*
|
|
281
|
+
* `note` is the evidence — "exists, 2.1KB", "exit 0", "not in the diff". On a
|
|
282
|
+
* failed check it doubles as the reason, so it is what the agent is told.
|
|
283
|
+
*/
|
|
284
|
+
export interface GateCheck {
|
|
285
|
+
item: string;
|
|
286
|
+
ok: boolean;
|
|
287
|
+
note: string;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* What every gate returns: the checks it ran. Violations are derived.
|
|
291
|
+
*
|
|
292
|
+
* Authoring stays a one-liner per item — `report.check(...)` appends and
|
|
293
|
+
* returns self, so a gate is a loop and a return.
|
|
294
|
+
*/
|
|
295
|
+
export declare class GateReport {
|
|
296
|
+
checks: GateCheck[];
|
|
297
|
+
check(item: string, ok: boolean, note?: string): GateReport;
|
|
298
|
+
get violations(): string[];
|
|
299
|
+
get passed(): boolean;
|
|
300
|
+
}
|
|
301
|
+
/** The minimal shape a gate needs from a run — avoids a circular import with runner.ts. */
|
|
302
|
+
export interface RunContext {
|
|
303
|
+
repo_root: string;
|
|
304
|
+
}
|
|
305
|
+
export type GateFn = (envelope: EnvelopeBase, run: RunContext) => GateReport | string[];
|
|
306
|
+
/** One agent invocation: prompt in, typed envelope out, gates verified. */
|
|
307
|
+
export interface AgentCall<T extends EnvelopeBase = EnvelopeBase> {
|
|
308
|
+
output_type: EnvelopeType<T>;
|
|
309
|
+
prompt: string;
|
|
310
|
+
previous?: EnvelopeBase | null;
|
|
311
|
+
gates?: GateFn[];
|
|
312
|
+
}
|
|
313
|
+
export declare function makeAgentCall<T extends EnvelopeBase>(input: {
|
|
314
|
+
output_type: EnvelopeType<T>;
|
|
315
|
+
prompt: string;
|
|
316
|
+
previous?: EnvelopeBase | null;
|
|
317
|
+
gates?: GateFn[];
|
|
318
|
+
}): AgentCall<T>;
|
|
319
|
+
export declare const PromptEngineeringSchema: v.ObjectSchema<{
|
|
320
|
+
readonly system: v.StringSchema<undefined>;
|
|
321
|
+
readonly user: v.StringSchema<undefined>;
|
|
322
|
+
}, undefined>;
|
|
323
|
+
export type PromptEngineering = v.InferOutput<typeof PromptEngineeringSchema>;
|
|
324
|
+
export declare const ThinkingLevelSchema: v.PicklistSchema<["off", "minimal", "low", "medium", "high", "xhigh", "max"], undefined>;
|
|
325
|
+
export type ThinkingLevel = v.InferOutput<typeof ThinkingLevelSchema>;
|
|
326
|
+
export declare const AgentConfigSchema: v.ObjectSchema<{
|
|
327
|
+
readonly name: v.StringSchema<undefined>;
|
|
328
|
+
readonly coding_agent: v.OptionalSchema<v.PicklistSchema<["flue", "claude_code"], undefined>, "flue">;
|
|
329
|
+
readonly model: v.OptionalSchema<v.StringSchema<undefined>, "google/gemini-3.6-flash">;
|
|
330
|
+
readonly thinking: v.OptionalSchema<v.PicklistSchema<["off", "minimal", "low", "medium", "high", "xhigh", "max"], undefined>, "medium">;
|
|
331
|
+
readonly color: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
332
|
+
readonly purpose: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
333
|
+
readonly prompt_engineering: v.ObjectSchema<{
|
|
334
|
+
readonly system: v.StringSchema<undefined>;
|
|
335
|
+
readonly user: v.StringSchema<undefined>;
|
|
336
|
+
}, undefined>;
|
|
337
|
+
readonly harness_engineering: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => never[]>;
|
|
338
|
+
readonly tools: v.OptionalSchema<v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, undefined>;
|
|
339
|
+
readonly writes: v.OptionalSchema<v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, undefined>;
|
|
340
|
+
}, undefined>;
|
|
341
|
+
export type AgentConfig = v.InferOutput<typeof AgentConfigSchema>;
|
|
342
|
+
export declare const ConfigDefaultsSchema: v.ObjectSchema<{
|
|
343
|
+
readonly coding_agent: v.OptionalSchema<v.PicklistSchema<["flue", "claude_code"], undefined>, "flue">;
|
|
344
|
+
readonly model: v.OptionalSchema<v.StringSchema<undefined>, "google/gemini-3.6-flash">;
|
|
345
|
+
readonly thinking: v.OptionalSchema<v.PicklistSchema<["off", "minimal", "low", "medium", "high", "xhigh", "max"], undefined>, "medium">;
|
|
346
|
+
readonly color: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
347
|
+
readonly harness_engineering: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => never[]>;
|
|
348
|
+
readonly tools: v.OptionalSchema<v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, undefined>;
|
|
349
|
+
readonly protected_files: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => string[]>;
|
|
350
|
+
readonly data_dir: v.OptionalSchema<v.StringSchema<undefined>, ".spf/data">;
|
|
351
|
+
}, undefined>;
|
|
352
|
+
export type ConfigDefaults = v.InferOutput<typeof ConfigDefaultsSchema>;
|
|
353
|
+
export declare const ObservabilityConfigSchema: v.ObjectSchema<{
|
|
354
|
+
readonly db: v.OptionalSchema<v.StringSchema<undefined>, ".spf/data/spf.db">;
|
|
355
|
+
readonly poll_ms: v.OptionalSchema<v.NumberSchema<undefined>, 500>;
|
|
356
|
+
}, undefined>;
|
|
357
|
+
export type ObservabilityConfig = v.InferOutput<typeof ObservabilityConfigSchema>;
|
|
358
|
+
/**
|
|
359
|
+
* `spf watch`'s configuration. `provider` is a small enum today (just
|
|
360
|
+
* `"github"`) by design — adding Jira/Linear later is a new provider
|
|
361
|
+
* module (`core/issues/*_provider.ts`) implementing `IssueProvider` plus
|
|
362
|
+
* one more enum entry here, not a rewrite of the poll loop.
|
|
363
|
+
*
|
|
364
|
+
* `repo` has no sensible default and is validated as required at `spf
|
|
365
|
+
* watch` startup, not here — an empty string parses fine (this schema has
|
|
366
|
+
* no opinion on whether watch is even configured), matching the same
|
|
367
|
+
* "fails loudly before anything spawns, not eagerly at parse time" pattern
|
|
368
|
+
* `quality:` already uses.
|
|
369
|
+
*/
|
|
370
|
+
export declare const WatchProviderSchema: v.PicklistSchema<["github"], undefined>;
|
|
371
|
+
export type WatchProvider = v.InferOutput<typeof WatchProviderSchema>;
|
|
372
|
+
export declare const WatchConfigSchema: v.ObjectSchema<{
|
|
373
|
+
readonly provider: v.OptionalSchema<v.PicklistSchema<["github"], undefined>, "github">;
|
|
374
|
+
readonly repo: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
375
|
+
readonly label_prefix: v.OptionalSchema<v.StringSchema<undefined>, "spf">;
|
|
376
|
+
readonly chain: v.OptionalSchema<v.StringSchema<undefined>, "plan-build-test">;
|
|
377
|
+
readonly base_branch: v.OptionalSchema<v.StringSchema<undefined>, "main">;
|
|
378
|
+
readonly poll_ms: v.OptionalSchema<v.NumberSchema<undefined>, 60000>;
|
|
379
|
+
readonly concurrency: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, 2>;
|
|
380
|
+
}, undefined>;
|
|
381
|
+
export type WatchConfig = v.InferOutput<typeof WatchConfigSchema>;
|
|
382
|
+
export declare const SFConfigSchema: v.ObjectSchema<{
|
|
383
|
+
readonly defaults: v.OptionalSchema<v.ObjectSchema<{
|
|
384
|
+
readonly coding_agent: v.OptionalSchema<v.PicklistSchema<["flue", "claude_code"], undefined>, "flue">;
|
|
385
|
+
readonly model: v.OptionalSchema<v.StringSchema<undefined>, "google/gemini-3.6-flash">;
|
|
386
|
+
readonly thinking: v.OptionalSchema<v.PicklistSchema<["off", "minimal", "low", "medium", "high", "xhigh", "max"], undefined>, "medium">;
|
|
387
|
+
readonly color: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
388
|
+
readonly harness_engineering: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => never[]>;
|
|
389
|
+
readonly tools: v.OptionalSchema<v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, undefined>;
|
|
390
|
+
readonly protected_files: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => string[]>;
|
|
391
|
+
readonly data_dir: v.OptionalSchema<v.StringSchema<undefined>, ".spf/data">;
|
|
392
|
+
}, undefined>, () => {
|
|
393
|
+
coding_agent: "claude_code" | "flue";
|
|
394
|
+
model: string;
|
|
395
|
+
thinking: "high" | "low" | "max" | "medium" | "minimal" | "off" | "xhigh";
|
|
396
|
+
color: string;
|
|
397
|
+
harness_engineering: string[];
|
|
398
|
+
tools?: string[] | null | undefined;
|
|
399
|
+
protected_files: string[];
|
|
400
|
+
data_dir: string;
|
|
401
|
+
}>;
|
|
402
|
+
readonly observability: v.OptionalSchema<v.ObjectSchema<{
|
|
403
|
+
readonly db: v.OptionalSchema<v.StringSchema<undefined>, ".spf/data/spf.db">;
|
|
404
|
+
readonly poll_ms: v.OptionalSchema<v.NumberSchema<undefined>, 500>;
|
|
405
|
+
}, undefined>, () => {
|
|
406
|
+
db: string;
|
|
407
|
+
poll_ms: number;
|
|
408
|
+
}>;
|
|
409
|
+
readonly agents: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
410
|
+
readonly name: v.StringSchema<undefined>;
|
|
411
|
+
readonly coding_agent: v.OptionalSchema<v.PicklistSchema<["flue", "claude_code"], undefined>, "flue">;
|
|
412
|
+
readonly model: v.OptionalSchema<v.StringSchema<undefined>, "google/gemini-3.6-flash">;
|
|
413
|
+
readonly thinking: v.OptionalSchema<v.PicklistSchema<["off", "minimal", "low", "medium", "high", "xhigh", "max"], undefined>, "medium">;
|
|
414
|
+
readonly color: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
415
|
+
readonly purpose: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
416
|
+
readonly prompt_engineering: v.ObjectSchema<{
|
|
417
|
+
readonly system: v.StringSchema<undefined>;
|
|
418
|
+
readonly user: v.StringSchema<undefined>;
|
|
419
|
+
}, undefined>;
|
|
420
|
+
readonly harness_engineering: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, () => never[]>;
|
|
421
|
+
readonly tools: v.OptionalSchema<v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, undefined>;
|
|
422
|
+
readonly writes: v.OptionalSchema<v.NullableSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, undefined>;
|
|
423
|
+
}, undefined>, undefined>, () => never[]>;
|
|
424
|
+
readonly quality: v.OptionalSchema<v.ObjectSchema<{
|
|
425
|
+
readonly checks: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
|
|
426
|
+
readonly name: v.StringSchema<undefined>;
|
|
427
|
+
readonly area: v.OptionalSchema<v.PicklistSchema<["frontend", "backend"], undefined>, "backend">;
|
|
428
|
+
readonly operation: v.PicklistSchema<["lint", "typecheck", "build"], undefined>;
|
|
429
|
+
readonly argv: v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.MinLengthAction<string[], 1, "argv must name at least the binary to run">]>;
|
|
430
|
+
readonly timeout_seconds: v.OptionalSchema<v.NumberSchema<undefined>, 120>;
|
|
431
|
+
}, undefined>, undefined>, () => never[]>;
|
|
432
|
+
readonly suites: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>, () => {}>;
|
|
433
|
+
}, undefined>, () => {
|
|
434
|
+
checks: {
|
|
435
|
+
name: string;
|
|
436
|
+
area: "backend" | "frontend";
|
|
437
|
+
operation: "build" | "lint" | "typecheck";
|
|
438
|
+
argv: string[];
|
|
439
|
+
timeout_seconds: number;
|
|
440
|
+
}[];
|
|
441
|
+
suites: {
|
|
442
|
+
[x: string]: string[];
|
|
443
|
+
};
|
|
444
|
+
}>;
|
|
445
|
+
readonly watch: v.OptionalSchema<v.ObjectSchema<{
|
|
446
|
+
readonly provider: v.OptionalSchema<v.PicklistSchema<["github"], undefined>, "github">;
|
|
447
|
+
readonly repo: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
448
|
+
readonly label_prefix: v.OptionalSchema<v.StringSchema<undefined>, "spf">;
|
|
449
|
+
readonly chain: v.OptionalSchema<v.StringSchema<undefined>, "plan-build-test">;
|
|
450
|
+
readonly base_branch: v.OptionalSchema<v.StringSchema<undefined>, "main">;
|
|
451
|
+
readonly poll_ms: v.OptionalSchema<v.NumberSchema<undefined>, 60000>;
|
|
452
|
+
readonly concurrency: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1, undefined>]>, 2>;
|
|
453
|
+
}, undefined>, () => {
|
|
454
|
+
provider: "github";
|
|
455
|
+
repo: string;
|
|
456
|
+
label_prefix: string;
|
|
457
|
+
chain: string;
|
|
458
|
+
base_branch: string;
|
|
459
|
+
poll_ms: number;
|
|
460
|
+
concurrency: number;
|
|
461
|
+
}>;
|
|
462
|
+
}, undefined>;
|
|
463
|
+
export type SFConfig = v.InferOutput<typeof SFConfigSchema>;
|
|
464
|
+
/** One traced event, always logged against adw_id + phase. */
|
|
465
|
+
export interface EventRecord {
|
|
466
|
+
adw_id: string;
|
|
467
|
+
phase_id: string;
|
|
468
|
+
type: string;
|
|
469
|
+
name: string;
|
|
470
|
+
payload: Record<string, unknown>;
|
|
471
|
+
parent_id: string;
|
|
472
|
+
tokens?: number | null;
|
|
473
|
+
started_at?: string | null;
|
|
474
|
+
ended_at?: string | null;
|
|
475
|
+
}
|
|
476
|
+
export declare function makeEventRecord(input: Partial<EventRecord> & {
|
|
477
|
+
adw_id: string;
|
|
478
|
+
type: string;
|
|
479
|
+
}): EventRecord;
|
|
480
|
+
/**
|
|
481
|
+
* Everything one coding-agent dispatch+read turn needs, whichever backend
|
|
482
|
+
* (`coding_agent:` in config) actually runs it — Flue today, others later.
|
|
483
|
+
* Each backend module (`agent_flue.ts`, ...) is free to ignore fields it has
|
|
484
|
+
* no use for (a subprocess-based backend has no use for `flue_db_path`) and
|
|
485
|
+
* to interpret `model` in its own vocabulary (Flue: `provider/model-id`;
|
|
486
|
+
* others may take a bare alias) — `agents.validate()` already branches its
|
|
487
|
+
* model-shape check on `coding_agent` for exactly this reason.
|
|
488
|
+
*
|
|
489
|
+
* No `session_dir`/`raw_output_path` (Flue's own persistence is the durable
|
|
490
|
+
* record for Flue; a subprocess backend owns its own equivalent) and no
|
|
491
|
+
* `extensions` (harness_engineering has no analogue on any current backend —
|
|
492
|
+
* see agents.validate()). `output_schema`/`output_type_name` is the one
|
|
493
|
+
* contract every backend must honor somehow — Flue via an injected
|
|
494
|
+
* `sf_report` tool, a CLI-shaped backend via its own structured-output flag —
|
|
495
|
+
* so a Valibot envelope type becomes that backend's schema-validated output
|
|
496
|
+
* with no second definition anywhere.
|
|
497
|
+
*/
|
|
498
|
+
export interface AgentRequest {
|
|
499
|
+
prompt: string;
|
|
500
|
+
system_prompt: string;
|
|
501
|
+
model: string;
|
|
502
|
+
thinking: ThinkingLevel;
|
|
503
|
+
session_id: string;
|
|
504
|
+
resume: boolean;
|
|
505
|
+
tools?: string[] | null;
|
|
506
|
+
output_schema: v.GenericSchema<Record<string, unknown>, unknown>;
|
|
507
|
+
output_type_name: string;
|
|
508
|
+
cwd: string;
|
|
509
|
+
flue_db_path: string;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Tokens and the dollars they cost, per component, summed over a call.
|
|
513
|
+
*
|
|
514
|
+
* Mirrors pi's `usage` shape one-for-one so the numbers reconcile with what
|
|
515
|
+
* pi itself reports: `input` EXCLUDES cache reads, which bill at their own
|
|
516
|
+
* (cheaper) rate — add them to learn the size of the prompt that was sent.
|
|
517
|
+
*/
|
|
518
|
+
export declare class UsageBreakdown {
|
|
519
|
+
input_tokens: number;
|
|
520
|
+
output_tokens: number;
|
|
521
|
+
cache_read_tokens: number;
|
|
522
|
+
cache_write_tokens: number;
|
|
523
|
+
reasoning_tokens: number;
|
|
524
|
+
total_tokens: number;
|
|
525
|
+
input_cost: number;
|
|
526
|
+
output_cost: number;
|
|
527
|
+
cache_read_cost: number;
|
|
528
|
+
cache_write_cost: number;
|
|
529
|
+
total_cost: number;
|
|
530
|
+
/**
|
|
531
|
+
* Fold in one pi `message_end` usage object.
|
|
532
|
+
*
|
|
533
|
+
* `totalTokens` is passed in rather than re-derived: the caller already
|
|
534
|
+
* computes it pi's way (totalTokens, else the sum of the parts).
|
|
535
|
+
*/
|
|
536
|
+
add_turn(usage: Record<string, any>, totalTokens: number): void;
|
|
537
|
+
/** Add another call's usage — a phase that retries spends more than once. */
|
|
538
|
+
merge(other: UsageBreakdown): void;
|
|
539
|
+
toJSON(): Record<string, number>;
|
|
540
|
+
}
|
|
541
|
+
export interface AgentResult {
|
|
542
|
+
text: string;
|
|
543
|
+
/**
|
|
544
|
+
* The validated structured output, however this backend produced it —
|
|
545
|
+
* Flue's injected `sf_report` tool call, or another backend's own
|
|
546
|
+
* schema-validated result field. Present whenever the backend captured
|
|
547
|
+
* one, regardless of whether it also produced JSON in `text`. `null`
|
|
548
|
+
* means it never validated, so the caller falls back to extracting JSON
|
|
549
|
+
* from `text` directly.
|
|
550
|
+
*/
|
|
551
|
+
report: unknown | null;
|
|
552
|
+
session_id: string;
|
|
553
|
+
tokens: number;
|
|
554
|
+
cost: number;
|
|
555
|
+
usage: UsageBreakdown;
|
|
556
|
+
context_tokens: number;
|
|
557
|
+
context_window: number;
|
|
558
|
+
}
|
|
559
|
+
export declare function makeAgentResult(input: Partial<AgentResult> & {
|
|
560
|
+
session_id: string;
|
|
561
|
+
}): AgentResult;
|
|
562
|
+
export {};
|