Wrap stream() in try/catch to prevent silent failures.
On exception, log the error and yield a structured error event:
['type' => 'error', 'message' => string]
Adds tests for connection errors, runtime exceptions, error event
format, and Log::error invocation. Closes ERR-001 in TODO.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace individual __get expectations with a single closure that handles
all property access. Fixes ErrorException on undefined property access
with Mockery mocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Verify agent_sessions.session_id: unique() constraint creates an
implicit unique index (agent_sessions_session_id_unique) which is
sufficient for string lookups; no additional index required
- Drop redundant agent_plans_slug_index: the unique() constraint on
slug already provides agent_plans_slug_unique covering all lookups
- Add compound (workspace_id, slug) index on agent_plans for the
common routing pattern WHERE workspace_id = ? AND slug = ?
- Verify agent_workspace_states.key: already indexed via ->index('key')
in migration 000003; no additional index required
- Mark DB-002 as resolved in TODO.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded cache key in ForAgentsController with a config-based
key (`mcp.cache.for_agents_key`) and configurable TTL
(`mcp.cache.for_agents_ttl`). This prevents collisions with other modules
or packages that might use the same flat cache key.
- Add `cacheKey()` method on ForAgentsController, reads from config
- Add `cache` section to config.php with default key and TTL
- Dynamic Cache-Control max-age now follows the configured TTL
- Add ForAgentsControllerTest covering key customisation,
cache storage, invalidation, TTL, and response structure
Refs: TODO.md CQ-003
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch View/Modal/Admin/ApiKeyManager.php from Core\Api\Models\ApiKey
to Core\Mod\Agentic\Models\AgentApiKey and AgentApiKeyService, bringing
the workspace-owner admin UI into consistency with all other services.
Changes:
- Replace Core\Api\Models\ApiKey import with AgentApiKey + AgentApiKeyService
- Use AgentApiKeyService::create() for key generation
- Use AgentApiKey::forWorkspace() scoping in revokeKey() and render()
- Rename newKeyScopes → newKeyPermissions, toggleScope → togglePermission
- Expose availablePermissions() from AgentApiKey for the create form
- Update blade template: permissions field, getMaskedKey(), togglePermission,
dynamic permission checkboxes from AgentApiKey::availablePermissions()
- Add tests/Feature/ApiKeyManagerTest.php with integration coverage
- Mark CQ-002 resolved in TODO.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The processOutput() method was a stub with no implementation. The
ContentProcessingService dependency it accepted is from the external
host-uk/core package and its API is not available here. Content
is already persisted via markCompleted() so no output processing
was ever performed.
Removes:
- processOutput() stub method
- ContentProcessingService import and handle() parameter
- target_type/target_id guard block that called the stub
Adds unit tests covering: prompt validation, entitlement checks,
provider availability, task completion metadata, usage recording,
and template variable interpolation.
Closes#17
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `Builder $query` parameter type and `: Builder` return type to
18 query scopes across 8 model files. Import `Illuminate\Database\Eloquent\Builder`
in each affected model.
Affected models: Task, AgentSession, AgentApiKey, AgentPhase, AgentPlan,
Prompt, AgentWorkspaceState, WorkspaceState.
Closes#16
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Direct git clone of ../php-framework avoids shell escaping
issues with dynamic PHP-based path extraction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch php -r argument to single quotes so PHP dollar signs
are not interpreted by bash. Pipe output to while-read loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PHP variables inside php -r need \$ escaping, but shell
variables outside need bare $ for command substitution and
variable expansion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Feature test covering PromptVersion creation, relationships (prompt,
creator), restore() rollback method, and version history tracking. Also
add idempotent migration for prompts and prompt_versions tables required
by the test suite.
Closes#15
The Forgejo act runner caches reusable workflow definitions,
preventing updates from being picked up. Inline the workflow
with dependency checkout step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The reusable php-test.yml now detects pest/phpunit/pint availability
and clones path dependencies using the runner token.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add phpunit.xml for standalone test execution.
Apply Laravel Pint formatting fixes across all source files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The .github/workflows/ci.yml has a visibility guard that evaluates
to false on Forgejo, causing all jobs to fail in 1 second.
Co-Authored-By: Charon <charon@lethean.io>
- All package migrations now guarded with hasTable()/hasColumn()
so they coexist with the consolidated app-level migration
- Migration 000001: aligned agent_api_keys and agent_sessions
schemas with current model expectations (key not key_hash,
session_id not uuid, etc.)
- Migration 000002: hasColumn guards for ALTER TABLE safety
- Migration 000003: hasTable guards for all CREATE TABLE calls
- Dashboard: wrap all queries in try/catch so /hub/agents loads
even when tables haven't been migrated yet
Co-Authored-By: Virgil <virgil@lethean.io>
Moves from dashboard group to the new agents group in AdminMenuRegistry,
giving it top-level visibility as the platform's primary capability.
Co-Authored-By: Virgil <virgil@lethean.io>
The context column (longText) was missing its array cast, causing
"Array to string conversion" errors when creating plans via MCP.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track completed improvements:
- P2-062 to P2-068: API key hashing, tests for AgentApiKey/Service/IpRestriction/PlanTemplate/AI providers, migration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert PHPUnit class-based tests to Pest functional syntax with:
- 47 test cases organised into 9 describe blocks
- Proper beforeEach/afterEach hooks for test setup/teardown
- Covers: template listing, retrieval, preview, variable substitution,
plan creation, validation, categories, context generation, edge cases
- Uses expect() assertions and method chaining for clarity
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rewrote all test methods to use Pest's test() function with expect()
assertions instead of PHPUnit class-based syntax:
- IP validation tests (IPv4 and IPv6)
- CIDR range matching for all prefix lengths (/0 to /32 for IPv4, /0 to /128 for IPv6)
- Whitelist management tests (parsing, formatting, comments)
- Entry validation and error handling
- Edge cases (loopback, private ranges, link-local, mixed protocols)
Test count increased from 60+ to 78 with additional edge case coverage.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Convert AgentApiKeyTest from PHPUnit class-based syntax to Pest functional syntax
- Add tests/Pest.php configuration with helper functions (createWorkspace, createApiKey)
- Organise tests using describe() blocks for better structure
- Add additional test coverage for key rotation and security edge cases
- Update TODO.md to reflect Pest syntax usage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>