Handle the case where Claude Code exits without producing a result line
(timeout, OOM, signal kill). Previously returned null and threw an error;
now returns incomplete result with best-effort output extraction.
Changes:
- Add "incomplete" as new ClaudeCodeResultSubtype value
- Extract output from last assistant turn when no result line exists
- Enhanced error messages distinguish incomplete vs unparseable output
- Store incomplete results in CAS with appropriate metadata
- Add 10 comprehensive test cases for incomplete result handling
Fixes#574
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This resolves issue #573 by moving uwf's CAS directory from
~/.uncaged/workflow/cas/ to the shared ~/.uncaged/json-cas/ location.
Changes:
- Added getGlobalCasDir() function with UNCAGED_CAS_DIR support
- Updated createUwfStore() to use global CAS directory
- Added comprehensive test coverage (11 new tests)
- Updated all existing tests for environment isolation
- Updated documentation (CLAUDE.md, README.md)
Benefits:
- Cross-tool visibility: json-cas CLI can read uwf-created nodes
- Schema sharing: both tools access same schema registry
- Future-proofing: enables json-cas render/verbose for uwf data
Fixes#573
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This resolves issue #573 by moving uwf's CAS directory from
~/.uncaged/workflow/cas/ to the shared ~/.uncaged/json-cas/ location.
Changes:
- Added getGlobalCasDir() function that respects UNCAGED_CAS_DIR env var
- Updated createUwfStore() to use the global CAS directory
- Updated all tests to set UNCAGED_CAS_DIR for test isolation
- Added comprehensive test suite for global CAS functionality
- Updated documentation (CLAUDE.md, README.md) to reflect new architecture
Benefits:
- Cross-tool visibility: json-cas CLI can now read uwf-created nodes
- Schema sharing: both tools access the same schema registry
- Future-proofing: enables json-cas render/verbose features for uwf data
Workflow metadata (threads.yaml, registry.yaml, history.jsonl) remains in
~/.uncaged/workflow/ as intended.
All tests pass. No breaking changes to existing functionality.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store the fully assembled prompt sent to each agent in CAS as a text
node, referenced from StepNodePayload.assembledPrompt. This enables
exact reproduction of what the agent received for debugging hallucinations.
Changes:
- workflow-protocol: StepRecord + STEP_NODE_SCHEMA add assembledPrompt field
- workflow-util-agent: AgentRunResult includes assembledPrompt, run.ts stores it
- workflow-util-agent: schemas register TEXT_SCHEMA for prompt storage
- workflow-agent-claude-code: return assembled prompt from buildClaudeCodePrompt
- workflow-agent-hermes: return assembled prompt from buildHermesPrompt
- workflow-agent-builtin: return empty prompt (no prompt assembly)
- cli-workflow: step read --prompt renders the stored prompt
- All test fixtures updated for new field
Legacy steps without assembledPrompt show 'Prompt not recorded' message.
小橘 🍊
- Enhanced Biome config with test file override for noConsole
- Applied Biome auto-fixes (8 files: formatting, template literals, optional chains)
- Updated all package repository URLs to git.shazhou.work/uncaged/workflow.git
- Added workflow-agent-claude-code to publish order in scripts/publish-all.mjs
- Added --ignore-scripts flag to publish command to bypass prepublishOnly guard
- Installed vitest in root devDependencies for test infrastructure
- Created vitest.config.ts for all 8 packages with passWithNoTests: true
- Fixed 3 test files to use vitest imports instead of bun:test
- Added test and test:ci scripts to packages missing them
- Added missing build step to .gitea/workflows/ci.yml
- Renamed CI job from 'test' to 'check' for clarity
- Created workflows/solve-issue.yaml with TDD-driven issue resolution workflow
- Registered solve-issue workflow with uwf (hash: 084YVM60BR8G6)
- Added packageManager: bun@1.3.14 to root package.json
- Added preinstall guard to block npm/pnpm/yarn
- Added prepublishOnly guard to root and all 7 public packages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When mustache variables in edge prompts resolve to empty strings (because
upstream output lacks the fields), the engine now returns a Result.error
instead of passing an empty --prompt to the agent.
- evaluate.ts: check rendered prompt is non-empty after mustache.render()
- run.ts: improve parseArgv error message for empty --prompt
- Export parseArgv for testability
- Add 7 tests covering all cases from the spec
Add comprehensive tests verifying that `uwf step show` produces valid
JSON output even when step detail nodes contain control characters
(newlines, tabs, carriage returns, etc.) in tool call args and content
fields.
Tests cover:
- Basic control characters (newlines, tabs, CR+LF)
- Backslashes and quotes
- Unicode control characters (U+0001-U+001F)
- Nested CAS refs with control characters
- Large steps with multiple tool calls
- Empty/null values
- YAML output format (unaffected by escaping)
The tests confirm that JSON.stringify() already handles control
character escaping correctly when serializing JavaScript objects
to JSON. No code changes needed - these tests serve as regression
guards to ensure the behavior remains correct.
Fixes#557
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ThreadStatus type to workflow-protocol
- Update StepOutput type to include status field alongside deprecated done/background fields
- Implement status computation in cmdThreadShow (idle/running/completed/cancelled)
- Update cmdThreadStepOnce to include status in return values
- Add comprehensive test suite for thread show status scenarios
Fixes#559
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exposes the existing cwd parameter from cmdThreadStart to the CLI layer,
allowing users to specify a custom working directory for thread execution.
- Added --cwd <path> option to uwf thread start
- Option defaults to process.cwd() when not provided
- Added comprehensive test suite with 4 test cases
- All 328 tests in cli-workflow package pass
Fixes#561
Implement thread-level and edge-level working directory management:
- Thread-level cwd (required, defaults to process.cwd())
- Captured at uwf thread start time
- Stored in StartNodePayload
- Inherited by all steps unless overridden
- Edge-level location (optional, supports mustache templates)
- New location: string | null field on Target type
- Resolved by moderator using previous step's output
- Example: location: "{{{repoPath}}}"
- Step audit trail
- Each StepNodePayload records actual cwd where agent executed
Changes:
- workflow-protocol: Add cwd to StartNodePayload & StepRecord, location to Target
- cli-workflow: Thread start captures cwd, moderator resolves location, step execution uses resolved cwd
- workflow-util-agent: Expose cwd in agent context
Tests:
- Protocol type tests (3 scenarios)
- Moderator location resolution tests (5 scenarios)
- Thread-location integration tests (3 scenarios)
All tests pass. Build successful. Backward compatible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add agentOverrides (minDepth 3) and modelOverrides (minDepth 2) to VALID_CONFIG_KEYS
- Support per-key minDepth instead of hardcoded 3
- No knownFields for either key (sub-keys are user-defined)
- Add 5 new tests covering valid/invalid paths for both keys
小橘 <xiaoju@shazhou.work>
- Add engines.bun >= 1.0.0 to workflow-agent-hermes package.json
- Update README to explain uwf-hermes is an adapter, not hermes itself
- Update uwf setup --agent help text to mention adapter concept
- Add tests for engines field, shebang, and adapter docs
- Patch uncaged-workflow-cli skill with Agent Adapters section
Adds 'uwf skill user' command for agents/humans using the uwf CLI.
Covers setup, workflow management, thread lifecycle, step operations,
CAS queries, logging, and global options with a Quick Start guide.
Refs #538
Adds 'uwf skill actor' command for agents executing workflow roles.
Covers the two things an actor needs to know:
1. Frontmatter output protocol (status field, schema-defined fields)
2. CAS operations (put, get, refs, walk, merkle DAG pattern)
Refs #540
- Remove unnecessary Promise.resolve() wrappers (sync function)
- Use try/finally for db.close() instead of manual close at each exit
- Flatten nested try/catch
Follow-up to #535 review nits.
小橘 🍊
When sessions.write_json_snapshots is disabled, Hermes only writes to
state.db (SQLite). loadHermesSession now falls back to reading from
~/.hermes/state.db when the JSON file is missing.
- Add getHermesDbPath() and loadHermesSessionFromDb() functions
- Use bun:sqlite with readonly mode, try-catch for graceful errors
- JSON file still takes priority (fast path)
- Filter messages to user/assistant/tool roles
- Convert unix timestamps to ISO 8601 strings
This commit addresses three related issues in the CLI config and setup commands:
1. Issue #531: Fix config list apiKey masking
- maskApiKeys() now checks for 'apiKey' instead of 'apiKeyEnv'
- Updated tests to use apiKey field throughout
2. Issue #532: Add config set key validation
- Reject unknown top-level keys with helpful error messages
- Reject unknown nested fields in providers/models/agents
- Reject incomplete paths and nested paths on scalar keys
- Added VALID_CONFIG_KEYS schema and validateConfigKey() function
3. Issue #533: Fix agent name double-prefix in setup
- mergeConfig() now uses _agentNameFromBinary() to normalize agent names
- 'uwf-hermes' input now produces 'hermes' key with 'uwf-hermes' command
- Added tests for prefixed agent names
All tests passing, no regressions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Breaking change: Store API keys directly in config.yaml instead of
environment variable names.
## Changes
### @uncaged/workflow-protocol
- Change ProviderConfig.apiKeyEnv: string → apiKey: string
- Update README to reflect new type
### @uncaged/workflow-util-agent
- extract.ts: Remove dotenv loading, use providerEntry.apiKey directly
- storage.ts: Update normalizeProviders to validate apiKey field
- Update error messages to reference apiKey instead of apiKeyEnv
### @uncaged/cli-workflow
- setup.ts: Write actual API key to config.yaml, not .env
- Remove apiKeyEnvName(), loadEnvFile(), saveEnvFile() functions
- Remove getEnvPath() function
- Update cmdSetup to not return envPath in result
- Update README to reflect config.yaml stores API keys
- Fix setup-validate.test.ts to not expect envPath in result
## Verification
- ✅ bun run build passes
- ✅ All tests pass (260/260 in cli-workflow, 55/55 in util-agent)
- ✅ bun run check passes (only pre-existing warnings)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add configuration management commands to uwf CLI:
- uwf config list: display all config values (masks API keys)
- uwf config get <key>: retrieve specific value using dot notation
- uwf config set <key> <value>: update config value with auto-creation
Implementation:
- New file packages/cli-workflow/src/commands/config.ts with helper functions
- Comprehensive test coverage (32 tests) in config.test.ts
- Supports nested path navigation via dot notation
- Auto-creates intermediate objects when setting new paths
- Masks apiKeyEnv values in list output for security
Resolves#526
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- moderator-reference: use nested map graph format matching evaluate.ts
- yaml-reference: use goal/procedure/output/capabilities/frontmatter fields
matching actual WorkflowPayload, not fabricated system/outputSchema
- skill.test.ts: replace hardcoded absolute path with __dirname-relative
- skill.test.ts: assert 'frontmatter' instead of 'outputSchema'
Closes#519
The ACP protocol's tool_call updates only carry a display title (not a
structured tool name) and omit rawInput for polished tools, making the
reconstructed messages unusable for step read/show.
Changes:
- hermes.ts: storePromptResult reads ~/.hermes/sessions/session_{id}.json
via loadHermesSession() instead of using ACP-reconstructed messages
- acp-client.ts: strip message/tool-call collection logic, keep only
text chunk accumulation for final response extraction
- step.ts: TurnData gains role + toolCalls fields; formatTurnBody
renders them in step read markdown output
- README: document sessions.write_json_snapshots requirement
Two fixes for 'uwf thread start solve-issue' failures:
1. json-cas 0.5.2 (npm) was missing oneOf in ALLOWED_SCHEMA_KEYS.
Published json-cas 0.5.3 with the fix, bumped all packages to ^0.5.3.
2. Semantic validator only recognized oneOf-based multi-exit schemas.
Roles using $status with enum (e.g. enum: [approved, rejected]) were
incorrectly treated as single-exit. Added isEnumMultiExit() support.
Changes:
- validate-semantic.ts: isEnumMultiExit(), getEnumStatuses(), checkSingleExitMustache()
- All package.json: @uncaged/json-cas ^0.5.2 → ^0.5.3
- validate-semantic.test.ts: 5 new enum multi-exit tests (Suite 3b)
- solve-issue-tea-worktree.test.ts: updated for current workflow structure
小橘 🍊
- Add agent discovery step to cmdSetupInteractive flow
- _promptAgentSelection: discover uwf-* binaries, auto-select if only one,
prompt user to choose if multiple, show install hints if none found
- mergeConfig: always write selected agent entry, update defaultAgent
- Known agent labels for hermes, claude-code, cursor, builtin
- 10 new tests for _agentNameFromBinary, _printAgentMenu, cmdSetup agent config
Fixes#424
The test used a fake CasRef string as frontmatter, which fails
putSchema validation when loading from YAML files. Replace with
a proper JSON Schema object.
Fixes pre-existing failures in workflow-resolution, cas-exit-code,
and thread-step-count tests.