@gr8ful/spf 0.1.6 → 0.2.1

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 (78) hide show
  1. package/README.md +7 -2
  2. package/assets/skill/cookbooks/authoring_chains.md +96 -84
  3. package/assets/skill/cookbooks/roster.md +3 -1
  4. package/assets/skill/references/config.md +5 -2
  5. package/assets/templates/ts-cc.spf.config.yaml +16 -0
  6. package/assets/templates/ts-flue-openrouter.spf.config.yaml +15 -0
  7. package/assets/templates/ts.spf.config.yaml +19 -4
  8. package/dist/chains/context.d.ts +2 -0
  9. package/dist/chains/index.d.ts +21 -2
  10. package/dist/chains/index.js +73 -104
  11. package/dist/chains/{adw_simple_sdlc.d.ts → simple_sdlc.d.ts} +7 -1
  12. package/dist/chains/{adw_simple_sdlc.js → simple_sdlc.js} +19 -30
  13. package/dist/chains/steps.d.ts +117 -0
  14. package/dist/chains/steps.js +299 -0
  15. package/dist/cli/ask.d.ts +27 -0
  16. package/dist/cli/ask.js +125 -0
  17. package/dist/cli/commands/doctor.js +2 -24
  18. package/dist/cli/commands/init.d.ts +1 -1
  19. package/dist/cli/commands/init.js +92 -9
  20. package/dist/cli/commands/run.d.ts +1 -1
  21. package/dist/cli/commands/run.js +3 -1
  22. package/dist/cli/commands/watch.js +26 -4
  23. package/dist/cli/env_file.d.ts +18 -0
  24. package/dist/cli/env_file.js +99 -0
  25. package/dist/cli/index.js +2 -2
  26. package/dist/cli/interview.d.ts +24 -0
  27. package/dist/cli/interview.js +330 -0
  28. package/dist/core/issues/jira_provider.d.ts +9 -0
  29. package/dist/core/issues/jira_provider.js +20 -2
  30. package/dist/core/prompts.d.ts +2 -0
  31. package/dist/core/prompts.js +2 -0
  32. package/dist/core/providers.d.ts +12 -0
  33. package/dist/core/providers.js +24 -0
  34. package/dist/core/quality.d.ts +9 -0
  35. package/dist/core/quality.js +10 -0
  36. package/dist/core/session.d.ts +6 -1
  37. package/dist/core/session.js +7 -3
  38. package/dist/core/tracer.js +1 -1
  39. package/dist/core/utils.d.ts +6 -2
  40. package/dist/core/utils.js +11 -2
  41. package/dist/core/watch.d.ts +12 -0
  42. package/dist/core/watch.js +11 -0
  43. package/dist/test/chains.test.d.ts +12 -0
  44. package/dist/test/chains.test.js +86 -0
  45. package/dist/test/env_file.test.d.ts +1 -0
  46. package/dist/test/env_file.test.js +74 -0
  47. package/dist/test/fake_asker.d.ts +23 -0
  48. package/dist/test/fake_asker.js +30 -0
  49. package/dist/test/init_command.test.d.ts +1 -0
  50. package/dist/test/init_command.test.js +66 -0
  51. package/dist/test/interview.test.d.ts +1 -0
  52. package/dist/test/interview.test.js +179 -0
  53. package/dist/test/ui_server.test.js +1 -1
  54. package/dist/test/watch.test.js +41 -1
  55. package/dist/ui/shared/types.d.ts +1 -1
  56. package/package.json +5 -2
  57. package/dist/chains/adw_build.d.ts +0 -12
  58. package/dist/chains/adw_build.js +0 -27
  59. package/dist/chains/adw_build_review.d.ts +0 -21
  60. package/dist/chains/adw_build_review.js +0 -55
  61. package/dist/chains/adw_build_test.d.ts +0 -21
  62. package/dist/chains/adw_build_test.js +0 -67
  63. package/dist/chains/adw_document.d.ts +0 -23
  64. package/dist/chains/adw_document.js +0 -59
  65. package/dist/chains/adw_plan.d.ts +0 -12
  66. package/dist/chains/adw_plan.js +0 -27
  67. package/dist/chains/adw_plan_build.d.ts +0 -12
  68. package/dist/chains/adw_plan_build.js +0 -30
  69. package/dist/chains/adw_plan_build_test.d.ts +0 -16
  70. package/dist/chains/adw_plan_build_test.js +0 -65
  71. package/dist/chains/adw_plan_build_test_quality.d.ts +0 -18
  72. package/dist/chains/adw_plan_build_test_quality.js +0 -66
  73. package/dist/chains/adw_prompt.d.ts +0 -12
  74. package/dist/chains/adw_prompt.js +0 -25
  75. package/dist/chains/adw_quality.d.ts +0 -12
  76. package/dist/chains/adw_quality.js +0 -32
  77. package/dist/chains/adw_scout.d.ts +0 -12
  78. package/dist/chains/adw_scout.js +0 -27
