* docs(S01): add slice plan * feat(S01/T01): Created four engine abstraction layer files: engine-type… - src/resources/extensions/gsd/engine-types.ts - src/resources/extensions/gsd/workflow-engine.ts - src/resources/extensions/gsd/execution-policy.ts - src/resources/extensions/gsd/engine-resolver.ts * test(S01/T02): Added activeEngineId to AutoSession lifecycle (property,… - src/resources/extensions/gsd/auto/session.ts - src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts * chore(M001/S02): auto-commit after research-slice * docs(S02): add slice plan * feat(S02/T01): Created DevWorkflowEngine and DevExecutionPolicy classes… - src/resources/extensions/gsd/dev-workflow-engine.ts - src/resources/extensions/gsd/dev-execution-policy.ts - src/resources/extensions/gsd/engine-resolver.ts - src/resources/extensions/gsd/auto.ts * test(S02/T02): Added 18 contract tests for dev engine wrapper and updat… - src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts - src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts * docs(S03): add slice plan * chore(S03/T01): Added definition-loader.ts with V1 YAML schema validati… - src/resources/extensions/gsd/definition-loader.ts - src/resources/extensions/gsd/tests/definition-loader.test.ts * feat(S03/T02): Added graph.ts with YAML I/O, DAG dependency queries, im… - src/resources/extensions/gsd/graph.ts - src/resources/extensions/gsd/tests/graph-operations.test.ts * docs(S04): add slice plan * test(S04/T01): Created run-manager with createRun/listRuns, CustomWorkf… - src/resources/extensions/gsd/run-manager.ts - src/resources/extensions/gsd/custom-workflow-engine.ts - src/resources/extensions/gsd/custom-execution-policy.ts - src/resources/extensions/gsd/tests/run-manager.test.ts - src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts * feat(S04/T02): Extended engine-resolver with custom engine branch, adde… - src/resources/extensions/gsd/engine-resolver.ts - src/resources/extensions/gsd/auto/session.ts - src/resources/extensions/gsd/auto.ts - src/resources/extensions/gsd/auto-dashboard.ts * test(S04/T03): Added polymorphic custom engine dispatch path to autoLoo… - src/resources/extensions/gsd/auto/loop.ts - src/resources/extensions/gsd/auto/phases.ts - src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts * docs(S05): add slice plan * feat(S05/T01): Created custom-verification.ts with four policy handlers… - src/resources/extensions/gsd/custom-verification.ts - src/resources/extensions/gsd/custom-execution-policy.ts - src/resources/extensions/gsd/engine-resolver.ts - src/resources/extensions/gsd/tests/custom-verification.test.ts * feat(S05/T02): Created context-injector.ts with injectContext() that re… - src/resources/extensions/gsd/context-injector.ts - src/resources/extensions/gsd/custom-workflow-engine.ts - src/resources/extensions/gsd/tests/context-injector.test.ts * docs(S06): add slice plan * test(S06/T01): Wired expandIteration() into resolveDispatch() with DEFI… - src/resources/extensions/gsd/custom-workflow-engine.ts - src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts - src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts * docs(S07): add slice plan * feat(S07/T01): Added six `/gsd workflow` subcommands (new, run, list, v… - src/resources/extensions/gsd/commands/handlers/workflow.ts - src/resources/extensions/gsd/commands/catalog.ts - src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts * fix(S07/T02): Added updateProgressWidget call in custom engine path and… - src/resources/extensions/gsd/auto/loop.ts - src/resources/extensions/gsd/dashboard-overlay.ts - src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts * docs(S08): add slice plan * docs(S08/T01): Created 7-file router-pattern skill for conversational Y… - src/resources/skills/create-workflow/SKILL.md - src/resources/skills/create-workflow/workflows/create-from-scratch.md - src/resources/skills/create-workflow/workflows/create-from-template.md - src/resources/skills/create-workflow/references/yaml-schema-v1.md - src/resources/skills/create-workflow/references/verification-policies.md - src/resources/skills/create-workflow/references/feature-patterns.md - src/resources/skills/create-workflow/templates/workflow-definition.yaml * test(S08/T02): Created 3 example workflow definitions (blog-post-pipeli… - src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml - src/resources/skills/create-workflow/templates/code-audit.yaml - src/resources/skills/create-workflow/templates/release-checklist.yaml - src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts * docs(S09): add slice plan * test(S09/T01): Comprehensive e2e integration test proving the full work… - src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts * chore: remove .gsd/ artifacts from tracking (already in .gitignore) * fix(skills): resolve broken cross-references in create-workflow workflow files Paths in workflows/ referenced references/ as siblings, but they need ../references/ since they're resolved relative to the workflows/ directory. * fix: resolve typecheck failures — .ts→.js imports, MapIterator.some(), LoadedGSDPreferences unwrap, constructor args - Convert .ts import extensions to .js in source files to match codebase convention (tests keep .ts since tsconfig.extensions allows it) - Use [...idCounts.values()].some() instead of MapIterator.some() - Unwrap LoadedGSDPreferences.preferences for DispatchContext.prefs - Pass runDir to CustomExecutionPolicy constructor in tests * fix: add codeFilesChanged to mergeMilestoneToMain mock (synced with main) * fix(tests): write DEFINITION.yaml in integration tests, fix error message assertion Root cause: S06 (iterate) added DEFINITION.yaml reading to resolveDispatch(), but S04's integration tests only wrote GRAPH.yaml. The missing file threw ENOENT, swallowed by the blanket catch, causing steps to stay 'pending' silently. Fixes: - custom-engine-loop-integration: write DEFINITION.yaml in all 5 tests - custom-workflow-engine: verify test creates temp dir with definition - dev-engine-wrapper: update error regex — resolver validates activeRunDir before engine ID, so 'Unknown engine' is never reached * fix: address 13 audit findings from self-review of workflow engine PR Critical: - Fix verify-before-reconcile ordering — verify step output before marking complete in GRAPH.yaml, so failed verification triggers retry - Fix GSD_ENGINE_BYPASS kill switch — check env var in autoLoop before entering custom engine block instead of throwing from resolveEngine - Add shell-command injection guard with suspicious pattern detection High: - Add ReDoS timeout guard (5s) for iterate regex patterns - Centralize DEFINITION.yaml parsing into readFrozenDefinition() with schema: "core" restriction, eliminating 3 independent parse+cast sites - Persist activeEngineId/activeRunDir in paused-session.json and restore on resume so custom workflows survive /exit - Clean up engine state on startAuto failure in workflow run handler Medium: - Coerce params values to strings in definition-loader (YAML numbers/bools) - Add path traversal guard (resolve + startsWith) in context-injector and custom-verification content-heuristic - Use function replacer in expandIteration to prevent $ escaping bugs Low: - Fix skill docs CLI syntax (remove --param prefix) - Use resolveProjectRoot instead of process.cwd() in catalog completions - Rename isHookUnit → skipArtifactVerification for clarity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
110 lines
3.3 KiB
TypeScript
110 lines
3.3 KiB
TypeScript
/**
|
|
* dev-workflow-engine.ts — DevWorkflowEngine implementation.
|
|
*
|
|
* Implements WorkflowEngine by delegating to existing GSD state derivation
|
|
* and dispatch logic. This is the "dev" engine — it wraps the current GSD
|
|
* auto-mode behavior behind the engine-polymorphic interface.
|
|
*/
|
|
|
|
import type { WorkflowEngine } from "./workflow-engine.js";
|
|
import type {
|
|
EngineState,
|
|
EngineDispatchAction,
|
|
CompletedStep,
|
|
ReconcileResult,
|
|
DisplayMetadata,
|
|
} from "./engine-types.js";
|
|
import type { GSDState } from "./types.js";
|
|
import type { DispatchAction, DispatchContext } from "./auto-dispatch.js";
|
|
|
|
import { deriveState } from "./state.js";
|
|
import { resolveDispatch } from "./auto-dispatch.js";
|
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
|
|
// ─── Bridge: DispatchAction → EngineDispatchAction ────────────────────────
|
|
|
|
/**
|
|
* Map a GSD-specific DispatchAction (which carries `matchedRule`, `unitType`,
|
|
* etc.) to the engine-generic EngineDispatchAction discriminated union.
|
|
*
|
|
* Exported for unit testing.
|
|
*/
|
|
export function bridgeDispatchAction(da: DispatchAction): EngineDispatchAction {
|
|
switch (da.action) {
|
|
case "dispatch":
|
|
return {
|
|
action: "dispatch",
|
|
step: {
|
|
unitType: da.unitType,
|
|
unitId: da.unitId,
|
|
prompt: da.prompt,
|
|
},
|
|
};
|
|
case "stop":
|
|
return {
|
|
action: "stop",
|
|
reason: da.reason,
|
|
level: da.level,
|
|
};
|
|
case "skip":
|
|
return { action: "skip" };
|
|
}
|
|
}
|
|
|
|
// ─── DevWorkflowEngine ───────────────────────────────────────────────────
|
|
|
|
export class DevWorkflowEngine implements WorkflowEngine {
|
|
readonly engineId = "dev" as const;
|
|
|
|
async deriveState(basePath: string): Promise<EngineState> {
|
|
const gsd: GSDState = await deriveState(basePath);
|
|
return {
|
|
phase: gsd.phase,
|
|
currentMilestoneId: gsd.activeMilestone?.id ?? null,
|
|
activeSliceId: gsd.activeSlice?.id ?? null,
|
|
activeTaskId: gsd.activeTask?.id ?? null,
|
|
isComplete: gsd.phase === "complete",
|
|
raw: gsd,
|
|
};
|
|
}
|
|
|
|
async resolveDispatch(
|
|
state: EngineState,
|
|
context: { basePath: string },
|
|
): Promise<EngineDispatchAction> {
|
|
const gsd = state.raw as GSDState;
|
|
const mid = gsd.activeMilestone?.id ?? "";
|
|
const midTitle = gsd.activeMilestone?.title ?? "";
|
|
const loaded = loadEffectiveGSDPreferences();
|
|
const prefs = loaded?.preferences ?? undefined;
|
|
|
|
const dispatchCtx: DispatchContext = {
|
|
basePath: context.basePath,
|
|
mid,
|
|
midTitle,
|
|
state: gsd,
|
|
prefs,
|
|
};
|
|
|
|
const result = await resolveDispatch(dispatchCtx);
|
|
return bridgeDispatchAction(result);
|
|
}
|
|
|
|
async reconcile(
|
|
state: EngineState,
|
|
_completedStep: CompletedStep,
|
|
): Promise<ReconcileResult> {
|
|
return {
|
|
outcome: state.isComplete ? "milestone-complete" : "continue",
|
|
};
|
|
}
|
|
|
|
getDisplayMetadata(state: EngineState): DisplayMetadata {
|
|
return {
|
|
engineLabel: "GSD Dev",
|
|
currentPhase: state.phase,
|
|
progressSummary: `${state.currentMilestoneId ?? "no milestone"} / ${state.activeSliceId ?? "—"} / ${state.activeTaskId ?? "—"}`,
|
|
stepCount: null,
|
|
};
|
|
}
|
|
}
|