Skip to content

[codex] Warp-inspired runtime extensions#11

Merged
Telli merged 2 commits into
mainfrom
codex/warp-runtime-extensions
Jul 9, 2026
Merged

[codex] Warp-inspired runtime extensions#11
Telli merged 2 commits into
mainfrom
codex/warp-runtime-extensions

Conversation

@Telli

@Telli Telli commented May 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • adds a new ExternalAgents module with built-in adapters for Claude Code, OpenCode, Gemini CLI, and Codex CLI
  • extends skills into session-aware skill packs with built-in packs, install/manage/run flows, and runtime events
  • adds WorkItems support for GitHub issue/PR import, manual JSON ingestion, session metadata, and summary export
  • adds static workbench/status surfaces for sessions, checkpoints, approvals, recent activity, and adapter health
  • updates docs and README coverage for external agents, skill packs, work items, and workbench commands

Validation

  • dotnet restore SharpClawCode.sln
  • dotnet build SharpClawCode.sln --no-restore
  • dotnet test SharpClawCode.sln --no-build
  • dotnet run --project src/SharpClaw.Code.Cli -- --output-format json external list

Intentionally Deferred

  • structured streaming for external CLIs
  • OAuth/cloud sync and automatic GitHub/Jira posting
  • live curses-style dashboard refresh
  • YAML skill-pack manifests

Summary by CodeRabbit

Release Notes

  • New Features

    • Added external agent support with commands to list, check status, and run adapters (plus REPL/slash routing), including approval gating for mutating runs.
    • Added skill packs with commands to list/install/enable/disable/run reusable packs.
    • Added work items integration to import GitHub issues/PRs and generic JSON tasks, plus export of session summaries.
    • Added a workbench command for session/approval/checkpoint/external-agent health, with --output-format json.
  • Documentation

    • Added new docs pages covering external agents, skill packs, work items, and the workbench.

@coderabbitai

coderabbitai Bot commented May 17, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds external-agent execution, skill-pack management, work-item import/export, and a workbench status command. It also introduces new protocol models/events, runtime and CLI wiring, project references, docs, and tests.

Changes

Feature Surface Expansion