@@ -1,55 +0,0 @@
1
- /**
2
- * ADW Build Review — implement, then confirm it is what was asked for.
3
- *
4
- * Usage:
5
- * spf build-review "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> builder -> reviewer [-> builder(revise) -> reviewer ... bounded]
8
- *
9
- * Review is not testing. Tests answer "does it run"; the reviewer answers "is this
10
- * the thing that was asked for" — it reads the spec (`plan.md` from a prior plan
11
- * phase if the session has one, else the prompt verbatim), reads the code that was
12
- * written, and rules on each requirement.
13
- *
14
- * Like the tester, the reviewer's phase succeeds when it RUNS and REPORTS. A
15
- * rejection does not fail the phase; it fails the run, checked at the end, after
16
- * the bounded revise loop has had its chances.
17
- */
18
- import * as agents from "../core/agents.js";
19
- import * as gates from "../core/gates.js";
20
- import * as session from "../core/session.js";
21
- import { BuildOutput, ReviewOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
22
- export const REQUIRED_AGENTS = ["builder", "reviewer"];
23
- export const REQUIRED_SUITES = [];
24
- const MAX_REVISION_LOOPS = 3;
25
- export async function main(ctx) {
26
- const { prompt, config_paths, adw_id, cwd } = ctx;
27
- const cfg = agents.loadConfig(config_paths);
28
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
29
- const run = session.ensure(cfg, adw_id, cwd);
30
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
31
- ph.log({ input: prompt });
32
- });
33
- let previous = await run.phase(makePhaseParams({ name: "build", kind: "agent", owner: "builder", description: "Implement the request" }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, gates: [gates.diffMatchesClaims] })));
34
- let review = null;
35
- for (let i = 1; i <= MAX_REVISION_LOOPS; i++) {
36
- review = await run.phase(makePhaseParams({
37
- name: `review_${i}`,
38
- kind: "agent",
39
- owner: "reviewer",
40
- description: "Rule on every requirement in the spec, against the code on disk",
41
- }), (ph) => ph.call(makeAgentCall({ output_type: ReviewOutput, prompt, previous, gates: [gates.artifactsExist, gates.verdictConsistent] })));
42
- if (review.approved)
43
- break;
44
- if (i === MAX_REVISION_LOOPS)
45
- break;
46
- previous = await run.phase(makePhaseParams({
47
- name: `revise_${i}`,
48
- kind: "agent",
49
- owner: "builder",
50
- retries: 1,
51
- description: "Close every blocking finding the reviewer named",
52
- }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, previous: review, gates: [gates.diffMatchesClaims] })));
53
- }
54
- return run.finish(review !== null && review.approved, `the reviewer never approved after ${MAX_REVISION_LOOPS} revision(s)`);
55
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * ADW Build Test — implement, then verify; failures flow back into the builder.
3
- *
4
- * Usage:
5
- * spf build-test "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> builder -> code(test) [-> builder(fix) -> code(test) ... bounded]
8
- *
9
- * Testing is CODE. The suite's command is written down in core/quality.ts,
10
- * so running it needs no judgement — only repairing it does. Failures reach the
11
- * builder as an envelope through `quality.asEnvelope`, which is the same door an
12
- * agent's report came through, so the repair loop is unchanged.
13
- *
14
- * A failing suite does NOT fail its phase: the runner did its job, the code is
15
- * what failed. It fails the run, checked at the end, after the bounded fix loop
16
- * has had its chances.
17
- */
18
- import type { ChainContext } from "./context.ts";
19
- export declare const REQUIRED_AGENTS: string[];
20
- export declare const REQUIRED_SUITES: string[];
21
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,67 +0,0 @@
1
- /**
2
- * ADW Build Test — implement, then verify; failures flow back into the builder.
3
- *
4
- * Usage:
5
- * spf build-test "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> builder -> code(test) [-> builder(fix) -> code(test) ... bounded]
8
- *
9
- * Testing is CODE. The suite's command is written down in core/quality.ts,
10
- * so running it needs no judgement — only repairing it does. Failures reach the
11
- * builder as an envelope through `quality.asEnvelope`, which is the same door an
12
- * agent's report came through, so the repair loop is unchanged.
13
- *
14
- * A failing suite does NOT fail its phase: the runner did its job, the code is
15
- * what failed. It fails the run, checked at the end, after the bounded fix loop
16
- * has had its chances.
17
- */
18
- import * as agents from "../core/agents.js";
19
- import * as gates from "../core/gates.js";
20
- import * as quality from "../core/quality.js";
21
- import * as session from "../core/session.js";
22
- import { BuildOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
23
- export const REQUIRED_AGENTS = ["builder"];
24
- export const REQUIRED_SUITES = ["test"];
25
- const MAX_FIX_LOOPS = 3;
26
- function record(ph, result) {
27
- const passed = result.checks.filter((c) => c.passed).length;
28
- ph.log({ passed: result.passed, checks: `${passed}/${result.checks.length}`, artifacts: result.artifacts.join(", ") });
29
- }
30
- export async function main(ctx) {
31
- const { prompt, config_paths, adw_id, cwd } = ctx;
32
- const cfg = agents.loadConfig(config_paths);
33
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
34
- const run = session.ensure(cfg, adw_id, cwd);
35
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
36
- ph.log({ input: prompt });
37
- });
38
- await run.phase(makePhaseParams({ name: "build", kind: "agent", owner: "builder", description: "Implement the request" }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, gates: [gates.diffMatchesClaims] })));
39
- let test = null;
40
- for (let i = 1; i <= MAX_FIX_LOOPS; i++) {
41
- test = await run.phase(makePhaseParams({
42
- name: `test_${i}`,
43
- kind: "code",
44
- owner: "quality",
45
- description: "Run the suite — a known command, so code runs it and no agent has to rediscover it",
46
- }), async (ph) => {
47
- const result = quality.runTests(run);
48
- record(ph, result);
49
- return result;
50
- });
51
- if (test.passed)
52
- break;
53
- await run.phase(makePhaseParams({
54
- name: `fix_${i}`,
55
- kind: "agent",
56
- owner: "builder",
57
- retries: 1,
58
- description: "Repair what the suite reported, from its verbatim output",
59
- }), (ph) => ph.call(makeAgentCall({
60
- output_type: BuildOutput,
61
- prompt,
62
- previous: quality.asEnvelope(test, "tests"),
63
- gates: [gates.diffMatchesClaims],
64
- })));
65
- }
66
- return run.finish(test !== null && test.passed, `the suite still failed after ${MAX_FIX_LOOPS} fix attempt(s)`);
67
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * ADW Document — write up the work that was just done, from the diff.
3
- *
4
- * Usage:
5
- * spf document "<prompt or path/to/prompt.md>" [--base main] [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> code(changes) -> documenter
8
- *
9
- * This runs AFTER a build, and the guard is structural rather than advisory: the
10
- * change capture is a code phase, and an empty diff raises there — before the
11
- * documenter is ever spawned. There is nothing to document until something was
12
- * built, and the phase says so instead of paying an agent to discover it.
13
- *
14
- * `git diff` against `--base` (main by default) is what "the latest changes"
15
- * means here; see core/changes.ts for how the base commit is resolved on a
16
- * branch, on main, and on a clean tree right after a chain committed.
17
- */
18
- import type { ChainContext } from "./context.ts";
19
- export declare const REQUIRED_AGENTS: string[];
20
- export declare const REQUIRED_SUITES: string[];
21
- export declare function main(ctx: ChainContext, options?: {
22
- base?: string;
23
- }): Promise<number>;
@@ -1,59 +0,0 @@
1
- /**
2
- * ADW Document — write up the work that was just done, from the diff.
3
- *
4
- * Usage:
5
- * spf document "<prompt or path/to/prompt.md>" [--base main] [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> code(changes) -> documenter
8
- *
9
- * This runs AFTER a build, and the guard is structural rather than advisory: the
10
- * change capture is a code phase, and an empty diff raises there — before the
11
- * documenter is ever spawned. There is nothing to document until something was
12
- * built, and the phase says so instead of paying an agent to discover it.
13
- *
14
- * `git diff` against `--base` (main by default) is what "the latest changes"
15
- * means here; see core/changes.ts for how the base commit is resolved on a
16
- * branch, on main, and on a clean tree right after a chain committed.
17
- */
18
- import * as agents from "../core/agents.js";
19
- import * as changes from "../core/changes.js";
20
- import * as gates from "../core/gates.js";
21
- import * as session from "../core/session.js";
22
- import { DocumentOutput, makeAgentCall, makeChangeCapture, makePhaseParams } from "../core/data_types.js";
23
- export const REQUIRED_AGENTS = ["documenter"];
24
- export const REQUIRED_SUITES = [];
25
- const DOCUMENT_NOTES = "Read diff_path in full before writing. Document only what the diff shows, then copy the write-up into app_docs/ as your task describes.";
26
- export async function main(ctx, options = {}) {
27
- const { prompt, config_paths, adw_id, cwd } = ctx;
28
- const base = options.base ?? "main";
29
- const cfg = agents.loadConfig(config_paths);
30
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
31
- const run = session.ensure(cfg, adw_id, cwd);
32
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
33
- ph.log({ input: prompt });
34
- });
35
- const changeset = await run.phase(makePhaseParams({ name: "changes", kind: "code", owner: "git", description: `Diff the working tree against ${base} — the change to be written up` }), async (ph) => {
36
- const result = changes.capture(run, makeChangeCapture({ base }));
37
- ph.log({
38
- base: `${result.base.label} @ ${result.base.commit.slice(0, 7)}`,
39
- reason: result.base.reason,
40
- files: result.files.length + result.untracked.length,
41
- lines: `+${result.insertions} -${result.deletions}`,
42
- diff: result.diff_path,
43
- });
44
- if (result.empty) {
45
- throw new Error(`nothing changed since ${result.base.label} (${result.base.reason}) — documenting runs after a build. ` +
46
- `Build something first, or point --base at the ref the work should be measured from.`);
47
- }
48
- return result;
49
- });
50
- await run.phase(makePhaseParams({ name: "document", kind: "agent", owner: "documenter", retries: 1, description: "Turn the captured diff into a write-up an engineer can read" }), async (ph) => {
51
- await ph.call(makeAgentCall({
52
- output_type: DocumentOutput,
53
- prompt,
54
- previous: changes.asEnvelope(changeset, DOCUMENT_NOTES),
55
- gates: [gates.artifactsExist, gates.filesNonEmpty],
56
- }));
57
- });
58
- return run.finish();
59
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * ADW Plan — one-shot planning workflow.
3
- *
4
- * Usage:
5
- * spf plan "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner
8
- */
9
- import type { ChainContext } from "./context.ts";
10
- export declare const REQUIRED_AGENTS: string[];
11
- export declare const REQUIRED_SUITES: string[];
12
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,27 +0,0 @@
1
- /**
2
- * ADW Plan — one-shot planning workflow.
3
- *
4
- * Usage:
5
- * spf plan "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner
8
- */
9
- import * as agents from "../core/agents.js";
10
- import * as gates from "../core/gates.js";
11
- import * as session from "../core/session.js";
12
- import { PlanOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
13
- export const REQUIRED_AGENTS = ["planner"];
14
- export const REQUIRED_SUITES = [];
15
- export async function main(ctx) {
16
- const { prompt, config_paths, adw_id, cwd } = ctx;
17
- const cfg = agents.loadConfig(config_paths);
18
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
19
- const run = session.ensure(cfg, adw_id, cwd);
20
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
21
- ph.log({ input: prompt });
22
- });
23
- await run.phase(makePhaseParams({ name: "plan", kind: "agent", owner: "planner", description: "Turn the request into an implementable plan" }), async (ph) => {
24
- await ph.call(makeAgentCall({ output_type: PlanOutput, prompt, gates: [gates.artifactsExist, gates.filesNonEmpty] }));
25
- });
26
- return run.finish();
27
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * ADW Plan Build — two-agent chain: planner -> envelope -> builder.
3
- *
4
- * Usage:
5
- * spf plan-build "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner -> builder -> git(commit)
8
- */
9
- import type { ChainContext } from "./context.ts";
10
- export declare const REQUIRED_AGENTS: string[];
11
- export declare const REQUIRED_SUITES: string[];
12
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,30 +0,0 @@
1
- /**
2
- * ADW Plan Build — two-agent chain: planner -> envelope -> builder.
3
- *
4
- * Usage:
5
- * spf plan-build "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner -> builder -> git(commit)
8
- */
9
- import * as agents from "../core/agents.js";
10
- import * as gates from "../core/gates.js";
11
- import * as session from "../core/session.js";
12
- import { BuildOutput, PlanOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
13
- export const REQUIRED_AGENTS = ["planner", "builder"];
14
- export const REQUIRED_SUITES = [];
15
- export async function main(ctx) {
16
- const { prompt, config_paths, adw_id, cwd } = ctx;
17
- const cfg = agents.loadConfig(config_paths);
18
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
19
- const run = session.ensure(cfg, adw_id, cwd);
20
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
21
- ph.log({ input: prompt });
22
- });
23
- const plan = await run.phase(makePhaseParams({ name: "plan", kind: "agent", owner: "planner", description: "Turn the request into an implementable plan" }), (ph) => ph.call(makeAgentCall({ output_type: PlanOutput, prompt, gates: [gates.artifactsExist, gates.filesNonEmpty] })));
24
- const build = await run.phase(makePhaseParams({ name: "build", kind: "agent", owner: "builder", description: "Implement the plan exactly" }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, previous: plan, gates: [gates.diffMatchesClaims] })));
25
- await run.phase(makePhaseParams({ name: "commit", kind: "code", owner: "git", description: "Land the builder's changes, using the message it wrote" }), async (ph) => {
26
- const message = build.commit_message || `spf(${run.adw_id}): ${build.summary}`;
27
- ph.log({ sha: run.git.commitAll(message), message });
28
- });
29
- return run.finish();
30
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * ADW Plan Build Test — the full starter chain.
3
- *
4
- * Usage:
5
- * spf plan-build-test "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner -> builder -> code(test) [-> builder(fix) -> code(test) ... bounded] -> git(commit)
8
- *
9
- * Testing is CODE: the suite's command lives in core/quality.ts, so no
10
- * agent spends a context window rediscovering it. Failures flow back to the
11
- * builder as an envelope, and only an exhausted fix loop fails the run.
12
- */
13
- import type { ChainContext } from "./context.ts";
14
- export declare const REQUIRED_AGENTS: string[];
15
- export declare const REQUIRED_SUITES: string[];
16
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,65 +0,0 @@
1
- /**
2
- * ADW Plan Build Test — the full starter chain.
3
- *
4
- * Usage:
5
- * spf plan-build-test "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner -> builder -> code(test) [-> builder(fix) -> code(test) ... bounded] -> git(commit)
8
- *
9
- * Testing is CODE: the suite's command lives in core/quality.ts, so no
10
- * agent spends a context window rediscovering it. Failures flow back to the
11
- * builder as an envelope, and only an exhausted fix loop fails the run.
12
- */
13
- import * as agents from "../core/agents.js";
14
- import * as gates from "../core/gates.js";
15
- import * as quality from "../core/quality.js";
16
- import * as session from "../core/session.js";
17
- import { BuildOutput, PlanOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
18
- export const REQUIRED_AGENTS = ["planner", "builder"];
19
- export const REQUIRED_SUITES = ["test"];
20
- const MAX_FIX_LOOPS = 3;
21
- function record(ph, result) {
22
- const passed = result.checks.filter((c) => c.passed).length;
23
- ph.log({ passed: result.passed, checks: `${passed}/${result.checks.length}`, artifacts: result.artifacts.join(", ") });
24
- }
25
- export async function main(ctx) {
26
- const { prompt, config_paths, adw_id, cwd } = ctx;
27
- const cfg = agents.loadConfig(config_paths);
28
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
29
- const run = session.ensure(cfg, adw_id, cwd);
30
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
31
- ph.log({ input: prompt });
32
- });
33
- const plan = await run.phase(makePhaseParams({ name: "plan", kind: "agent", owner: "planner", description: "Turn the request into an implementable plan" }), (ph) => ph.call(makeAgentCall({ output_type: PlanOutput, prompt, gates: [gates.artifactsExist, gates.filesNonEmpty] })));
34
- let previous = await run.phase(makePhaseParams({ name: "build", kind: "agent", owner: "builder", description: "Implement the plan exactly" }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, previous: plan, gates: [gates.artifactsExist] })));
35
- let test = null;
36
- for (let i = 1; i <= MAX_FIX_LOOPS; i++) {
37
- test = await run.phase(makePhaseParams({
38
- name: `test_${i}`,
39
- kind: "code",
40
- owner: "quality",
41
- description: "Run the suite — a known command, so code runs it and no agent has to rediscover it",
42
- }), async (ph) => {
43
- const result = quality.runTests(run);
44
- record(ph, result);
45
- return result;
46
- });
47
- if (test.passed)
48
- break;
49
- previous = await run.phase(makePhaseParams({
50
- name: `fix_${i}`,
51
- kind: "agent",
52
- owner: "builder",
53
- retries: 1,
54
- description: "Repair what the suite reported, from its verbatim output",
55
- }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, previous: quality.asEnvelope(test, "tests"), gates: [gates.artifactsExist] })));
56
- }
57
- // Only tested work gets committed — a red suite leaves the tree uncommitted.
58
- if (test !== null && test.passed) {
59
- await run.phase(makePhaseParams({ name: "commit", kind: "code", owner: "git", description: "Land the code only after the suite came back green" }), async (ph) => {
60
- const message = previous.commit_message || `spf(${run.adw_id}): ${previous.summary}`;
61
- ph.log({ sha: run.git.commitAll(message), message });
62
- });
63
- }
64
- return run.finish(test !== null && test.passed, `the suite still failed after ${MAX_FIX_LOOPS} fix attempt(s)`);
65
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * ADW Plan Build Test Quality — full agent chain plus deterministic quality.
3
- *
4
- * Usage:
5
- * spf plan-build-test-quality "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner -> builder -> [code(verify) -> code(test) -> builder(fix)] bounded -> git(commit)
8
- *
9
- * Verify and test are CODE, not agents. Their commands are known, so running them
10
- * needs no judgement — only repairing them does. A failing block does not fail its
11
- * phase: the runner did its job, the code is what failed. The failure becomes an
12
- * envelope and flows back into the builder, and only an exhausted repair loop
13
- * fails the run.
14
- */
15
- import type { ChainContext } from "./context.ts";
16
- export declare const REQUIRED_AGENTS: string[];
17
- export declare const REQUIRED_SUITES: string[];
18
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,66 +0,0 @@
1
- /**
2
- * ADW Plan Build Test Quality — full agent chain plus deterministic quality.
3
- *
4
- * Usage:
5
- * spf plan-build-test-quality "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> planner -> builder -> [code(verify) -> code(test) -> builder(fix)] bounded -> git(commit)
8
- *
9
- * Verify and test are CODE, not agents. Their commands are known, so running them
10
- * needs no judgement — only repairing them does. A failing block does not fail its
11
- * phase: the runner did its job, the code is what failed. The failure becomes an
12
- * envelope and flows back into the builder, and only an exhausted repair loop
13
- * fails the run.
14
- */
15
- import * as agents from "../core/agents.js";
16
- import * as gates from "../core/gates.js";
17
- import * as quality from "../core/quality.js";
18
- import * as session from "../core/session.js";
19
- import { BuildOutput, PlanOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
20
- export const REQUIRED_AGENTS = ["planner", "builder"];
21
- export const REQUIRED_SUITES = ["all"];
22
- const MAX_FIX_LOOPS = 3;
23
- function record(ph, result) {
24
- const passed = result.checks.filter((c) => c.passed).length;
25
- ph.log({ passed: result.passed, checks: `${passed}/${result.checks.length}`, artifacts: result.artifacts.join(", ") });
26
- }
27
- export async function main(ctx) {
28
- const { prompt, config_paths, adw_id, cwd } = ctx;
29
- const cfg = agents.loadConfig(config_paths);
30
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
31
- const run = session.ensure(cfg, adw_id, cwd);
32
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
33
- ph.log({ input: prompt });
34
- });
35
- const plan = await run.phase(makePhaseParams({ name: "plan", kind: "agent", owner: "planner", description: "Turn the request into an implementable plan" }), (ph) => ph.call(makeAgentCall({ output_type: PlanOutput, prompt, gates: [gates.artifactsExist, gates.filesNonEmpty] })));
36
- let previous = await run.phase(makePhaseParams({ name: "build", kind: "agent", owner: "builder", description: "Implement the plan exactly" }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, previous: plan, gates: [gates.diffMatchesClaims] })));
37
- let testResult = null;
38
- let qualityResult = null;
39
- for (let i = 1; i <= MAX_FIX_LOOPS; i++) {
40
- qualityResult = await run.phase(makePhaseParams({ name: `verify_${i}`, kind: "code", owner: "quality", description: "Lint, typecheck, and build before testing" }), async (ph) => {
41
- const result = quality.runQuality(run);
42
- record(ph, result);
43
- return result;
44
- });
45
- // runQuality() already includes the test block; a repo that wants tests
46
- // in their own phase can split them out the way this comment does.
47
- testResult = qualityResult;
48
- if (qualityResult.passed && testResult.passed)
49
- break;
50
- if (i === MAX_FIX_LOOPS)
51
- break;
52
- // Whichever block failed becomes the builder's spec — verbatim command
53
- // output, no parser standing between the failure and the fix.
54
- const broken = !qualityResult.passed ? qualityResult : testResult;
55
- const what = !qualityResult.passed ? "verification" : "tests";
56
- previous = await run.phase(makePhaseParams({ name: `fix_${i}`, kind: "agent", owner: "builder", retries: 1, description: `Resolve the reported ${what} failures` }), (ph) => ph.call(makeAgentCall({ output_type: BuildOutput, prompt, previous: quality.asEnvelope(broken, what), gates: [gates.diffMatchesClaims] })));
57
- }
58
- const verified = qualityResult !== null && qualityResult.passed && testResult !== null && testResult.passed;
59
- if (verified) {
60
- await run.phase(makePhaseParams({ name: "commit", kind: "code", owner: "git", description: "Commit the tested and quality-verified working tree" }), async (ph) => {
61
- const message = previous.commit_message || `spf(${run.adw_id}): ${previous.summary}`;
62
- ph.log({ sha: run.git.commitAll(message), message });
63
- });
64
- }
65
- return run.finish(verified, `verify/test never came back clean after ${MAX_FIX_LOOPS} fix attempt(s)`);
66
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * ADW Prompt — the smallest ADW: one agent, one prompt, traced end-to-end.
3
- *
4
- * Usage:
5
- * spf prompt "<prompt or path/to/prompt.md>" [--agent builder] [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> <agent>
8
- */
9
- import type { ChainContext } from "./context.ts";
10
- export declare function main(ctx: ChainContext, options?: {
11
- agent?: string;
12
- }): Promise<number>;
@@ -1,25 +0,0 @@
1
- /**
2
- * ADW Prompt — the smallest ADW: one agent, one prompt, traced end-to-end.
3
- *
4
- * Usage:
5
- * spf prompt "<prompt or path/to/prompt.md>" [--agent builder] [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> <agent>
8
- */
9
- import * as agents from "../core/agents.js";
10
- import * as session from "../core/session.js";
11
- import { GenericOutput, makeAgentCall, makePhaseParams } from "../core/data_types.js";
12
- export async function main(ctx, options = {}) {
13
- const { prompt, config_paths, adw_id, cwd } = ctx;
14
- const agent = options.agent ?? "builder";
15
- const cfg = agents.loadConfig(config_paths);
16
- agents.validate(cfg, [agent], [], cwd);
17
- const run = session.ensure(cfg, adw_id, cwd);
18
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
19
- ph.log({ input: prompt });
20
- });
21
- await run.phase(makePhaseParams({ name: "prompt", kind: "agent", owner: agent, description: `Send the request straight to ${agent} and parse its envelope` }), async (ph) => {
22
- await ph.call(makeAgentCall({ output_type: GenericOutput, prompt }));
23
- });
24
- return run.finish();
25
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * ADW Quality — lint, typecheck, and build the project.
3
- *
4
- * Usage:
5
- * spf quality "<reason for the quality run>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> code(quality)
8
- */
9
- import type { ChainContext } from "./context.ts";
10
- export declare const REQUIRED_AGENTS: string[];
11
- export declare const REQUIRED_SUITES: string[];
12
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,32 +0,0 @@
1
- /**
2
- * ADW Quality — lint, typecheck, and build the project.
3
- *
4
- * Usage:
5
- * spf quality "<reason for the quality run>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> code(quality)
8
- */
9
- import * as agents from "../core/agents.js";
10
- import * as quality from "../core/quality.js";
11
- import * as session from "../core/session.js";
12
- import { makePhaseParams } from "../core/data_types.js";
13
- export const REQUIRED_AGENTS = [];
14
- export const REQUIRED_SUITES = ["all"];
15
- export async function main(ctx) {
16
- const { prompt, config_paths, adw_id, cwd } = ctx;
17
- const cfg = agents.loadConfig(config_paths);
18
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
19
- const run = session.ensure(cfg, adw_id, cwd);
20
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture why quality verification was requested" }), async (ph) => {
21
- ph.log({ input: prompt });
22
- });
23
- await run.phase(makePhaseParams({ name: "quality", kind: "code", owner: "quality", description: "Run the deterministic quality blocks" }), async (ph) => {
24
- const result = quality.runQuality(run);
25
- const passed = result.checks.filter((c) => c.passed).length;
26
- ph.log({ passed: result.passed, checks: `${passed}/${result.checks.length}`, artifacts: result.artifacts.join(", ") });
27
- if (!result.passed) {
28
- throw new Error("quality failed: " + result.failures.join("; "));
29
- }
30
- });
31
- return run.finish();
32
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * ADW Scout — read-only recon workflow. Just looking for stuff.
3
- *
4
- * Usage:
5
- * spf scout "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> scout
8
- */
9
- import type { ChainContext } from "./context.ts";
10
- export declare const REQUIRED_AGENTS: string[];
11
- export declare const REQUIRED_SUITES: string[];
12
- export declare function main(ctx: ChainContext): Promise<number>;
@@ -1,27 +0,0 @@
1
- /**
2
- * ADW Scout — read-only recon workflow. Just looking for stuff.
3
- *
4
- * Usage:
5
- * spf scout "<prompt or path/to/prompt.md>" [--config <path>] [--adw-id a1b2c3d4]
6
- *
7
- * Phases: engineer(request) -> scout
8
- */
9
- import * as agents from "../core/agents.js";
10
- import * as gates from "../core/gates.js";
11
- import * as session from "../core/session.js";
12
- import { makeAgentCall, makePhaseParams, ScoutOutput } from "../core/data_types.js";
13
- export const REQUIRED_AGENTS = ["scout"];
14
- export const REQUIRED_SUITES = [];
15
- export async function main(ctx) {
16
- const { prompt, config_paths, adw_id, cwd } = ctx;
17
- const cfg = agents.loadConfig(config_paths);
18
- agents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);
19
- const run = session.ensure(cfg, adw_id, cwd);
20
- await run.phase(makePhaseParams({ name: "request", kind: "engineer", owner: run.engineer, description: "Capture the incoming ask" }), async (ph) => {
21
- ph.log({ input: prompt });
22
- });
23
- await run.phase(makePhaseParams({ name: "scout", kind: "agent", owner: "scout", description: "Find and report where things live — change nothing" }), async (ph) => {
24
- await ph.call(makeAgentCall({ output_type: ScoutOutput, prompt, gates: [gates.artifactsExist] }));
25
- });
26
- return run.finish();
27
- }