feat(pipeline): skill phase kind + PhaseRunner seam + halt/answer/resume - #206
Conversation
| if (skill.kind === "fn") { | ||
| const res = await skill.run(ctx); | ||
| return { outcome: "passed", summary: res.summary, artifacts: res.artifacts }; | ||
| } |
There was a problem hiding this comment.
🟡 Medium — Uncaught exceptions in native fn skills
If a native fn skill throws an exception during execution, the error will propagate directly and reject the execution promise. Wrapping the skill execution in a try-catch block allows capturing the error and returning a graceful failure outcome (outcome: "failed") so the pipeline status can be updated gracefully in the database.
| } | |
| if (skill.kind === "fn") { | |
| try { | |
| const res = await skill.run(ctx); | |
| return { outcome: "passed", summary: res.summary, artifacts: res.artifacts }; | |
| } catch (err: any) { | |
| return { outcome: "failed", reason: `Skill execution failed: ${err?.message ?? err}` }; | |
| } | |
| } |
🤖 Gemini code reviewThis PR introduces the skill phase execution flow (with PhaseRunner abstraction for external model/slash skills) and the halt-answer-resume mechanism for pipeline execution. Findings: 🔴 0 · 🟠 0 · 🟡 1 · 🟢 0 Tokens spent · ⬆️ Input: 4,569 · ⬇️ Output: 238 · Σ Total: 9,452 |
4390bd1 to
b78f528
Compare
fa77b26 to
9fa086c
Compare
Add the runtime layer. A 'skill' PhaseKind runs fn skills natively and drives prompt/slash skills through an injectable PhaseRunner (the backend seam; a SessionManager-backed adapter lands in a follow-up). PipelineManager.answer(id, requestId, {approved, value}) is the daemon side of halt -> answer-from-a-frontend -> resume: it resolves a halted phase (pass/fail) and continues advancing to the next halt or terminal. Fully unit-tested with fakes; no live backend required. Still dark (pipeline off by default).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Addressed the Gemini finding: |
9fa086c to
4822afd
Compare
…205) * feat(pipeline): config schema (off by default) + daemon boot wiring Add a PipelineSchema to config (enabled=false default, defaultPack=null) with a CODEOID_PIPELINE_ENABLED env switch, and construct a PipelineManager in SessionManager when enabled — sharing the daemon DB and rehydrating non-terminal pipelines on boot (resume). Undefined when disabled, so the daemon stays dark by default. Pure createPipelineManagerFromConfig() factory keeps the enable/disable + share-DB + restart-survival behavior unit-tested without a full SessionManager. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(pipeline): skill phase kind + PhaseRunner seam + halt/answer/resume (#206) Add the runtime layer. A 'skill' PhaseKind runs fn skills natively and drives prompt/slash skills through an injectable PhaseRunner (the backend seam; a SessionManager-backed adapter lands in a follow-up). PipelineManager.answer(id, requestId, {approved, value}) is the daemon side of halt -> answer-from-a-frontend -> resume: it resolves a halted phase (pass/fail) and continues advancing to the next halt or terminal. Fully unit-tested with fakes; no live backend required. Still dark (pipeline off by default). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dark) (#204) * docs: SDLC pipeline design — external prior-art & SOTA validation + refinements Add §2a (Spec Kit / BMAD / Kiro / Roo / Aider + 2026 papers + omnigent/kiss_ai) and §5a (per-phase tool scoping, typed artifacts, entry/grounding gates, constitution/steering layer, gate enforcement tiers). Resolve open Q3/Q4/Q6; default the pipeline off (freestyle) until a pack is selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(pipeline): SDLC pipeline primitive — engine, store, registries (dark) Methodology-agnostic pipeline foundation (docs/sdlc-pipeline.md §5): PhaseDef/PipelineState types + the four plugin seams (PhaseKind, GatePlugin, SkillPlugin, Pack), a Map-backed registry, a built-in noop phase kind + always/manual gates, the advance engine (entry/exit gates; onFail halt/retry/abort), durable bun:sqlite state, and PipelineManager with resume() for restart survival. No daemon wiring, no methodology content — lands dark. 26 unit tests; tsc + biome clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(pipeline): config schema (off by default) + daemon boot wiring (#205) * feat(pipeline): config schema (off by default) + daemon boot wiring Add a PipelineSchema to config (enabled=false default, defaultPack=null) with a CODEOID_PIPELINE_ENABLED env switch, and construct a PipelineManager in SessionManager when enabled — sharing the daemon DB and rehydrating non-terminal pipelines on boot (resume). Undefined when disabled, so the daemon stays dark by default. Pure createPipelineManagerFromConfig() factory keeps the enable/disable + share-DB + restart-survival behavior unit-tested without a full SessionManager. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(pipeline): skill phase kind + PhaseRunner seam + halt/answer/resume (#206) Add the runtime layer. A 'skill' PhaseKind runs fn skills natively and drives prompt/slash skills through an injectable PhaseRunner (the backend seam; a SessionManager-backed adapter lands in a follow-up). PipelineManager.answer(id, requestId, {approved, value}) is the daemon side of halt -> answer-from-a-frontend -> resume: it resolves a halted phase (pass/fail) and continues advancing to the next halt or terminal. Fully unit-tested with fakes; no live backend required. Still dark (pipeline off by default). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Third slice: phase execution + the halt → answer → resume path. Still dark — pipeline off by default.
makeSkillPhaseKind(runner?)— the"skill"phase kind.fnskills run natively (no backend);prompt/slashskills drive through an injectablePhaseRunner(the backend seam). With no runner configured, a prompt/slash skill fails with a clear reason, so the kind stays usable in pure tests and degrades safely.PhaseRunner(runner.ts) — the seam between a phase and a backend (runPromptwith per-phaseprovider/modelfor cross-provider-per-phase routing). The SessionManager-backed adapter that actually drives a worker turn lands in a follow-up.PipelineManager.answer(id, requestId, { approved, value })— the daemon side of halt → answer-from-a-frontend → resume (§4.1, §5.3): resolves a halted phase (pass/fail) and continues advancing to the next halt or terminal. Persists across restart.Verification
bun test src/daemon/pipeline— 42 pass / 0 fail (16 new: skill-kind + answer/resume)tsc --noEmit— clean project-widebiome check— cleanStacked
Base =
feat/sdlc-pipeline-wiring(#205). This branch also carries a one-line lint fix (import typeinmanager.ts) that the rebased stack applies to #204/#205 as well.Deferred to follow-ups
SessionManager-backedPhaseRunner: a worker session per phase actually driving a backend turn (needs the fake-provider integration harness).pipeline.*messages,SessionInfo.phase) + the §10 frontend halt-surfacing UX (answer a blocker from Web/Telegram).🤖 Generated with Claude Code