Layer / File(s) Summary
External agents
src/SharpClaw.Code.ExternalAgents/*, src/SharpClaw.Code.Protocol/Models/ExternalAgentModels.cs, src/SharpClaw.Code.Protocol/Events/ExternalAgentEvents.cs, src/SharpClaw.Code.Protocol/Events/RuntimeEvent.cs, src/SharpClaw.Code.Commands/Handlers/ExternalCommandHandler.cs, src/SharpClaw.Code.Commands/Handlers/AgentsCommandHandler.cs, src/SharpClaw.Code.Commands/Handlers/AgentStatusSlashCommandHandler.cs
Adds external-agent contracts, built-in adapters, registry/service orchestration, protocol models/events, and CLI handlers for listing, status, and run operations.
Skill packs and work items
src/SharpClaw.Code.Skills/*, src/SharpClaw.Code.WorkItems/*, src/SharpClaw.Code.Protocol/Models/SkillPackModels.cs, src/SharpClaw.Code.Protocol/Models/WorkItemModels.cs, src/SharpClaw.Code.Commands/Handlers/SkillsCommandHandler.cs, src/SharpClaw.Code.Commands/Handlers/WorkCommandHandler.cs, src/SharpClaw.Code.Protocol/Events/SkillAndWorkItemEvents.cs
Adds skill-pack and work-item data contracts, registries, providers, services, CLI commands, and related runtime events.
Workbench and session support
src/SharpClaw.Code.Protocol/Operational/WorkbenchStatusReport.cs, src/SharpClaw.Code.Runtime/*, src/SharpClaw.Code.Sessions/*, src/SharpClaw.Code.Commands/Handlers/WorkbenchCommandHandler.cs, src/SharpClaw.Code.Commands/Handlers/CheckpointsSlashCommandHandler.cs
Adds workbench status reporting, checkpoint lookup, latest-event reads, session export summaries, and runtime event/model serialization updates.
Wiring, project structure, docs, and tests
SharpClawCode.sln, src/*/*.csproj, src/SharpClaw.Code.Cli/Composition/CliServiceCollectionExtensions.cs, src/SharpClaw.Code.Runtime/Composition/RuntimeServiceCollectionExtensions.cs, README.md, docs/*, tests/SharpClaw.Code.UnitTests/*
Updates solution/project references, DI registration, README/docs links and pages, and supporting unit tests for the new feature areas.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and broadly matches the PR’s runtime-focused additions, even though it doesn’t name the specific modules.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/warp-runtime-extensions

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Telli Telli marked this pull request as ready for review May 18, 2026 01:03
Copilot AI review requested due to automatic review settings May 18, 2026 01:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Warp-inspired runtime extensions: a new ExternalAgents module (Claude/OpenCode/Gemini/Codex CLI adapters), a session-aware skill-pack ecosystem with built-in packs and install/enable/disable/run flows, work-item import/export (GitHub + generic JSON) with session metadata persistence and Markdown/JSON summaries, and a static workbench/status surface. Protocol models, events, AOT serialization context, runtime DI, CLI/REPL commands, and docs are updated to expose these surfaces.

Changes:

  • New SharpClaw.Code.ExternalAgents and SharpClaw.Code.WorkItems projects with adapters, registries, services, permission-aware execution, and runtime events.
  • Skill packs (ISkillPackRegistry, manifest, install/enable/disable/run) layered alongside the legacy skill registry; SkillsCommandHandler extended with new subcommands.
  • WorkbenchStatusService plus workbench/work/external/agent-status/checkpoints CLI+slash handlers, runtime DI, diagnostics check, config schema, and docs.

Reviewed changes

Copilot reviewed 65 out of 65 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
src/SharpClaw.Code.ExternalAgents/** New module: adapter base, four built-in adapters, registry, permission-gated service, executable resolver, default config provider, DI
src/SharpClaw.Code.WorkItems/** New module: GitHub + generic providers, registry, session-aware import/export service, DI
src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs + Abstractions + DI Built-in packs, file-backed install/enable/disable, prompt template expansion
src/SharpClaw.Code.Protocol/** New event types, models (ExternalAgent/SkillPack/WorkItem/WorkbenchStatus), AOT serializer entries, polymorphic event mapping
src/SharpClaw.Code.Runtime/** Workbench status service + abstraction, external-agent config provider, health diagnostic check, config merge of new sections, DI wiring
src/SharpClaw.Code.Commands/Handlers/** New External, Work, Workbench, CheckpointsSlash, AgentStatusSlash handlers; Skills extended with pack commands; Agents extended with external subcommand
src/SharpClaw.Code.Cli/Composition/CliServiceCollectionExtensions.cs Registers new handlers and shares AgentsCommandHandler instance across both CLI and slash command surfaces
SharpClawCode.sln + new .csproj files New project references and solution entries
tests/SharpClaw.Code.UnitTests/** Adds tests for GitHubWorkItemProvider URL parsing, SkillPackRegistry listing/installing, and the Codex external-agent adapter command shaping
docs/{external-agents,skills,work-items,workbench}.md + README.md New documentation for the user-facing features
Comments suppressed due to low confidence (2)

src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs:122

  • EnableAsync / DisableAsync look up the pack directory using skillId as a literal directory name, but ResolveAsync/BuildPromptAsync allow the user to refer to a pack by either Manifest.Id or Manifest.Name (case-insensitive). As a result, a user can skills run a pack by name but then skills enable --id <Name> will return "not found" and a no-op. Consider resolving the pack via ResolveAsync first and acting on its Source directory.
    src/SharpClaw.Code.Commands/Handlers/WorkCommandHandler.cs:94
  • ExportSummaryAsync requires request.Provider (it is later persisted into WorkItemSummaryExportedEvent), but WorkCommandHandler.ExecuteExportSummaryAsync always hardcodes "github" for the provider regardless of which provider actually imported the work item. The exported event will therefore mis-attribute generic/Jira summaries as GitHub. Pull the provider from the session-stored WorkItem.Provider (already available via ReadWorkItem) instead of from the request.
    private async Task<int> ExecuteExportSummaryAsync(string format, CommandExecutionContext context, CancellationToken cancellationToken)
    {
        var result = await workItemService
            .ExportSummaryAsync(new WorkItemExportRequest("github", context.SessionId, null, format), context.WorkingDirectory, cancellationToken)
            .ConfigureAwait(false);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +88 to +100
private async Task<(ConversationSession Session, bool Created)> ResolveSessionAsync(string workspace, string? sessionId, WorkItem workItem, CancellationToken cancellationToken)
{
ConversationSession? session = null;
if (!string.IsNullOrWhiteSpace(sessionId))
{
session = await sessionStore.GetByIdAsync(workspace, sessionId, cancellationToken).ConfigureAwait(false);
}

session ??= await sessionStore.GetLatestAsync(workspace, cancellationToken).ConfigureAwait(false);
if (session is not null)
{
return (session, false);
}
Comment on lines +29 to +35
using var client = new HttpClient();
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("SharpClawCode", "1.0"));
var token = Environment.GetEnvironmentVariable("GITHUB_TOKEN");
if (!string.IsNullOrWhiteSpace(token))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
ResolveMetadata(session, SharpClawWorkflowMetadataKeys.ActiveAgentId),
status.RuntimeState,
status.ApprovalSettings,
0,
Comment on lines +78 to +95
var targetDirectory = pathService.Combine(GetWorkspaceRoot(workspaceRoot, ensureExists: true), manifest.Id);
fileSystem.CreateDirectory(targetDirectory);
await fileSystem.WriteAllTextAsync(
pathService.Combine(targetDirectory, ManifestFileName),
JsonSerializer.Serialize(manifest, ProtocolJsonContext.Default.SkillPackManifest),
cancellationToken).ConfigureAwait(false);

if (request.EnableAfterInstall)
{
fileSystem.TryDeleteFile(pathService.Combine(targetDirectory, DisabledFileName));
}
else
{
await fileSystem.WriteAllTextAsync(pathService.Combine(targetDirectory, DisabledFileName), systemClock.UtcNow.ToString("O"), cancellationToken).ConfigureAwait(false);
}

return new SkillPack(manifest, targetDirectory, false, request.EnableAfterInstall, systemClock.UtcNow);
}
Comment on lines +115 to +149
private async Task<ConversationSession> ResolveSessionAsync(string workspace, ExternalAgentRunRequest request, CancellationToken cancellationToken)
{
ConversationSession? session = null;
if (!string.IsNullOrWhiteSpace(request.SessionId))
{
session = await sessionStore.GetByIdAsync(workspace, request.SessionId, cancellationToken).ConfigureAwait(false);
}

session ??= await sessionStore.GetLatestAsync(workspace, cancellationToken).ConfigureAwait(false);
if (session is not null)
{
return session;
}

var created = new ConversationSession(
CreateIdentifier("session"),
"External agent session",
SessionLifecycleState.Active,
request.PermissionMode,
OutputFormat.Text,
workspace,
workspace,
systemClock.UtcNow,
systemClock.UtcNow,
null,
null,
new Dictionary<string, string>());
await sessionStore.SaveAsync(workspace, created, cancellationToken).ConfigureAwait(false);
await PublishAsync(
workspace,
created.Id,
new SessionCreatedEvent(CreateIdentifier("event"), created.Id, null, systemClock.UtcNow, created),
cancellationToken).ConfigureAwait(false);
return created;
}
public string Provider => "generic";

/// <inheritdoc />
public bool CanImport(string idOrUrl) => idOrUrl.EndsWith(".json", StringComparison.OrdinalIgnoreCase) || idOrUrl.TrimStart().StartsWith('{');
Comment on lines +56 to +70
if (command.Arguments.Length >= 2 && string.Equals(command.Arguments[0], "import", StringComparison.OrdinalIgnoreCase))
{
return ExecuteImportAsync("github", command.Arguments[1], context, cancellationToken);
}

if (command.Arguments.Length == 0 || string.Equals(command.Arguments[0], "show", StringComparison.OrdinalIgnoreCase))
{
return ExecuteExportSummaryAsync("markdown", context, cancellationToken);
}

if (string.Equals(command.Arguments[0], "export-summary", StringComparison.OrdinalIgnoreCase))
{
return ExecuteExportSummaryAsync("markdown", context, cancellationToken);
}


/// <inheritdoc />
public Task<int> ExecuteAsync(SlashCommandParseResult command, CommandExecutionContext context, CancellationToken cancellationToken)
=> agentsCommandHandler.ExecuteAsync(new SlashCommandParseResult(true, "agents", ["external", "status"]), context, cancellationToken);
Comment on lines +29 to +43
var manifest = new SkillPackManifest(
"custom-review",
"Custom Review",
"1.0.0",
"Custom review pack",
"tests",
["review"],
null,
null,
null,
null,
null,
null,
"Review {{arguments}} in {{workspace}}.");
await File.WriteAllTextAsync(manifestPath, JsonSerializer.Serialize(manifest, ProtocolJsonContext.Default.SkillPackManifest));
Comment on lines +179 to +186
private static void Validate(SkillPackManifest manifest)
{
ArgumentException.ThrowIfNullOrWhiteSpace(manifest.Id);
ArgumentException.ThrowIfNullOrWhiteSpace(manifest.Name);
ArgumentException.ThrowIfNullOrWhiteSpace(manifest.Version);
ArgumentException.ThrowIfNullOrWhiteSpace(manifest.Description);
ArgumentException.ThrowIfNullOrWhiteSpace(manifest.EntryPointPrompt);
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🧹 Nitpick comments (1)
src/SharpClaw.Code.WorkItems/Providers/GitHubWorkItemProvider.cs (1)

29-35: 🏗️ Heavy lift

Use IHttpClientFactory for HttpClient management

new HttpClient() on each call increases connection churn and can hurt reliability under repeated imports. The codebase already demonstrates the proper pattern using IHttpClientFactory in TelemetryServiceCollectionExtensions.cs—configure headers and timeouts centrally via dependency injection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/SharpClaw.Code.WorkItems/Providers/GitHubWorkItemProvider.cs` around
lines 29 - 35, Replace the direct new HttpClient usage in GitHubWorkItemProvider
(where the code creates a client, sets UserAgent and Authorization from
GITHUB_TOKEN) with an injected IHttpClientFactory: add an IHttpClientFactory
dependency to the GitHubWorkItemProvider constructor and call
_httpClientFactory.CreateClient("GitHub") (or a suitable named/typed client)
instead of new HttpClient(); move default header and timeout configuration into
your DI setup (following the pattern in TelemetryServiceCollectionExtensions.cs)
so UserAgent, Authorization (if token present) and timeouts are applied
centrally, and remove per-call client creation to avoid connection churn.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/work-items.md`:
- Line 20: Replace the internal reference GenericWorkItemFixture with a concrete
JSON example in the docs: update the sentence that currently reads "The JSON
shape matches `GenericWorkItemFixture`..." to include the provided JSON payload
example (provider, id, title, description, url, status, labels, assignee,
metadata) so CLI users can copy/import directly; ensure the example is fenced as
JSON and matches the suggested keys/values exactly.

In `@src/SharpClaw.Code.Commands/Handlers/AgentsCommandHandler.cs`:
- Around line 208-211: ParseMode currently coerces any unknown string to
ExternalAgentMode.WorkspaceWrite; change it to validate explicitly and fail
fast: map "readOnly" and "read" (case-insensitive) to
ExternalAgentMode.ReadOnly, map "write" and "workspaceWrite" (case-insensitive)
to ExternalAgentMode.WorkspaceWrite, and for any other null/unknown value throw
an ArgumentException (or ArgumentOutOfRangeException) with a clear message;
update the ParseMode method to perform these checks and throw instead of
returning a default.

In `@src/SharpClaw.Code.Commands/Handlers/ExternalCommandHandler.cs`:
- Around line 107-110: The ParseMode method currently treats any unrecognized
string as ExternalAgentMode.WorkspaceWrite, which risks accidental mutating
behavior; update ParseMode to explicitly accept only known values ("readOnly" /
"read" -> ExternalAgentMode.ReadOnly, "writeOnly" / "write" / "workspaceWrite"
-> ExternalAgentMode.WorkspaceWrite) and throw an informative exception (e.g.,
ArgumentException) or return a Result/nullable to surface invalid '--mode'
inputs so callers fail fast instead of defaulting to write mode; reference the
ParseMode function and ExternalAgentMode enum when implementing this validation
and ensure the error message mentions the invalid value and expected modes.

In `@src/SharpClaw.Code.Commands/Handlers/WorkCommandHandler.cs`:
- Around line 56-59: The code in WorkCommandHandler calls ExecuteImportAsync and
ExecuteExportAsync with a hardcoded "github" provider, breaking non-GitHub
sessions; change those calls to use the current session/provider instead of the
literal string. Replace the "github" argument with the runtime provider (e.g.
context.Session?.Provider or the provider parsed from the command) when calling
ExecuteImportAsync and ExecuteExportAsync so import/export use the active
provider (keep a sensible fallback only if absolutely needed). Ensure you update
all occurrences (the ExecuteImportAsync and ExecuteExportAsync calls referenced
in this diff) to reference that provider variable.

In `@src/SharpClaw.Code.ExternalAgents/Adapters/ExternalAgentAdapterBase.cs`:
- Around line 60-64: The error message uses Descriptor.ExecutableName which can
be incorrect when ExternalAgentAdapterConfig.ExecutablePath overrides the
default; modify the executable resolution block in ExternalAgentAdapterBase
(where executableResolver.Resolve(ResolveExecutable(adapterConfig)) is called)
to capture the resolved executable identifier (e.g., store
ResolveExecutable(adapterConfig) into a local like resolvedExecutable or
resolvedPath) and use that value in the Failure(...) message instead of
Descriptor.ExecutableName so the missing-executable error reports the actual
configured/resolved executable.

In `@src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentRegistry.cs`:
- Around line 27-30: The loop over orderedAdapters calling
adapter.GetStatusAsync(...) can let one adapter exception fail the whole report;
change the foreach in ExternalAgentRegistry so each adapter call is protected
with try/catch: for each adapter in orderedAdapters, call await
adapter.GetStatusAsync(workspaceRoot, cancellationToken).ConfigureAwait(false)
inside a try block and on success Add the result to statuses, and in the catch
create and add a fallback/failed status object (including adapter identifier and
exception message/stack) so one adapter failure doesn't break the entire catalog
report; ensure you still observe cancellationToken and do not swallow exceptions
globally.

In `@src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentService.cs`:
- Around line 89-113: Wrap the call to adapter.RunAsync inside a try/catch that
preserves cancellation (catch only Exception and rethrow if cancellation
requested), and on any non-cancellation exception construct an
ExternalAgentRunResult representing a failure (set FailureKind to a
runtime/exception kind, include the exception message/stack in OutputText and
ExternalSessionId as appropriate, and set an exit code) then call
PublishFailedAsync (or publish an ExternalAgentRunFailedEvent analogous to the
successful path) with the workspace, session.Id, request.AdapterId and the
constructed result, await SaveSessionMetadataAsync only on success, and finally
return the failure result; update ExternalAgentService where adapter.RunAsync is
invoked to ensure all exceptions produce a consistent ExternalAgentRunResult and
emitted failed event instead of letting the exception escape.
- Around line 118-124: The code currently falls back to GetLatestAsync when a
requested SessionId is provided but not found; change the logic in
ExternalAgentService so that if request.SessionId is non-empty you call
sessionStore.GetByIdAsync(workspace, request.SessionId, cancellationToken) and
if that returns null immediately throw a clear exception (e.g.
InvalidOperationException or a NotFoundException) indicating the specific
SessionId was not found, and only call sessionStore.GetLatestAsync when
request.SessionId is null/empty; update the code around the session variable and
the calls to GetByIdAsync/GetLatestAsync accordingly.

In
`@src/SharpClaw.Code.ExternalAgents/Services/PathExternalAgentExecutableResolver.cs`:
- Around line 31-34: The resolver in PathExternalAgentExecutableResolver appends
every extension from the extensions list to executableNameOrPath
unconditionally, which produces invalid candidates when the input already
contains an extension (e.g., "foo.exe" -> "foo.exe.EXE"); update the resolution
logic to first check if Path.HasExtension(executableNameOrPath) or
Path.GetExtension(executableNameOrPath) matches a Windows extension and, if so,
only test the given name as-is (construct candidate = Path.Combine(directory,
executableNameOrPath) and call File.Exists), otherwise iterate extensions and
append them as currently done; ensure you still use the existing variables
(extensions, executableNameOrPath, candidate, directory, File.Exists) and
preserve current directory iteration behavior.

In `@src/SharpClaw.Code.Runtime/Workflow/WorkbenchStatusService.cs`:
- Around line 38-40: The code in WorkbenchStatusService.cs currently reads the
entire session event stream via eventStore.ReadAllAsync and then calls
TakeLast(8) into the variable events, which loads full history; change this to
fetch only the last 8 events from the store instead of reading all. Update the
callsite using a store API that returns the tail (e.g.,
eventStore.ReadLastAsync(workspace, session.Id, 8, cancellationToken)) or, if
such an API is not available, replace the ReadAllAsync + TakeLast logic with a
streaming/iterator read that iterates the stream in reverse or reads pages and
stops once 8 events are collected (so the variable events still ends up as the
last 8 events but without materializing the entire stream). Ensure you replace
usages of eventStore.ReadAllAsync(...).TakeLast(8) and keep cancellationToken
handling intact.

In `@src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs`:
- Around line 146-153: ResolveFromDirectoryAsync currently calls
JsonSerializer.Deserialize which can throw JsonException and it returns a
SkillPack without validating the manifest, causing ListAsync enumeration to fail
on a single malformed manifest; update ResolveFromDirectoryAsync to catch
JsonException (and other deserialization exceptions), log or swallow the error
and return null so the directory scan can continue, and ensure you call
Validate(manifest) (same as ResolveAsync) before constructing/returning the
SkillPack instance to reject invalid manifests early; reference
ResolveFromDirectoryAsync, JsonSerializer.Deserialize, Validate(manifest),
ResolveAsync and SkillPack when making the changes.
- Around line 78-79: The code in SkillPackRegistry.cs uses manifest.Id and
skillId directly with IPathService.Combine/GetWorkspaceRoot and
fileSystem.CreateDirectory, allowing path traversal or absolute paths; modify
the code to validate and sanitize these IDs before any path composition:
add/extend Validate() to reject empty or whitespace IDs, any path separator
characters (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), rooted
paths (Path.IsPathRooted), parent-segment sequences (".."), and any
Path.GetInvalidFileNameChars; alternatively normalize IDs by taking
Path.GetFileName(id) or using a dedicated SanitizeSkillPackId(string) helper and
call it everywhere manifest.Id or skillId are used (e.g., in GetWorkspaceRoot,
where paths are combined and in directory creation like
fileSystem.CreateDirectory(targetDirectory)) so that only safe, single-segment
directory names are allowed.

In `@src/SharpClaw.Code.WorkItems/Providers/GenericWorkItemProvider.cs`:
- Around line 27-28: The JSON deserialization in GenericWorkItemProvider
currently lets a JsonException bubble up instead of normalizing to the
provider's InvalidOperationException; wrap the call to
JsonSerializer.Deserialize(...) that assigns 'fixture' in
GenericWorkItemProvider in a try/catch that catches JsonException and rethrows a
new InvalidOperationException("Generic work-item fixture could not be parsed.",
innerException) so malformed JSON is reported consistently (preserve the
original exception as the inner exception).

In `@src/SharpClaw.Code.WorkItems/Services/WorkItemRegistry.cs`:
- Around line 13-15: Resolve currently falls back to CanImport even when a
non-empty provider argument was explicitly given, which can return an unintended
provider; update Resolve (method Resolve and use of orderedProviders) to first
attempt the case-insensitive provider match, and if provider is not null/empty
(use string.IsNullOrWhiteSpace or IsNullOrEmpty) and no match is found return
null immediately, otherwise proceed to the existing fallback that picks the
first orderedProviders item where CanImport(idOrUrl) is true.

In `@src/SharpClaw.Code.WorkItems/Services/WorkItemService.cs`:
- Around line 91-99: The current logic falls back to GetLatestAsync when a
requested sessionId is not found; change it so that when sessionId is provided
(non-empty) you call sessionStore.GetByIdAsync(workspace, sessionId, ...) and if
that returns null you fail immediately (throw an informative exception or return
an explicit error) instead of calling sessionStore.GetLatestAsync; only call
GetLatestAsync when sessionId is null/whitespace. Update the code around the
session variable and the calls to sessionStore.GetByIdAsync and GetLatestAsync
in the method (the block handling sessionId/session) to implement this behavior
and surface a clear error when the explicit session is missing.

---

Nitpick comments:
In `@src/SharpClaw.Code.WorkItems/Providers/GitHubWorkItemProvider.cs`:
- Around line 29-35: Replace the direct new HttpClient usage in
GitHubWorkItemProvider (where the code creates a client, sets UserAgent and
Authorization from GITHUB_TOKEN) with an injected IHttpClientFactory: add an
IHttpClientFactory dependency to the GitHubWorkItemProvider constructor and call
_httpClientFactory.CreateClient("GitHub") (or a suitable named/typed client)
instead of new HttpClient(); move default header and timeout configuration into
your DI setup (following the pattern in TelemetryServiceCollectionExtensions.cs)
so UserAgent, Authorization (if token present) and timeouts are applied
centrally, and remove per-call client creation to avoid connection churn.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c3a67092-172f-4c6a-8e67-40f657fe811b

📥 Commits

Reviewing files that changed from the base of the PR and between 2ec4dcb and 7094ec1.

📒 Files selected for processing (65)
  • README.md
  • SharpClawCode.sln
  • docs/external-agents.md
  • docs/skills.md
  • docs/work-items.md
  • docs/workbench.md
  • src/SharpClaw.Code.Cli/Composition/CliServiceCollectionExtensions.cs
  • src/SharpClaw.Code.Commands/Handlers/AgentStatusSlashCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/AgentsCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/CheckpointsSlashCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/ExternalCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/SkillsCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/WorkCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/WorkbenchCommandHandler.cs
  • src/SharpClaw.Code.Commands/SharpClaw.Code.Commands.csproj
  • src/SharpClaw.Code.ExternalAgents/Abstractions/IExternalAgentAdapter.cs
  • src/SharpClaw.Code.ExternalAgents/Abstractions/IExternalAgentConfigProvider.cs
  • src/SharpClaw.Code.ExternalAgents/Abstractions/IExternalAgentExecutableResolver.cs
  • src/SharpClaw.Code.ExternalAgents/Abstractions/IExternalAgentRegistry.cs
  • src/SharpClaw.Code.ExternalAgents/Abstractions/IExternalAgentService.cs
  • src/SharpClaw.Code.ExternalAgents/Adapters/BuiltInExternalAgentAdapters.cs
  • src/SharpClaw.Code.ExternalAgents/Adapters/ExternalAgentAdapterBase.cs
  • src/SharpClaw.Code.ExternalAgents/AssemblyMarker.cs
  • src/SharpClaw.Code.ExternalAgents/ExternalAgentsServiceCollectionExtensions.cs
  • src/SharpClaw.Code.ExternalAgents/Services/DefaultExternalAgentConfigProvider.cs
  • src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentRegistry.cs
  • src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentService.cs
  • src/SharpClaw.Code.ExternalAgents/Services/PathExternalAgentExecutableResolver.cs
  • src/SharpClaw.Code.ExternalAgents/SharpClaw.Code.ExternalAgents.csproj
  • src/SharpClaw.Code.Protocol/Events/ExternalAgentEvents.cs
  • src/SharpClaw.Code.Protocol/Events/RuntimeEvent.cs
  • src/SharpClaw.Code.Protocol/Events/SkillAndWorkItemEvents.cs
  • src/SharpClaw.Code.Protocol/Models/ExternalAgentModels.cs
  • src/SharpClaw.Code.Protocol/Models/OpenCodeParityModels.cs
  • src/SharpClaw.Code.Protocol/Models/SharpClawWorkflowMetadataKeys.cs
  • src/SharpClaw.Code.Protocol/Models/SkillPackModels.cs
  • src/SharpClaw.Code.Protocol/Models/WorkItemModels.cs
  • src/SharpClaw.Code.Protocol/Operational/WorkbenchStatusReport.cs
  • src/SharpClaw.Code.Protocol/Serialization/ProtocolJsonContext.cs
  • src/SharpClaw.Code.Runtime/Abstractions/IWorkbenchStatusService.cs
  • src/SharpClaw.Code.Runtime/Composition/RuntimeServiceCollectionExtensions.cs
  • src/SharpClaw.Code.Runtime/Configuration/SharpClawConfigService.cs
  • src/SharpClaw.Code.Runtime/Diagnostics/Checks/ExternalAgentHealthCheck.cs
  • src/SharpClaw.Code.Runtime/Diagnostics/OperationalDiagnosticsCoordinator.cs
  • src/SharpClaw.Code.Runtime/Export/SessionExportService.cs
  • src/SharpClaw.Code.Runtime/ExternalAgents/RuntimeExternalAgentConfigProvider.cs
  • src/SharpClaw.Code.Runtime/SharpClaw.Code.Runtime.csproj
  • src/SharpClaw.Code.Runtime/Workflow/WorkbenchStatusService.cs
  • src/SharpClaw.Code.Skills/Abstractions/ISkillPackRegistry.cs
  • src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs
  • src/SharpClaw.Code.Skills/SkillsServiceCollectionExtensions.cs
  • src/SharpClaw.Code.WorkItems/Abstractions/IWorkItemProvider.cs
  • src/SharpClaw.Code.WorkItems/Abstractions/IWorkItemRegistry.cs
  • src/SharpClaw.Code.WorkItems/Abstractions/IWorkItemService.cs
  • src/SharpClaw.Code.WorkItems/AssemblyMarker.cs
  • src/SharpClaw.Code.WorkItems/Providers/GenericWorkItemProvider.cs
  • src/SharpClaw.Code.WorkItems/Providers/GitHubWorkItemProvider.cs
  • src/SharpClaw.Code.WorkItems/Services/WorkItemRegistry.cs
  • src/SharpClaw.Code.WorkItems/Services/WorkItemService.cs
  • src/SharpClaw.Code.WorkItems/SharpClaw.Code.WorkItems.csproj
  • src/SharpClaw.Code.WorkItems/WorkItemsServiceCollectionExtensions.cs
  • tests/SharpClaw.Code.UnitTests/ExternalAgents/ExternalAgentAdapterTests.cs
  • tests/SharpClaw.Code.UnitTests/SharpClaw.Code.UnitTests.csproj
  • tests/SharpClaw.Code.UnitTests/Skills/SkillPackRegistryTests.cs
  • tests/SharpClaw.Code.UnitTests/WorkItems/GitHubWorkItemProviderTests.cs

Comment thread docs/work-items.md Outdated
Comment thread src/SharpClaw.Code.Commands/Handlers/AgentsCommandHandler.cs Outdated
Comment thread src/SharpClaw.Code.Commands/Handlers/ExternalCommandHandler.cs Outdated
Comment thread src/SharpClaw.Code.Commands/Handlers/WorkCommandHandler.cs
Comment thread src/SharpClaw.Code.ExternalAgents/Adapters/ExternalAgentAdapterBase.cs Outdated
Comment thread src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs Outdated
Comment on lines +146 to +153
var manifestText = await fileSystem.ReadAllTextIfExistsAsync(pathService.Combine(directory, ManifestFileName), cancellationToken).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(manifestText))
{
return null;
}

var manifest = JsonSerializer.Deserialize(manifestText, ProtocolJsonContext.Default.SkillPackManifest);
if (manifest is null)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all SkillPackManifest deserialization paths and current exception handling coverage.
rg -n -C3 "JsonSerializer\\.Deserialize\\(.*SkillPackManifest" src
rg -n -C3 "catch \\(JsonException\\)|Validate\\(manifest\\)" src/SharpClaw.Code.Skills

Repository: clawdotnet/SharpClawCode

Length of output: 2607


🏁 Script executed:

sed -n '145,175p' src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs

Repository: clawdotnet/SharpClawCode

Length of output: 1266


🏁 Script executed:

rg -n "ResolveFromDirectoryAsync" src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs | head -20

Repository: clawdotnet/SharpClawCode

Length of output: 303


🏁 Script executed:

sed -n '40,60p' src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs

Repository: clawdotnet/SharpClawCode

Length of output: 874


🏁 Script executed:

sed -n '30,50p' src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs

Repository: clawdotnet/SharpClawCode

Length of output: 871


Add exception handling and validation to ResolveFromDirectoryAsync to prevent malformed manifests from breaking directory scans.

At line 152, JsonSerializer.Deserialize can throw JsonException uncaught. In ListAsync, this breaks enumeration of all remaining packs when a single manifest is malformed. Additionally, the method returns a SkillPack without calling Validate(manifest), unlike the ResolveAsync method which validates at line 76.

🛡️ Suggested fix
     private async Task<SkillPack?> ResolveFromDirectoryAsync(string directory, CancellationToken cancellationToken)
     {
         var manifestText = await fileSystem.ReadAllTextIfExistsAsync(pathService.Combine(directory, ManifestFileName), cancellationToken).ConfigureAwait(false);
         if (string.IsNullOrWhiteSpace(manifestText))
         {
             return null;
         }
 
-        var manifest = JsonSerializer.Deserialize(manifestText, ProtocolJsonContext.Default.SkillPackManifest);
-        if (manifest is null)
+        SkillPackManifest? manifest;
+        try
         {
-            return null;
+            manifest = JsonSerializer.Deserialize(manifestText, ProtocolJsonContext.Default.SkillPackManifest);
         }
+        catch (JsonException)
+        {
+            return null;
+        }
+        if (manifest is null)
+        {
+            return null;
+        }
+        try
+        {
+            Validate(manifest);
+        }
+        catch (ArgumentException)
+        {
+            return null;
+        }
+        catch (InvalidOperationException)
+        {
+            return null;
+        }
 
         return new SkillPack(manifest, directory, false, !fileSystem.FileExists(pathService.Combine(directory, DisabledFileName)));
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var manifestText = await fileSystem.ReadAllTextIfExistsAsync(pathService.Combine(directory, ManifestFileName), cancellationToken).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(manifestText))
{
return null;
}
var manifest = JsonSerializer.Deserialize(manifestText, ProtocolJsonContext.Default.SkillPackManifest);
if (manifest is null)
var manifestText = await fileSystem.ReadAllTextIfExistsAsync(pathService.Combine(directory, ManifestFileName), cancellationToken).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(manifestText))
{
return null;
}
SkillPackManifest? manifest;
try
{
manifest = JsonSerializer.Deserialize(manifestText, ProtocolJsonContext.Default.SkillPackManifest);
}
catch (JsonException)
{
return null;
}
if (manifest is null)
{
return null;
}
try
{
Validate(manifest);
}
catch (ArgumentException)
{
return null;
}
catch (InvalidOperationException)
{
return null;
}
return new SkillPack(manifest, directory, false, !fileSystem.FileExists(pathService.Combine(directory, DisabledFileName)));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs` around lines 146 -
153, ResolveFromDirectoryAsync currently calls JsonSerializer.Deserialize which
can throw JsonException and it returns a SkillPack without validating the
manifest, causing ListAsync enumeration to fail on a single malformed manifest;
update ResolveFromDirectoryAsync to catch JsonException (and other
deserialization exceptions), log or swallow the error and return null so the
directory scan can continue, and ensure you call Validate(manifest) (same as
ResolveAsync) before constructing/returning the SkillPack instance to reject
invalid manifests early; reference ResolveFromDirectoryAsync,
JsonSerializer.Deserialize, Validate(manifest), ResolveAsync and SkillPack when
making the changes.

Comment thread src/SharpClaw.Code.WorkItems/Providers/GenericWorkItemProvider.cs Outdated
Comment thread src/SharpClaw.Code.WorkItems/Services/WorkItemRegistry.cs Outdated
Comment thread src/SharpClaw.Code.WorkItems/Services/WorkItemService.cs
@Telli Telli merged commit 4282a77 into main Jul 9, 2026
3 of 4 checks passed
@Telli Telli deleted the codex/warp-runtime-extensions branch July 9, 2026 10:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/SharpClaw.Code.Sessions/Storage/SqliteEventStore.cs (1)

70-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared deserialization logic to reduce duplication.

ReadLatestAsync and ReadAllAsync share nearly identical reader-to-events loops (connection open, command execute, read/deserialize/skip-null/accumulate). Extracting a private helper for the reader loop would eliminate the duplication and ensure both paths stay consistent if the serialization format changes.

♻️ Suggested refactor: extract a shared reader helper
+ private static async Task<List<RuntimeEvent>> ReadEventsAsync(DbCommand command, CancellationToken cancellationToken)
+ {
+     var events = new List<RuntimeEvent>();
+     await using var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
+     while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
+     {
+         if (reader.IsDBNull(0)) continue;
+         var runtimeEvent = JsonSerializer.Deserialize(reader.GetString(0), ProtocolJsonContext.Default.RuntimeEvent);
+         if (runtimeEvent is not null) events.Add(runtimeEvent);
+     }
+     return events;
+ }
+
  public async Task<IReadOnlyList<RuntimeEvent>> ReadLatestAsync(string workspacePath, string sessionId, int count, CancellationToken cancellationToken)
  {
      ArgumentOutOfRangeException.ThrowIfNegativeOrZero(count);
      await using var connection = await SqliteSessionStoreDatabase
          .OpenConnectionAsync(fileSystem, storagePathResolver, workspacePath, cancellationToken)
          .ConfigureAwait(false);
      await using var command = connection.CreateCommand();
      command.CommandText = """
          SELECT payload_json
          FROM runtime_events
          WHERE session_id = $sessionId
          ORDER BY sequence DESC
          LIMIT $count;
          """;
      command.Parameters.AddWithValue("$sessionId", sessionId);
      command.Parameters.AddWithValue("$count", count);
-     var events = new List<RuntimeEvent>();
-     await using var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
-     while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
-     {
-         if (reader.IsDBNull(0)) continue;
-         var runtimeEvent = JsonSerializer.Deserialize(reader.GetString(0), ProtocolJsonContext.Default.RuntimeEvent);
-         if (runtimeEvent is not null) events.Add(runtimeEvent);
-     }
+     var events = await ReadEventsAsync(command, cancellationToken);
      events.Reverse();
      return events;
  }

The same helper can then be used in ReadAllAsync as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/SharpClaw.Code.Sessions/Storage/SqliteEventStore.cs` around lines 70 -
107, `ReadLatestAsync` duplicates the same reader-to-`RuntimeEvent`
deserialization loop used by `ReadAllAsync`, so extract that logic into a shared
private helper in `SqliteEventStore` and have both methods call it. Keep the
helper responsible for reading rows, skipping null payloads, deserializing with
`ProtocolJsonContext.Default.RuntimeEvent`, and collecting results, while
`ReadLatestAsync` still applies its reverse-order handling after reusing the
shared loop.
src/SharpClaw.Code.Sessions/Abstractions/IEventStore.cs (1)

36-40: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Override ReadLatestAsync in concrete event stores for efficiency.

The default implementation loads all events into memory via ReadAllAsync then takes the last count. For sessions with large event logs, this is O(n) memory and I/O. Concrete stores (e.g., SqliteEventStore) should override this with a bounded query (e.g., ORDER BY sequence DESC LIMIT count) to avoid loading the entire event history.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/SharpClaw.Code.Sessions/Abstractions/IEventStore.cs` around lines 36 -
40, The default IEventStore.ReadLatestAsync implementation is inefficient
because it reads the full event history via ReadAllAsync and then trims it;
update concrete event stores such as SqliteEventStore to override
ReadLatestAsync with a bounded query that fetches only the latest count events
(for example using descending sequence order with a limit) and returns them in
the correct chronological order. Keep the existing argument validation and
cancellation handling, and use the same method name/signature so the optimized
override is picked up transparently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/SharpClaw.Code.Sessions/Abstractions/IEventStore.cs`:
- Around line 36-40: The default IEventStore.ReadLatestAsync implementation is
inefficient because it reads the full event history via ReadAllAsync and then
trims it; update concrete event stores such as SqliteEventStore to override
ReadLatestAsync with a bounded query that fetches only the latest count events
(for example using descending sequence order with a limit) and returns them in
the correct chronological order. Keep the existing argument validation and
cancellation handling, and use the same method name/signature so the optimized
override is picked up transparently.

In `@src/SharpClaw.Code.Sessions/Storage/SqliteEventStore.cs`:
- Around line 70-107: `ReadLatestAsync` duplicates the same
reader-to-`RuntimeEvent` deserialization loop used by `ReadAllAsync`, so extract
that logic into a shared private helper in `SqliteEventStore` and have both
methods call it. Keep the helper responsible for reading rows, skipping null
payloads, deserializing with `ProtocolJsonContext.Default.RuntimeEvent`, and
collecting results, while `ReadLatestAsync` still applies its reverse-order
handling after reusing the shared loop.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b658f6a9-fed5-4c0c-9904-7c10f7b84bc8

📥 Commits

Reviewing files that changed from the base of the PR and between 7094ec1 and 226b30c.

📒 Files selected for processing (30)
  • docs/external-agents.md
  • docs/work-items.md
  • src/SharpClaw.Code.Commands/Handlers/AgentStatusSlashCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/AgentsCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/ExternalCommandHandler.cs
  • src/SharpClaw.Code.Commands/Handlers/WorkCommandHandler.cs
  • src/SharpClaw.Code.ExternalAgents/Adapters/ExternalAgentAdapterBase.cs
  • src/SharpClaw.Code.ExternalAgents/Services/DefaultExternalAgentConfigProvider.cs
  • src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentRegistry.cs
  • src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentService.cs
  • src/SharpClaw.Code.ExternalAgents/Services/PathExternalAgentExecutableResolver.cs
  • src/SharpClaw.Code.Protocol/Operational/WorkbenchStatusReport.cs
  • src/SharpClaw.Code.Runtime/Composition/RuntimeServiceCollectionExtensions.cs
  • src/SharpClaw.Code.Runtime/WorkItems/RuntimeWorkItemConfigProvider.cs
  • src/SharpClaw.Code.Runtime/Workflow/WorkbenchStatusService.cs
  • src/SharpClaw.Code.Sessions/Abstractions/IEventStore.cs
  • src/SharpClaw.Code.Sessions/Storage/HostAwareEventStore.cs
  • src/SharpClaw.Code.Sessions/Storage/SqliteEventStore.cs
  • src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs
  • src/SharpClaw.Code.WorkItems/Abstractions/IWorkItemConfigProvider.cs
  • src/SharpClaw.Code.WorkItems/Providers/GenericWorkItemProvider.cs
  • src/SharpClaw.Code.WorkItems/Providers/GitHubWorkItemProvider.cs
  • src/SharpClaw.Code.WorkItems/Services/DefaultWorkItemConfigProvider.cs
  • src/SharpClaw.Code.WorkItems/Services/WorkItemRegistry.cs
  • src/SharpClaw.Code.WorkItems/Services/WorkItemService.cs
  • src/SharpClaw.Code.WorkItems/SharpClaw.Code.WorkItems.csproj
  • src/SharpClaw.Code.WorkItems/WorkItemsServiceCollectionExtensions.cs
  • tests/SharpClaw.Code.UnitTests/Skills/SkillPackRegistryTests.cs
  • tests/SharpClaw.Code.UnitTests/WorkItems/GenericWorkItemProviderTests.cs
  • tests/SharpClaw.Code.UnitTests/WorkItems/WorkItemRegistryTests.cs
💤 Files with no reviewable changes (1)
  • src/SharpClaw.Code.Protocol/Operational/WorkbenchStatusReport.cs
✅ Files skipped from review due to trivial changes (3)
  • docs/work-items.md
  • src/SharpClaw.Code.WorkItems/Abstractions/IWorkItemConfigProvider.cs
  • docs/external-agents.md
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/SharpClaw.Code.WorkItems/SharpClaw.Code.WorkItems.csproj
  • src/SharpClaw.Code.Commands/Handlers/AgentStatusSlashCommandHandler.cs
  • src/SharpClaw.Code.WorkItems/WorkItemsServiceCollectionExtensions.cs
  • src/SharpClaw.Code.ExternalAgents/Services/PathExternalAgentExecutableResolver.cs
  • src/SharpClaw.Code.WorkItems/Services/WorkItemRegistry.cs
  • src/SharpClaw.Code.Runtime/Composition/RuntimeServiceCollectionExtensions.cs
  • src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentRegistry.cs
  • src/SharpClaw.Code.WorkItems/Providers/GenericWorkItemProvider.cs
  • src/SharpClaw.Code.WorkItems/Services/WorkItemService.cs
  • src/SharpClaw.Code.Skills/Services/SkillPackRegistry.cs
  • src/SharpClaw.Code.ExternalAgents/Services/ExternalAgentService.cs
  • src/SharpClaw.Code.Runtime/Workflow/WorkbenchStatusService.cs
  • src/SharpClaw.Code.ExternalAgents/Adapters/ExternalAgentAdapterBase.cs
  • src/SharpClaw.Code.Commands/Handlers/AgentsCommandHandler.cs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants