mirror of
https://github.com/coleam00/Archon
synced 2026-04-21 21:47:53 +00:00
13 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3b16dd6c90 |
fix(server,web,workflows): web approval gates auto-resume + reject-with-reason dialog
Fixes three tightly-coupled bugs that made web approval gates unusable:
1. orchestrator-agent did not pass parentConversationId to executeWorkflow
for any web-dispatched foreground / interactive / resumable run. Without
that field, findResumableRunByParentConversation (the machinery the CLI
relies on for resume) couldn't find the paused run from the same
conversation on a follow-up message, and the approve/reject API handlers
had no conversation to dispatch back to.
2. POST /api/workflows/runs/:runId/{approve,reject} recorded the decision
and returned "Send a message to continue the workflow." — the workflow
never actually resumed. Added tryAutoResumeAfterGate() that mirrors what
workflowApproveCommand / workflowRejectCommand already do on the CLI:
look up the parent conversation, dispatch `/workflow run <name>
<userMessage>` back through dispatchToOrchestrator. Failures are
non-fatal — the user can still send a manual message as a fallback.
3. The during-streaming cancel-check in dag-executor aborted any streaming
node whenever the run status left 'running', including the legitimate
transition to 'paused' that an approval node performs. A concurrent AI
node in the same DAG layer now tolerates 'paused' and finishes its own
stream; only truly terminal / unknown states (null, cancelled, failed,
completed) abort the in-flight stream.
Web UI: ConfirmRunActionDialog gains an optional reasonInput prop (label +
placeholder) that renders a textarea and passes the trimmed value to
onConfirm. WorkflowRunCard (dashboard) and WorkflowProgressCard (chat)
both use it for Reject now — the chat card was still on window.confirm,
which was both inconsistent with the dashboard and couldn't collect a
reason. The trimmed reason threads through to $REJECTION_REASON in the
workflow's on_reject prompt.
Supersedes #1147. @jonasvanderhaegen surfaced the root cause and shape of
the fix; that PR was 87 commits stale and pre-dated the reject-UX upgrade
(#1261 area), so this is a fresh re-do on current dev.
Tests:
- packages/server/src/routes/api.workflow-runs.test.ts — 5 new cases:
approve with parent dispatches; approve without parent returns "Send a
message"; approve with deleted parent conversation skips safely; reject
dispatches on-reject flows; reject that cancels (no on_reject) does NOT
dispatch.
- packages/core/src/orchestrator/orchestrator.test.ts — updated the two
synthesizedPrompt-dispatch tests for the new executeWorkflow arity.
Closes #1131.
Co-authored-by: Jonas Vanderhaegen <7755555+jonasvanderhaegen@users.noreply.github.com>
|
||
|
|
e7efc4155e |
fix: address review findings for on_reject and capture_response
- emit workflow_cancelled event + SSE notification on max-attempts exhaustion in executeApprovalNode (dag-executor.ts) - add missing Record<string, unknown> type annotation on metadataUpdate in orchestrator-agent.ts - wrap CLI hasOnReject DB calls in try/catch matching the else-branch pattern - add tests for $REJECTION_REASON substitution in executor-shared.test.ts - add tests for command-handler reject on_reject branch and captureResponse approve behavior - add tests for API approve/reject endpoints (on_reject routing, max attempts, captureResponse, 404/400 error cases) - add tests for workflowRejectCommand (on_reject, working_path guard, max attempts, plain cancel) - add approvalOnRejectSchema validation tests (empty prompt, out-of-range max_attempts) - update docs/approval-nodes.md: capture_response opt-in behavior, new fields table, conditional rejection behavior, on_reject lifecycle section - update docs/authoring-workflows.md: add $REJECTION_REASON and $LOOP_USER_INPUT to variable table, update Human-in-the-Loop pattern - add $REJECTION_REASON to CLAUDE.md variable substitution list |
||
|
|
8703432f4d
|
fix(web): show paused workflow runs in dashboard (#916)
* fix: show paused workflow runs in dashboard (#913) Paused runs (approval gates) were invisible in the dashboard because two hardcoded status lists predated the 'paused' status from #888. Changes: - Add 'paused' to dashboardValidStatuses in the API route handler - Add 'paused' to activeRuns filter in DashboardPage Fixes #913 * fix(tests): correct property access path in interactive field tests Tests for the interactive workflow field accessed result.workflows[0].interactive but discoverWorkflows returns WorkflowWithSource[] where each element wraps the definition, so the correct path is result.workflows[0].workflow.interactive. * fix: add paused to Zustand hydration + test paused status filter - Add 'paused' to hydration condition in DashboardPage to match activeRuns filter (consistency fix) - Add test verifying status=paused is accepted by dashboard API |
||
|
|
71f8591e90
|
feat: workflow lifecycle overhaul — path-based guards, interrupted status, resume/abandon (#871)
* feat: add interrupted to WorkflowRunStatus schema
Implements US-001 from PRD.
Changes:
- Add 'interrupted' to workflowRunStatusSchema z.enum in packages/workflows/src/schemas/workflow-run.ts
- Add 'interrupted' to workflowRunStatusSchema in packages/server/src/routes/schemas/workflow.schemas.ts
- Add interrupted: z.number() to dashboardRunsResponseSchema counts object
- Add 'interrupted' to dashboardValidStatuses in API handler
- Add interrupted: 0 to DashboardRunsResult counts interface and runtime object in packages/core/src/db/workflows.ts
* feat: update IWorkflowStore interface & DB query implementations
Implements US-002 from PRD.
Changes:
- IWorkflowStore: rename getActiveWorkflowRun → getActiveWorkflowRunByPath(workingPath)
- IWorkflowStore: drop conversationId from findResumableRun signature
- IWorkflowStore: add interruptOrphanedRuns() method
- db/workflows: add getActiveWorkflowRunByPath querying status IN ('running', 'interrupted')
- db/workflows: update findResumableRun to query by workflow_name + working_path only, include 'interrupted' status
- db/workflows: add interruptOrphanedRuns() UPDATE SET status='interrupted' WHERE status='running'
- store-adapter: wire all three new/modified methods
- executor: update call sites to use renamed methods (type-check requirement)
- tests: update all mock stores and add new tests for getActiveWorkflowRunByPath and interruptOrphanedRuns
* feat: replace staleness guard with path-based lifecycle
Implements US-003 from PRD.
Changes:
- executor.ts: remove STALE_MINUTES staleness auto-kill; replace with
status-based guard — 'running' blocks, 'interrupted' offers resume/abandon
- server/src/index.ts: replace failStaleWorkflowRuns() with
createWorkflowStore().interruptOrphanedRuns() on startup
- executor-preamble.test.ts: replace staleness detection tests with
concurrent run guard tests covering 'running' and 'interrupted' cases
* feat: command handler — /workflow status, resume, and abandon
Implements US-004. Replaces time-based stale heuristics with explicit
lifecycle commands for workflow management.
Changes:
- Remove WORKFLOW_SLOW_THRESHOLD_MS and WORKFLOW_STALE_THRESHOLD_MS constants
- Replace /workflow status with global view: lists all running+interrupted runs
across all worktrees (ID, name, working path, status, started-at)
- Add /workflow resume <id>: validates state then calls resumeWorkflowRun
- Add /workflow abandon <id>: validates state then calls failWorkflowRun
- Add statuses[] filter to listWorkflowRuns for IN (...) queries
- Update /workflow help text and default case usage string
- Update /status command to remove stale warning that referenced removed constants
- Replace old /workflow status tests with new behavior coverage
- Add /workflow resume and /workflow abandon test coverage
* feat: CLI workflow status, resume, and abandon subcommands
Implements US-005 from PRD.
Changes:
- Implement workflowStatusCommand: lists all running+interrupted runs with ID, name, path, status, age; supports --json flag
- Add workflowResumeCommand: validates run state then calls resumeWorkflowRun
- Add workflowAbandonCommand: validates run state then calls failWorkflowRun('Abandoned by user')
- Replace findLastFailedRun usage in --resume path with findResumableRun(workflowName, cwd)
- Wire resume/abandon subcommands in cli.ts
- Update tests: replace "not implemented" test with status/resume/abandon coverage
* feat: Web UI interrupted status badge and dashboard support
Implements US-006 from PRD.
Changes:
- api.generated.d.ts: add 'interrupted' to WorkflowRunStatus enum and DashboardRunsResponse.counts
- api.ts: add interrupted field to DashboardCounts interface
- WorkflowExecution.tsx: add 'interrupted' to TERMINAL_STATUSES; add amber color to StatusBadge
- WorkflowRunCard.tsx: add amber dot and badge for interrupted status
- StatusSummaryBar.tsx: add 'interrupted' to STATUS_CHIPS filter list
- DashboardPage.tsx: include interrupted in activeRuns filter and counts default
* refactor: remove dead timer-based workflow staleness code
Implements US-007 from PRD.
Changes:
- Remove findLastFailedRun() from db/workflows.ts (CLI path unified on findResumableRun in US-005)
- Remove failStaleWorkflowRuns() from db/workflows.ts (replaced by interruptOrphanedRuns in US-002)
- Remove IDatabase import from db/workflows.ts (no longer needed)
- Remove failStaleWorkflowRuns tests from db/workflows.test.ts
grep -r 'STALE' packages/ (workflow-timer variant), grep -r 'findLastFailedRun' and
grep -r 'failStaleWorkflowRuns' all return zero matches.
* fix: address review feedback — truncated IDs, resume semantics, type safety
- Use full UUIDs in resume/abandon command suggestions (was .slice(0, 8))
- Add completed_at to interruptOrphanedRuns for correct duration metrics
- Fix resume commands: mark interrupted→failed to unblock path guard,
let next workflow invocation auto-resume via findResumableRun
- Collapse dual status/statuses fields into status?: T | T[]
- Extract TERMINAL/RESUMABLE/ACTIVE_WORKFLOW_STATUSES constants
- Add explicit else-if for interrupted status in executor path guard
- Add structured logging to CLI workflow commands
- Restore conversationId to cmd.workflow_status_failed log
- Add tests: listWorkflowRuns statuses filter, interrupted auto-resume,
DB error handling for resume/abandon
- Update docs: commands-reference, cli-user-guide, authoring-workflows, CLAUDE.md
* refactor: simplify CLI commands and status filter logic
- Extract getRunOrThrow helper for shared run lookup pattern
- Use WorkflowRun[] instead of Awaited<ReturnType<...>>
- Remove single-item special case in listWorkflowRuns (IN works for all)
- Use ?? instead of || for null-coalescing consistency
- Remove unused ACTIVE_WORKFLOW_STATUSES constant
- Add inline comment on completed_at for interrupted runs
* fix: handle SQLite string dates in formatAge
SQLite returns started_at as a string, not a Date object.
formatAge now accepts Date | string and converts accordingly.
Found during E2E testing against real SQLite database.
* feat: UX improvements — real resume, dashboard actions, cleanup command
- CLI resume now actually re-executes the workflow (calls workflowRunCommand
with --resume internally instead of just flipping DB status)
- Remove truncated IDs from executor guard messages (full ID in commands only)
- Add Resume/Abandon/Delete buttons to dashboard workflow run cards
- Add Delete button to history table rows
- Add API endpoints: POST resume, POST abandon, DELETE workflow run
- Add CLI workflow cleanup command (deletes terminal runs older than N days)
- Add deleteWorkflowRun and deleteOldWorkflowRuns DB functions
* refactor: simplify API handlers, dashboard actions, and log conventions
- Use RESUMABLE/TERMINAL_WORKFLOW_STATUSES constants in API handlers
(was inline string checks diverging from CLI/command-handler)
- Extract makeRunAction helper in DashboardPage (4 identical handlers → 1)
- Fix log event names to use domain prefix convention (api.workflow_run_*)
- Use Ban icon for Abandon to distinguish from Cancel's XCircle
- Use instanceof Date guard in formatAge for clarity
- Add comment on delete handler's active-status guard
* refactor: simplify workflow lifecycle — remove interrupted, single resume path
Rework the primitives for a clean foundation:
Status model: 5 statuses (pending, running, completed, failed, cancelled).
Remove 'interrupted' entirely — server restart now marks orphaned runs
as 'failed' directly (with metadata.failure_reason = 'server_restart').
Resume model: one path. The executor's implicit findResumableRun
detects prior failed runs and skips completed nodes. The CLI --resume
flag reuses the prior run's worktree but lets the executor handle
node-skipping (no more preCreatedRun bypass). Chat /workflow resume
tells the user to re-invoke (auto-resume kicks in).
Path guard: only blocks 'running' status (was running + interrupted).
Guards always run regardless of preCreatedRun.
Cancellation: generalized from status === 'cancelled' to
status !== 'running' at all 3 check points (streaming, loop iterations,
DAG layers). Ready for future 'paused' status with zero changes.
- interruptOrphanedRuns → failOrphanedRuns
- Remove preCreatedRun bypass from CLI --resume path
- Generalize 3 cancellation check points in dag-executor
- Update all API endpoints, command handlers, UI components
- Update all tests and documentation
* fix: cancel/complete race, abandon semantics, UTC dates
- Fix cancel/complete race condition: dag-executor now checks DB status
before calling completeWorkflowRun or failWorkflowRun, preventing a
cancel during the final layer from being overwritten to completed
- Abandon uses cancelWorkflowRun instead of failWorkflowRun, so
abandoned runs don't get auto-resumed by findResumableRun
- Fix formatAge UTC bug: SQLite dates without Z suffix now parsed as UTC
* fix: address PR review — SQL safety, transactions, error handling, docs, tests
- Validate olderThanDays before SQL interpolation in deleteOldWorkflowRuns
- Wrap multi-statement deletes in transactions (deleteOldWorkflowRuns, deleteWorkflowRun)
- Fix deleteWorkflowRun error double-wrap (don't re-wrap "not found" errors)
- Handle null getWorkflowRunStatus in DAG executor (treat as deleted, abort)
- Fix mock name mismatch: interruptOrphanedRuns → failOrphanedRuns in 3 test files
- Fix default mock getWorkflowRunStatus to return 'running' instead of null
- Add NaN guard to formatAge (returns 'unknown' on unparseable dates)
- Fix stale 'interrupted' references in route summary and delete comment
- Include working path in /workflow resume response
- Align deleteOldWorkflowRuns return type to { count } for consistency
- Document workflow cleanup command in CLAUDE.md, CLI user guide, commands reference
- Document new API endpoints (resume, abandon, delete) in CLAUDE.md
- Add tests for deleteOldWorkflowRuns, deleteWorkflowRun, workflowCleanupCommand
- Fix workflowAbandonCommand test to assert cancelWorkflowRun call
* refactor: simplify code per review — extract helper, cleaner date parsing, consistent guards
- Extract duplicated status-check blocks into skipIfStatusChanged helper in dag-executor
- Simplify formatAge to single-pass date parsing with Z suffix (ISO 8601)
- Use TERMINAL_WORKFLOW_STATUSES constant in delete route guard
- Rename cancelError → actionError in DashboardPage (covers 4 actions now)
- Fix merge conflict: add IDatabase import, getRunningWorkflows from dev
- Fix api.conversations.test.ts: add missing workflow mocks, fix Hono → OpenAPIHono
* fix: address review findings — double-rollback, missing guards, log context, tests
- Fix double-rollback in deleteWorkflowRun by removing inner rollback()
call and letting the outer catch handle it
- Add terminal-status guard inside deleteWorkflowRun itself, not just in
the route handler, to prevent deletion of running workflows
- Add rollback failure logging to the rollback() helper
- Add runId to error logs in resume/abandon/delete API route handlers
- Add workingPath to getActiveWorkflowRunByPath error log
- Add workflowRunId to dag-executor status-check warn logs
- Wrap workflowRunCommand in try/catch in workflowResumeCommand with
structured logging and null guard for user_message
- Clean up stale 'interrupted' references in JSDoc
- Fix missing / prefix on workflow cleanup in commands-reference.md
- Add API route tests for POST /resume, POST /abandon, DELETE /:runId
* refactor: apply code simplifications from review
- Replace fragile startsWith string matching in deleteWorkflowRun catch
with a typed WorkflowRunGuardError class
- Reorder listWorkflowRuns placeholder generation: capture startIdx
before pushing values for clarity
- Replace curried makeRunAction factory in DashboardPage with a plain
runAction helper function
- Move skipIfStatusChanged helper definition before its call sites in
dag-executor to match reading order
|
||
|
|
1e0636e0c7
|
refactor(tests): Zod-based test factories + mock deduplication (step 3) (#856)
* refactor(tests): Zod-based test factories + mock deduplication (step 3)
Add makeTestWorkflow/makeTestWorkflowList/makeTestWorkflowRun factories
in @archon/workflows/test-utils and shared mock factories in
packages/server/src/test/workflow-mock-factories.ts. Replace ~45 inline
WorkflowDefinition fixture objects across 6 test files and deduplicate
4 identical mock.module blocks repeated across 5 server test files.
* fix(tests): complete fixture conversion + review fixes
- Convert remaining ~28 inline workflow fixtures in CLI workflow.test.ts
and command-handler.test.ts to use makeTestWorkflow factory
- Remove unused makeTestWorkflowRun (YAGNI — MockWorkflowRun uses
string dates from DB layer, incompatible with Zod Date type)
- Use WorkflowLoadResult type in mock factory instead of unknown[]
- Add comment documenting makeCommandValidationMock as always-true stub
- Document api.workflow-runs.test.ts reliance on Hono URL normalization
- Rephrase test-utils docstring to avoid over-claiming cast scope
- Extract TestWorkflowOverrides named type for readability
* fix(tests): address review — valid ParseResult type, isValidCommandName coverage, simplify overrides
- makeLoaderMock now returns a valid ParseResult discriminant (error arm)
instead of the impossible { workflow: null, error: null } state
- Add test for isValidCommandName rejection in api.workflow-runs.test.ts
to cover the 400 branch that was untested after mock deduplication
- Simplify TestWorkflowOverrides: nodes as unknown[] (matches z.any()),
inline parsed variable, remove redundant Record casts in makeDefaultsMock
* refactor(tests): add mockAllWorkflowModules() to deduplicate mock.module calls
Replace 4 identical mock.module('@archon/workflows/...') lines in each of
4 server test files with a single mockAllWorkflowModules() call.
|
||
|
|
53a987287b
|
refactor(workflows): eliminate barrel exports — direct subpath imports (step 2.3) (#849)
* refactor(workflows): eliminate barrel exports — direct subpath imports (step 2.3) (#846) Delete packages/workflows/src/index.ts and replace the `"."` barrel entry in package.json exports with an explicit 17-entry subpath map. All 13 source files and 12 test files across @archon/core, @archon/cli, and @archon/server now import from specific subpaths (e.g. @archon/workflows/executor, @archon/workflows/schemas/workflow) instead of the opaque barrel. Test mock.module() calls are split per-subpath so spies target the same module reference that the handler under test imports from. Updates CLAUDE.md import convention docs to show direct-subpath-only examples. Fixes #846 * style: auto-fix prettier formatting in auth-service/server.js * docs: remove stale index.ts entry from workflows directory structure packages/workflows/src/index.ts was deleted in this PR but the CLAUDE.md directory tree still listed it. Remove the stale entry. * fix: address review findings — trim unused exports, fix docs - Remove 5 unused exports from package.json (executor-shared, dag-executor, model-validation, utils/variable-substitution, schemas barrel) — YAGNI - Fix CLAUDE.md tree character (├── → └── on utils/, last child) - Remove redundant barrel wrong-example block from CLAUDE.md (compiler already enforces this since there's no "." export entry) - Clarify @archon/web import prohibition scope in CLAUDE.md - Update docs/cli-developer-guide.md: stale discoverWorkflows → discoverWorkflowsWithConfig, barrel refs → direct subpaths |
||
|
|
c4e4fab845
|
feat(web): make workflow builder Node Library panel resizable (#837)
* feat(web): make workflow builder Node Library panel resizable Add drag handle to the Node Library panel's right edge, allowing users to resize it between 160px and 400px. Width persists in localStorage across sessions. Closes #834. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(web): fix lint and format issues in WorkflowBuilder and auth-service - Add explicit `: void` return type to useEffect cleanup function - Run Prettier on auth-service/server.js (pre-existing format issue) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): fix pre-existing test failures in workflows.test and path-validation.test - Remove obsolete `current_step_index` test from workflows.test (field no longer exists in WorkflowRun type) - Fix mock pollution caused by unconsumed mockResolvedValueOnce in updateWorkflowRun tests - Add ARCHON_DOCKER cleanup in path-validation.test beforeEach to prevent Docker env from interfering with path assertions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address review findings for PR #837 Fixed: - Use lazy useState initializer for localStorage read in NodeLibraryPanel (avoids redundant localStorage.getItem calls on every render) - Wrap localStorage.getItem in try-catch to handle private/restricted browsers - Wrap localStorage.setItem in try-catch to handle QuotaExceededError - Add ARIA role/orientation/label to drag handle for accessibility - Remove stale current_step_index from WorkflowRun mock fixtures in 3 test files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Archon <archon@dynamous.ai> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
95574bd7e9
|
refactor(api): migrate remaining routes to @hono/zod-openapi (step 1.1) (#836)
* refactor(api): migrate remaining routes to @hono/zod-openapi (step 1.1) - Create conversation.schemas.ts with 9 Zod schemas for conversation/message routes - Create codebase.schemas.ts with 5 Zod schemas for codebase routes - Add 14 workflowRun schemas to workflow.schemas.ts - Migrate 19 plain routes to registerOpenApiRoute(createRoute(...), handler) - Update 4 test files for Zod validation behavior (validationErrorHook, assertion updates) All JSON API routes now use the typed openapi() wrapper. OpenAPI spec at /api/openapi.json covers all JSON endpoints. SSE routes intentionally excluded. Closes #831 * fix: address MEDIUM review findings from PR #836 - Replace manual c.req.json() re-parses in sendMessageRoute and runWorkflowRoute with c.req.valid('json') (Zod already validates before handler runs; manual parse was redundant and swallowed errors) - Add z.string().min(1) to sendMessageBodySchema to enforce non-empty message invariant at the schema level instead of ad-hoc in handler - Move isValidCommandName guard outside try block in runWorkflowRoute so invalid names return 400 (not 500 via run_workflow_failed) - Fix makeApp() return type from Hono to OpenAPIHono in three test files - Update addCodebaseBodySchema JSDoc to match permissive schema (constraint is enforced by handler, not schema) - Add GET /api/workflows/runs/by-worker/:platformId tests (found/not-found) * fix: complete Zod migration for all route handlers - Replace manual c.req.json() in createConversation, updateConversation, addCodebase, validateWorkflow, and saveWorkflow handlers with getValidatedBody() helper that centralizes the .valid('json') cast - Add getValidatedBody(c, schema) helper to eliminate repeated unsafe casts — keeps the pattern searchable and type-safe - Migrate sendMessageRoute and runWorkflowRoute to use getValidatedBody() - Add .strict() to createConversationBodySchema to reject unknown fields (e.g. conversationId) at the Zod layer instead of in handler code - Add .refine() to addCodebaseBodySchema enforcing url/path mutual exclusion at schema level — removes redundant handler validation - Add .min(1) to updateConversationBodySchema.title for consistency with sendMessageBodySchema.message - Normalize all error responses to use apiError() helper instead of raw c.json({ error: ... }) for consistent error format - Remove stale route registration order comment - Fix missing validationErrorHook in conversationId rejection test |
||
|
|
158f6d5aa8
|
refactor(api): Zod schemas + @hono/zod-openapi + frontend decoupling (#828)
* refactor(api): Zod schemas + @hono/zod-openapi as single source of truth (step 1) - Install @hono/zod-openapi; swap Hono → OpenAPIHono with defaultHook - Add Zod schemas for workflow/command API routes (common, workflow, conversation scaffolding) - Migrate 6 workflow/command routes to .openapi(); serve /api/openapi.json - Create packages/web/src/lib/workflow-types.ts with frontend-local type mirrors - Remove @archon/workflows from web package.json; swap all imports in 10 web files - Update CLAUDE.md with Zod schema conventions Closes #823 * fix: address review findings for PR #828 - Add workflowLoadErrorSchema and errors field to workflowListResponseSchema so GET /api/workflows schema matches the actual handler response - Fix 500 handler in GET /api/workflows to use apiError() instead of returning { workflows: [], warning: } which contradicted errorSchema - Improve defaultHook to return per-field Zod error messages using result.error.issues instead of opaque result.error.message - Clarify workflowListItemSchema comment as Step 2 scaffolding - Add GET /api/workflows to CLAUDE.md API Endpoints section * fix: address review findings from multi-agent PR review - Remove unused workflowListItemSchema (YAGNI, no callers) - Remove conversation.schemas.ts scaffolding (defer to #831) - Fix openapi() wrapper comment: output is NOT validated at runtime - Rename openapi() → registerOpenApiRoute() for clarity - Unify definition body schema to z.record(z.unknown()) (was inconsistent) - Constrain WorkflowLoadError.errorType to z.enum - Extract defaultHook to shared openapi-defaults.ts - Extract jsonError() helper for repeated error response shapes - Move route configs to module scope (pure config, no closure deps) - Deduplicate workflowDefinitionSchema comment - CLAUDE.md: add /api/openapi.json, update @archon/server to OpenAPIHono, add @archon/web import caveat, clarify wrapper convention |
||
|
|
ef04321eef
|
refactor(workflows)!: remove sequential execution mode, DAG becomes sole format (#805)
* refactor(workflows)!: remove sequential execution mode, DAG becomes sole format Remove the steps-based (sequential) workflow execution mode entirely. All workflows now use the nodes-based (DAG) format exclusively. - Convert 8 sequential default workflows to DAG format - Delete archon-fix-github-issue sequential (DAG version absorbs triggers) - Remove SingleStep, ParallelBlock, StepWorkflow types and guards - Gut executor.ts from ~2200 to ~730 lines (remove sequential loop) - Remove step_started/completed/failed and parallel_agent_* events - Remove logStepStart/Complete and logParallelBlockStart/Complete - Delete SequentialEditor, StepProgress, ParallelBlockView components - Remove sequential mode from workflow builder and execution views - Delete executor.test.ts (4395 lines), update ~45 test fixtures - Update CLAUDE.md and docs to reflect DAG-only format BREAKING CHANGE: Workflows using `steps:` format are no longer supported. Convert to `nodes:` (DAG) format. The loader provides a clear error message directing users to the migration guide. * fix: address review findings — guard errors, remove dead code, add tests - Guard logNodeSkip/logWorkflowError against filesystem errors in dag-executor - Move mkdir(artifactsDir) inside try-catch with user-friendly error - Remove startFromStep dead parameter from executeWorkflow signature - Remove isDagWorkflow() tautology and all callers (20+ sites) - Remove dead BuilderMode/mode state from frontend components - Remove vestigial isLoop, selectedStep, stepIndex, step_index fields - Remove "DAG" prefix from user-facing resume/error messages - Fix 5 stale docs (README, getting-started, authoring-commands, web adapter) - Update event-emitter tests to use node events instead of removed step events - Add executor-shared.test.ts (12 tests) for substituteWorkflowVariables - Add executor.test.ts (11 tests) for concurrent-run, model resolution, resume * fix(workflows): add migration guide, port preamble tests, improve error message - Add docs/sequential-dag-migration-guide.md with 3 conversion patterns (single step, chain with clearContext, parallel block) and a Claude Code migration command for automated conversion - Update loader error message to point to migration guide and include ready-to-run claude command - Port 8 preamble tests from deleted executor.test.ts to new executor-preamble.test.ts: staleness detection (3), concurrent-run guard (3), DAG resume (2) Addresses review feedback from #805. * fix(workflows): update loader test to match new error message wording * fix: address review findings — fail stuck runs, remove dead code, fix docs - Mark workflow run as failed when artifacts mkdir fails (prevents 15-min concurrent-run guard block) - Remove vestigial totalSteps from WorkflowStartedEvent and executor - Delete dead WorkflowToolbar.tsx (369 lines, no importers) - Remove stepIndex prop from StepLogs (always 0, label now "Node logs") - Restore cn() in StatusBar for consistent conditional classes - Promote resume-check log to error, add errorType to failure logs - Remove ghost $PLAN/$IMPLEMENTATION_SUMMARY from docs (never implemented) - Update workflows.md rules to DAG-only format - Fix migration guide trigger_rule example - Clean up blank-line residues and stale comments * fix: resolve rebase conflicts with #729 (forkSession) and #730 (dashboard) - Remove sequential forkSession/persistSession code from #729 (dead after sequential removal) - Fix loader type narrowing for DagNode context field - Update dashboard components from #730 to use dagNodes instead of steps - Remove WorkflowStepEvent/ParallelAgentEvent from dashboard SSE hook |
||
|
|
9c931419a0
|
fix: prevent worktree sharing across conversations and web workers (#716)
* fix: prevent worktree sharing across conversations and web workers Bug 1: All chat adapters (Slack, Discord, Telegram, Web) passed no isolationHints, causing workflowId to default to empty string. This made every conversation on the same codebase resolve to the same worktree via findReusable(), corrupting each other's work. Fix: Pass conversationId as workflowId in isolation hints for all chat adapters. Each conversation now gets its own worktree. Bug 2: Web background workflows (dispatchBackgroundWorkflow) inherited the parent conversation's cwd directly without resolving their own isolation. Multiple concurrent workflows in the same web chat would write to the same worktree simultaneously. Fix: Each background worker now runs validateAndResolveIsolation with its unique worker conversation ID as workflowId, getting its own isolated worktree. Falls back to parent cwd if isolation fails. * fix: make worker isolation fatal + update docs Address review findings from PR #716: - Make isolation failure fatal for web workers — never fall back to shared parent worktree. IsolationBlockedError re-thrown to abort. - Persist workerCwd to conversation DB row after isolation resolves. - Restore cwd: ctx.cwd default in initial worker conversation create. - Log warn when getCodebase() returns null for non-null codebaseId. - Fix log event name to orchestrator.worker_* convention. - Add codebaseId and conversationId to error log context. Docs: - Update entry points diagram (add Slack, Discord, Telegram, Web, CLI). - Replace stale DB schema with current isolation_environments table. - Replace "Planned Architecture (Phase 2.5+)" with "Isolation by Adapter" section documenting the now-implemented per-conversation isolation. - Update Key Files table with current file paths and new entries. |
||
|
|
ede77c91f0
|
refactor: decouple tool call persistence from web adapter (#642) (#652)
Move tool call persistence from WebAdapter's MessagePersistence to the workflow executor via workflow_events table. Tool calls are now persisted as 'tool_called' events in all three execution paths (sequential, loop, DAG) using the existing fire-and-forget pattern, making them visible in the web UI regardless of which adapter initiated the workflow. - Add 'tool_called' to WorkflowEventType union - Persist tool events in executor (sequential + loop) and dag-executor - Update WorkflowExecution to extract tool events from workflow_events - Update WorkflowLogs to render tool calls from events instead of message metadata - Simplify WebAdapter.sendStructuredEvent (remove persistence, keep SSE) - Remove appendToolCall/finalizeRunningTools from MessagePersistence - Add tests for tool_called event persistence across all execution modes |
||
|
|
7815e308d5 |
feat: comprehensive test coverage across all packages (#645)
Add 500+ new tests across 8 packages, filling critical coverage gaps: **@archon/web** (NEW — 47 tests) - format.ts: ensureUtc, formatDuration, formatDurationMs, formatStarted - message-cache.ts: LRU eviction, getCachedMessages, setSendInFlight **@archon/core** (179 new tests) - orchestrator-agent.ts: parseOrchestratorCommands, filterToolIndicators, stream/batch modes - handlers/clone.ts: URL normalization, SSH→HTTPS, GH_TOKEN injection, command auto-loading - utils/error-formatter.ts: all error categories, security filtering - db/adapters/postgres.ts: query, withTransaction, dialect helpers **@archon/server** (91 new tests) - api.codebases: POST/GET/DELETE codebase CRUD - api.messages: POST message, GET history, PATCH conversation - api.health: health, db health, concurrency, config, commands - api.workflow-runs: run/cancel/list/get workflow executions, dashboard **@archon/workflows** (141 new tests) - event-emitter.ts: subscribe, emit, listener isolation, run mapping - validation-parser.ts: markdown table parsing, result cells, edge cases - types.ts: all type guards (isParallelBlock, isDagWorkflow, isBashNode, etc.) - command-validation.ts: path traversal, dotfiles, empty names **@archon/isolation** (42 new tests) - WorktreeProvider: destroy(), get(), list(), adopt(), healthCheck() - Orphan directory cleanup with Windows path fix **@archon/adapters** (24 new tests) - Discord: ensureThread, thread creation, mention stripping, history - Telegram: getConversationId, sendFormattedChunk fallback **@archon/cli** (8 new tests) - chatCommand: message streaming, conversation ID generation Also updates package.json test scripts to include all new files with proper mock.module isolation batching. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |