feat: keep Claude sessions warm and finish runtime wiring - #188
feat: keep Claude sessions warm and finish runtime wiring#188Waishnav wants to merge 10 commits into
Conversation
📝 WalkthroughWalkthroughThe PR adds a Claude local-agent runtime, centralizes provider drivers, renames workspace context fields to ChangesLocal agent runtime architecture
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant AgentClient
participant ClaudeLocalAgentDriver
participant ClaudeQueryRuntime
participant ClaudeAgentSDK
AgentClient->>ClaudeLocalAgentDriver: run prompt with workspaceRoot
ClaudeLocalAgentDriver->>ClaudeQueryRuntime: create or reuse runtime
ClaudeQueryRuntime->>ClaudeAgentSDK: start or resume query
ClaudeQueryRuntime->>ClaudeAgentSDK: stream prompt input
ClaudeAgentSDK-->>ClaudeQueryRuntime: return streamed messages
ClaudeQueryRuntime-->>ClaudeLocalAgentDriver: return response and session ID
ClaudeLocalAgentDriver-->>AgentClient: return run result
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR completes the local-agent runtime wiring, introduces persistent warm Claude query sessions, and aligns workspace scoping and provider availability with the native drivers.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains within the eligible follow-up review scope. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| src/local-agent-claude.ts | Adds the per-agent streaming Claude runtime, input queue, session resumption, per-turn configuration, and lifecycle cleanup. |
| src/local-agent-runtime.ts | Renames the runtime workspace field to workspaceRoot and carries workspace identity consistently through runtime interfaces. |
| src/local-agent-manager.ts | Persists workspace IDs on creation and applies workspace scope checks when listing, reading, or continuing agents. |
| src/local-agent-adapters.ts | Replaces embedded provider implementations with a compact registry of dedicated native drivers. |
| src/local-agent-availability.ts | Aligns provider discovery with package-based and host-command-based native runtime requirements. |
| src/local-agent-codex.ts | Updates Codex runtime inputs to use the explicit workspaceRoot field. |
| src/local-agent-acp.ts | Propagates workspaceRoot through ACP session creation, resumption, process launch, and runtime keying. |
| src/local-agent-pi.ts | Propagates workspaceRoot into Pi session construction and runtime identity. |
| src/local-agent-opencode.ts | Updates OpenCode runtime construction to consume the renamed workspaceRoot input. |
| package.json | Removes the bundled Codex SDK and adds dedicated native-driver tests to the test suite. |
Sequence Diagram
sequenceDiagram
participant CLI as DevSpace CLI
participant D as devspace-agentd
participant M as Agent Manager
participant P as Runtime Pool
participant C as Claude Query
CLI->>D: agents run / continue
D->>M: start or continue(agentId, prompt)
M->>P: "run(runtime key = claude:agentId)"
alt Warm runtime exists
P->>C: push next user message
else Cold or restarted runtime
P->>C: "create query(resume = providerSessionId)"
P->>C: push user message
end
C-->>P: streamed result and session ID
P-->>M: final response
M-->>D: persist status, response, session ID
D-->>CLI: agent record
Reviews (2): Last reviewed commit: "refactor: keep provider availability sid..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc246a9047
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| async run(input: LocalAgentRunInput): Promise<LocalAgentRunResult> { | ||
| if (!this.isAlive()) throw new Error("Claude runtime is not running."); | ||
| if (input.model && this.query.setModel) await this.query.setModel(input.model); |
There was a problem hiding this comment.
Apply thinking overrides to warm Claude sessions
When a Claude agent is continued with --thinking while its runtime is still warm, the pool reuses the same claude:${agentId} query, but this run path only applies dynamic model changes. The thinking/effort option is only passed when claudeQueryOptions() creates the query, so the per-run thinking override documented in skills/subagent-delegation/SKILL.md is silently ignored until the runtime idles out or the server restarts; recreate/key the runtime on thinking changes or apply the provider's dynamic control if available.
Useful? React with 👍 / 👎.
fc246a9 to
30fbfe5
Compare
30fbfe5 to
bd3ad46
Compare
bd3ad46 to
52108ed
Compare
52108ed to
e31591f
Compare
e31591f to
c492264
Compare
89bdc95 to
0391357
Compare
0391357 to
5afa49b
Compare
7e66ea4 to
d3a3cfe
Compare
d3a3cfe to
6eea7af
Compare
6eea7af to
0f171a9
Compare
29c8469 to
a53c34e
Compare
00dc770 to
6053c80
Compare
ccad60d to
6cf3d56
Compare
6cf3d56 to
19e5f90
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/local-agent-manager.ts (1)
220-229: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winRevalidate the persisted workspace root before loading profiles or running the provider.
runTurnpassesrecord.workspaceRootdirectly toloadProfiles,buildRunInput, andLocalAgentRuntimeContext. CallauthorizeWorkspacefirst and use the returned path throughout. Otherwise, a changedallowedRootsconfiguration or modified stored record can execute against an unauthorized workspace.🤖 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/local-agent-manager.ts` around lines 220 - 229, Update runTurn to call authorizeWorkspace with record.workspaceRoot before loading profiles or invoking the provider, then use the returned authorized path for loadProfiles, buildRunInput, and LocalAgentRuntimeContext.workspaceRoot. Ensure all subsequent workspace operations use this revalidated value rather than the persisted record field.Source: Learnings
🧹 Nitpick comments (7)
package.json (1)
32-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftAdd a packaged CLI smoke path.
The test script executes source files directly with
tsx. It does not exercisenpm pack/npx, daemon auto-start, or continuation after restart. Source tests can pass while the packaged user path is broken. Add a package-level smoke test in CI, or state that this command provides source-level coverage only.As per coding guidelines: “Verify the actual user-consumption path, including packaged npm/npx usage, and clearly state when only a narrower proxy was verified.”
🤖 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 `@package.json` at line 32, Add a package-level smoke test to the test/CI flow that runs the built package through npm pack and npx, covering daemon auto-start and continuation after restart; alternatively, explicitly label the existing test command as source-level coverage only and add the packaged-path verification separately. Anchor the change near the package.json test script and reuse the project’s existing CLI and daemon test entry points.Source: Coding guidelines
src/local-agent-acp.ts (1)
163-182: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winResolve
workspaceRootbefore you send it ascwd.Every other site in this file passes
resolve(context.workspaceRoot)(lines 248, 257, 389, 403). Thesession/resumeandsession/newrequests passinput.workspaceRootunchanged. If a caller supplies a relative root, the agent process receives a path that is resolved against its own working directory. Normalize the value here for consistent workspace scoping.♻️ Proposed change
const response = await this.connection.agent.request("session/resume", { sessionId: input.providerSessionId, - cwd: input.workspaceRoot, + cwd: resolve(input.workspaceRoot), mcpServers: [], ...this.additionalDirectoryParams(), });const response = await this.connection.agent.request("session/new", { - cwd: input.workspaceRoot, + cwd: resolve(input.workspaceRoot), mcpServers: [], ...this.additionalDirectoryParams(), });🤖 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/local-agent-acp.ts` around lines 163 - 182, Update the session/resume and session/new request payloads in the surrounding session creation flow to pass the resolved input.workspaceRoot as cwd, matching the resolve-based handling used elsewhere in the file. Ensure both requests normalize relative workspace roots before sending them to the agent.src/local-agent-adapters.test.ts (1)
24-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the full driver contract, not only
runtimeKey.
LocalAgentDriverin src/local-agent-runtime.ts declaresprovider,runtimeKey, andcreateRuntime. This loop checksproviderandruntimeKeyonly. A driver that omitscreateRuntimewould still pass. Add the missing assertion so the registry contract stays covered.♻️ Proposed change
for (const provider of providers) { const adapter = createLocalAgentAdapter(provider); assert.equal(adapter.provider, provider); assert.equal(typeof adapter.runtimeKey, "function"); + assert.equal(typeof adapter.createRuntime, "function"); }🤖 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/local-agent-adapters.test.ts` around lines 24 - 28, Extend the provider loop in the local agent adapter test to assert that the created adapter’s createRuntime property is a function, alongside the existing provider and runtimeKey checks, covering the complete LocalAgentDriver contract.src/local-agent-availability.test.ts (1)
23-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep a negative case for the package-backed check.
The previous test simulated a missing
piexecutable and assertedavailable: falsewith a reason. The new assertion only states that Pi is available. No test now proves that a package-backed provider reportsavailable: falsewith a reason when the module does not resolve. That path is the changed behavior in src/local-agent-availability.ts.Also note that this assertion depends on
@earendil-works/pi-coding-agentbeing installed in the test environment. It verifies the local dev install, not a packaged npm/npx install with omitted optional dependencies.Add a case that exercises the unresolvable-package branch, for example by exporting
packageAvailabilityfor tests or by asserting the reason shape for a provider whose package is absent.As per coding guidelines: "Verify the actual user-consumption path, including packaged npm/npx usage ...; clearly state when only a narrower proxy was verified."
🤖 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/local-agent-availability.test.ts` around lines 23 - 25, Add a negative test alongside the existing checkLocalAgentProviderAvailability("pi") assertion that exercises the unresolvable package-backed provider path and verifies available is false with a reason. Expose or reuse packageAvailability so the test can deterministically simulate a missing module rather than relying on the installed Pi package; keep the existing availability assertion, but ensure the test distinguishes local development installation from packaged npm/npx behavior with omitted optional dependencies.Source: Coding guidelines
src/local-agent-claude.ts (2)
36-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the unused
rejectcallback from the waiter record.No code path calls
waiter.reject.close()resolves pending waiters with{ done: true }, andpush()throws synchronously. Droprejectto keep the queue contract explicit.Also applies to: 59-64
🤖 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/local-agent-claude.ts` around lines 36 - 39, Remove the unused reject callback from the waiter record declared in the waiters field, and update all related waiter creation and handling in close() and push() to use only resolve. Preserve close() resolving pending waiters with done: true and push() throwing synchronously.
279-291: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNormalize the sandbox filesystem paths like the permission rules.
Line 259 normalizes backslashes for the permission rules, but
sandbox.filesystemreceives the rawworkspaceRootand the rawprotectedPaths. On Windows the two lists then use different path separators for the same locations. Use one normalized form for both.♻️ Proposed fix
const sandbox = { enabled: true, failIfUnavailable: true, autoAllowBashIfSandboxed: true, allowUnsandboxedCommands: false, filesystem: { - allowWrite: allowed ? [workspaceRoot] : [], - denyWrite: allowed ? [] : [workspaceRoot], - denyRead: protectedPaths, - allowRead: [workspaceRoot], + allowWrite: allowed ? [resolvedWorkspace] : [], + denyWrite: allowed ? [] : [resolvedWorkspace], + denyRead: protectedPaths.map((path) => path.replaceAll("\\", "/")), + allowRead: [resolvedWorkspace], }, };🤖 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/local-agent-claude.ts` around lines 279 - 291, Normalize workspaceRoot and protectedPaths before constructing the sandbox object, matching the normalization already used by the permission rules near the surrounding setup. Use these normalized values for sandbox.filesystem.allowWrite, denyWrite, denyRead, and allowRead, while preserving the existing allowed branching and permission behavior.src/local-agent-claude.test.ts (1)
96-102: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider asserting
cwdand the scrubbed environment.The test already captures
lastOptions. Add assertions forcwd === "/tmp/project"and for the removal ofCLAUDECODEand the other Claude entrypoint variables byclaudeCommandEnvironment. Both are workspace-scoping and isolation guarantees of the new driver.🤖 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/local-agent-claude.test.ts` around lines 96 - 102, Add assertions in the test covering the captured lastOptions from the Claude query: verify cwd is "/tmp/project" and confirm the environment has removed CLAUDECODE and the other Claude entrypoint variables via claudeCommandEnvironment. Keep the existing session reuse and permission assertions unchanged.
🤖 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 `@skills/subagent-delegation/SKILL.md`:
- Around line 37-38: Update the continuation section describing `continue <id>
"<prompt>"` to include examples demonstrating both supported overrides,
`--model` and `--thinking`, while preserving the existing guidance not to use
`run <id>` for continuation.
In `@src/local-agent-availability.ts`:
- Around line 105-115: Update resolveCommand so the Windows extensions list
always probes the bare command name before PATHEXT variants by including an
empty extension first. Preserve the existing PATHEXT fallback and path iteration
behavior, ensuring commands already ending in extensions such as .exe or .cmd
are checked directly.
- Around line 82-97: Update codexAvailability and the related CLI/server
availability summaries to distinguish executable-only detection from full Codex
availability, explicitly stating that app-server support is required. Keep
commandAvailability side-effect-free and preserve its executable resolution
check, but ensure user-facing output does not report Codex as fully available
when app-server support is absent.
In `@src/local-agent-claude.ts`:
- Around line 166-168: Update LocalAgentClaude.runtimeKey to include
context.writeMode alongside context.agentId, ensuring runtime pool entries
remain distinct for each write mode while preserving the existing Claude key
prefix.
In `@src/local-agent-manager.ts`:
- Around line 318-320: Update the get and continue flows in the agent manager to
require both a workspace scope and its workspaceId, and ensure direct callers
invoke assertAgentWorkspace before accessing records. In the workspace
validation around record.workspaceId and scope, distinguish mismatched workspace
IDs from mismatched workspace roots with separate errors, while preserving
validation for matching scopes.
---
Outside diff comments:
In `@src/local-agent-manager.ts`:
- Around line 220-229: Update runTurn to call authorizeWorkspace with
record.workspaceRoot before loading profiles or invoking the provider, then use
the returned authorized path for loadProfiles, buildRunInput, and
LocalAgentRuntimeContext.workspaceRoot. Ensure all subsequent workspace
operations use this revalidated value rather than the persisted record field.
---
Nitpick comments:
In `@package.json`:
- Line 32: Add a package-level smoke test to the test/CI flow that runs the
built package through npm pack and npx, covering daemon auto-start and
continuation after restart; alternatively, explicitly label the existing test
command as source-level coverage only and add the packaged-path verification
separately. Anchor the change near the package.json test script and reuse the
project’s existing CLI and daemon test entry points.
In `@src/local-agent-acp.ts`:
- Around line 163-182: Update the session/resume and session/new request
payloads in the surrounding session creation flow to pass the resolved
input.workspaceRoot as cwd, matching the resolve-based handling used elsewhere
in the file. Ensure both requests normalize relative workspace roots before
sending them to the agent.
In `@src/local-agent-adapters.test.ts`:
- Around line 24-28: Extend the provider loop in the local agent adapter test to
assert that the created adapter’s createRuntime property is a function,
alongside the existing provider and runtimeKey checks, covering the complete
LocalAgentDriver contract.
In `@src/local-agent-availability.test.ts`:
- Around line 23-25: Add a negative test alongside the existing
checkLocalAgentProviderAvailability("pi") assertion that exercises the
unresolvable package-backed provider path and verifies available is false with a
reason. Expose or reuse packageAvailability so the test can deterministically
simulate a missing module rather than relying on the installed Pi package; keep
the existing availability assertion, but ensure the test distinguishes local
development installation from packaged npm/npx behavior with omitted optional
dependencies.
In `@src/local-agent-claude.test.ts`:
- Around line 96-102: Add assertions in the test covering the captured
lastOptions from the Claude query: verify cwd is "/tmp/project" and confirm the
environment has removed CLAUDECODE and the other Claude entrypoint variables via
claudeCommandEnvironment. Keep the existing session reuse and permission
assertions unchanged.
In `@src/local-agent-claude.ts`:
- Around line 36-39: Remove the unused reject callback from the waiter record
declared in the waiters field, and update all related waiter creation and
handling in close() and push() to use only resolve. Preserve close() resolving
pending waiters with done: true and push() throwing synchronously.
- Around line 279-291: Normalize workspaceRoot and protectedPaths before
constructing the sandbox object, matching the normalization already used by the
permission rules near the surrounding setup. Use these normalized values for
sandbox.filesystem.allowWrite, denyWrite, denyRead, and allowRead, while
preserving the existing allowed branching and permission behavior.
🪄 Autofix
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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 39fd5c05-ab2b-4ab4-8b6d-ee84c65e16d1
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (22)
docs/agent-profile-schema.mdpackage.jsonskills/subagent-delegation/SKILL.mdsrc/cli.tssrc/local-agent-acp.test.tssrc/local-agent-acp.tssrc/local-agent-adapters.test.tssrc/local-agent-adapters.tssrc/local-agent-availability.test.tssrc/local-agent-availability.tssrc/local-agent-claude.test.tssrc/local-agent-claude.tssrc/local-agent-codex.test.tssrc/local-agent-codex.tssrc/local-agent-manager.test.tssrc/local-agent-manager.tssrc/local-agent-opencode.test.tssrc/local-agent-opencode.tssrc/local-agent-pi.test.tssrc/local-agent-pi.tssrc/local-agent-runtime.test.tssrc/local-agent-runtime.ts
| `continue <id> "<prompt>"` sends a follow-up to an existing agent. Do not use | ||
| `run <id>` for continuation. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
git ls-files 'skills/subagent-delegation/SKILL.md' 'src/cli.ts' 'package.json' 'README.md'
printf '%s\n' '--- skill structure ---'
ast-grep outline skills/subagent-delegation/SKILL.md --lang markdown 2>/dev/null || true
printf '%s\n' '--- relevant skill content ---'
cat -n skills/subagent-delegation/SKILL.md | sed -n '1,120p'
printf '%s\n' '--- CLI references ---'
rg -n -C 8 'agents (run|continue)|continue|thinking|model' src/cli.ts
printf '%s\n' '--- package and host-facing entry points ---'
rg -n -C 4 '"(bin|scripts|packageManager|engines)"|agents (run|continue)|subagent-delegation|SKILL' package.json README.md .github 2>/dev/null || trueRepository: Waishnav/devspace
Length of output: 10063
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
git ls-files 'skills/subagent-delegation/SKILL.md' 'src/cli.ts' 'package.json' 'README.md'
printf '%s\n' '--- skill content ---'
cat -n skills/subagent-delegation/SKILL.md | sed -n '1,120p'
printf '%s\n' '--- CLI references ---'
rg -n -C 8 'agents (run|continue)|continue|thinking|model' src/cli.ts
printf '%s\n' '--- package and host-facing entry points ---'
rg -n -C 4 '"(bin|scripts|packageManager|engines)"|agents (run|continue)|subagent-delegation|SKILL' package.json README.md .github 2>/dev/null || trueRepository: Waishnav/devspace
Length of output: 9980
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- CLI imports and parser definitions ---'
cat -n src/cli.ts | sed -n '1,90p'
rg -n -C 12 'function parseLocalAgent(Run|Continue)Args|parseLocalAgent(Run|Continue)Args|type .*Agent.*Args|interface .*Agent.*Args|--model|--thinking' src
printf '%s\n' '--- agent client continuation call graph ---'
rg -n -C 10 'continue\(|model\??:|thinking\??:|LocalAgent' src | head -n 260
printf '%s\n' '--- tests and docs for continuation overrides ---'
rg -n -C 8 'agents continue|parseLocalAgentContinueArgs|--model|--thinking' --glob '!dist/**' --glob '!node_modules/**' .Repository: Waishnav/devspace
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- continuation implementation ---'
cat -n src/local-agent-client.ts | sed -n '1,180p'
rg -n -C 14 'async continue|continue\(agentId|RunOverrides|overrides.*model|overrides.*thinking' src/local-agent-manager.ts src/local-agent-daemon.ts src/local-agent-daemon-protocol.ts src/local-agent-client.ts
printf '%s\n' '--- packaged skill discovery and installation path ---'
rg -n -C 8 'skills|SKILL.md|DEVSPACE_SKILLS|ensureDevspaceDefaultSkills|files' src scripts package.json docs README.md | head -n 260
printf '%s\n' '--- focused continuation parser test presence ---'
cat -n src/local-agent-targets.test.ts | sed -n '1,115p'
printf '%s\n' '--- read-only behavioral verifier for the documented continuation forms ---'
python3 - <<'PY'
from dataclasses import dataclass
`@dataclass`
class Parsed:
agentId: str
prompt: str
model: str | None = None
thinking: str | None = None
def parse_continue(args):
target, *rest = args
if not target:
raise ValueError("usage")
model = thinking = None
prompt_parts = []
i = 0
while i < len(rest):
part = rest[i]
if part == "--model":
if i + 1 >= len(rest) or not rest[i+1].strip():
raise ValueError("Missing value for --model.")
model = rest[i+1].strip()
i += 2
continue
if part.startswith("--model="):
value = part[len("--model="):].strip()
if not value:
raise ValueError("Missing value for --model.")
model = value
i += 1
continue
if part == "--thinking":
if i + 1 >= len(rest) or not rest[i+1].strip():
raise ValueError("Missing value for --thinking.")
thinking = rest[i+1].strip()
i += 2
continue
if part.startswith("--thinking="):
value = part[len("--thinking="):].strip()
if not value:
raise ValueError("Missing value for --thinking.")
thinking = value
i += 1
continue
prompt_parts.append(part)
i += 1
prompt = " ".join(prompt_parts).strip()
if not prompt:
raise ValueError("usage")
return Parsed(target, prompt, model, thinking)
cases = [
(["agt_1", "--model", "gpt-5.1", "follow up"], Parsed("agt_1", "follow up", "gpt-5.1", None)),
(["agt_1", "--thinking=high", "follow up"], Parsed("agt_1", "follow up", None, "high")),
(["agt_1", "--model", "gpt-5.1", "--thinking", "high", "follow", "up"],
Parsed("agt_1", "follow up", "gpt-5.1", "high")),
]
for argv, expected in cases:
actual = parse_continue(argv)
assert actual == expected, (argv, actual, expected)
print("continuation override forms parse as model/thinking values and preserve the prompt")
PYRepository: Waishnav/devspace
Length of output: 50373
Document continuation option overrides.
Because devspace agents continue accepts and forwards --model and --thinking, add examples for both options to the continuation section.
🤖 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 `@skills/subagent-delegation/SKILL.md` around lines 37 - 38, Update the
continuation section describing `continue <id> "<prompt>"` to include examples
demonstrating both supported overrides, `--model` and `--thinking`, while
preserving the existing guidance not to use `run <id>` for continuation.
| function codexAvailability(env: NodeJS.ProcessEnv): LocalAgentProviderAvailability { | ||
| const command = resolveCodexCommand(env); | ||
| if (!command) { | ||
| return { name: "codex", available: false, reason: "codex executable not found" }; | ||
| } | ||
| if (!isCodexAppServerSupported(command.executable, codexCommandEnvironment(env))) { | ||
| return { name: "codex", available: false, reason: "codex app-server is not supported" }; | ||
| } | ||
| return { name: "codex", available: true }; | ||
| return commandAvailability("codex", env.CODEX_COMMAND ?? "codex", env); | ||
| } | ||
|
|
||
| function commandAvailability( | ||
| provider: LocalAgentProvider, | ||
| command: string, | ||
| options: { env?: NodeJS.ProcessEnv } = {}, | ||
| env: NodeJS.ProcessEnv, | ||
| ): LocalAgentProviderAvailability { | ||
| const executable = resolveCommand(command, options.env); | ||
| if (!executable) { | ||
| return { | ||
| name: provider, | ||
| available: false, | ||
| reason: `${command} executable not found`, | ||
| }; | ||
| } | ||
|
|
||
| return { name: provider, available: true }; | ||
| if (resolveCommand(command, env)) return { name: provider, available: true }; | ||
| return { | ||
| name: provider, | ||
| available: false, | ||
| reason: `${command} executable not found`, | ||
| }; | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Trace availability reporting surfaces and remaining app-server checks.
set -euo pipefail
rg -nP --type=ts -C4 '\b(getLocalAgentProviderAvailabilitySnapshot|formatLocalAgentProviderAvailabilitySummary)\s*\('
echo "---- app-server support checks ----"
rg -nP --type=ts -C4 'app-server|isCodexAppServerSupported'
echo "---- docs mentioning codex availability ----"
rg -n --glob '*.md' -C3 'app-server|codex executable'Repository: Waishnav/devspace
Length of output: 155
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- candidate files ----"
git ls-files | grep -E '(^|/)(local-agent|server|cli|daemon|README|AGENTS).*' | head -200
echo "---- availability identifiers and app-server terms ----"
rg -n -C3 'getLocalAgentProviderAvailabilitySnapshot|formatLocalAgentProviderAvailabilitySummary|codexAvailability|commandAvailability|isCodexAppServerSupported|app-server|Codex provider is not available' . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' || true
echo "---- local-agent file outlines ----"
for f in $(git ls-files 'src/local-agent*.ts'); do
echo "### $f"
ast-grep outline "$f" 2>/dev/null || true
doneRepository: Waishnav/devspace
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- availability implementation ----"
cat -n src/local-agent-availability.ts | sed -n '1,135p'
echo "---- CLI status output ----"
cat -n src/cli.ts | sed -n '180,230p'
echo "---- server startup output and snapshot ----"
cat -n src/server.ts | sed -n '1675,1710p'
cat -n src/server.ts | sed -n '1895,1932p'
echo "---- manager runtime creation and error propagation ----"
cat -n src/local-agent-manager.ts | sed -n '45,125p'
cat -n src/local-agent-manager.ts | sed -n '200,335p'
echo "---- daemon protocol/client error surfaces ----"
cat -n src/local-agent-daemon.ts | sed -n '100,300p'
cat -n src/local-agent-client.ts | sed -n '40,180p'
cat -n src/local-agent-daemon-protocol.ts | sed -n '1,80p'
echo "---- relevant docs ----"
rg -n -C3 'app-server|subagent providers|codex' README.md docs .agents/plan AGENTS.md --glob '*.md' | head -240
echo "---- relevant tests ----"
rg -n -C4 'app-server|availability|subagent providers|codex executable|does not support' src/*.test.ts | head -260Repository: Waishnav/devspace
Length of output: 49902
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- manager begin/start lifecycle ----"
cat -n src/local-agent-manager.ts | sed -n '120,205p'
echo "---- server local-agent handlers and client calls ----"
rg -n -C5 'localAgentClient|agent\.start|agent\.continue|agent\.get|agent\.list|subagent' src/server.ts src/*.ts --glob '!src/local-agent-manager.ts' | head -320
echo "---- availability and Codex tests ----"
cat -n src/local-agent-availability.test.ts | sed -n '1,100p'
cat -n src/local-agent-codex.test.ts | sed -n '1,85p'
cat -n src/local-agent-codex.ts | sed -n '186,220p'
echo "---- focused read-only invariant verifier ----"
python3 - <<'PY'
from pathlib import Path
availability = Path("src/local-agent-availability.ts").read_text()
cli = Path("src/cli.ts").read_text()
server = Path("src/server.ts").read_text()
codex = Path("src/local-agent-codex.ts").read_text()
docs = Path("docs/agent-profile-schema.md").read_text()
checks = {
"codex availability delegates to executable-only command check":
'return commandAvailability("codex", env.CODEX_COMMAND ?? "codex", env);' in availability,
"summary has no app-server wording":
"app-server" not in availability,
"cli prints availability summary":
"formatLocalAgentProviderAvailabilitySummary(localAgentProviders)" in cli,
"server snapshots availability":
"getLocalAgentProviderAvailabilitySnapshot()" in server,
"server prints availability summary":
"formatLocalAgentProviderAvailabilitySummary(localAgentProviders)" in server,
"runtime checks app-server support":
"isCodexAppServerSupported(command.executable, this.env)" in codex,
"runtime error names app-server requirement":
"the installed codex does not support app-server." in codex,
"docs name codex app-server command":
"`codex app-server` command" in docs,
}
for name, result in checks.items():
print(f"{'PASS' if result else 'FAIL'}: {name}")
PYRepository: Waishnav/devspace
Length of output: 30322
Explain the Codex app-server requirement in availability output.
The CLI and server summaries report Codex as available when only the executable exists. createRuntime then rejects installations without app-server support, and the daemon initially returns a running record before storing the later failure. Keep the side-effect-free check, but label it as executable-only and show the app-server requirement in these user-facing summaries.
🤖 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/local-agent-availability.ts` around lines 82 - 97, Update
codexAvailability and the related CLI/server availability summaries to
distinguish executable-only detection from full Codex availability, explicitly
stating that app-server support is required. Keep commandAvailability
side-effect-free and preserve its executable resolution check, but ensure
user-facing output does not report Codex as fully available when app-server
support is absent.
| const extensions = process.platform === "win32" | ||
| ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD") | ||
| .split(";") | ||
| .filter(Boolean) | ||
| ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) | ||
| : [""]; | ||
| const candidates: string[] = []; | ||
| for (const directory of path.split(delimiter)) { | ||
| if (!directory) continue; | ||
| for (const extension of extensions) { | ||
| candidates.push(resolve(directory, `${command}${extension}`)); | ||
| const candidate = resolve(directory, `${command}${extension}`); | ||
| if (executableExists(candidate)) return candidate; | ||
| } | ||
| } | ||
| return candidates; | ||
| return undefined; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Windows lookup misses a command that already carries an extension.
On win32, extensions contains only PATHEXT entries. It never contains an empty string. So resolveCommand probes codex.exe.COM, codex.exe.EXE, and so on, and it never probes codex.exe itself. A user who sets CODEX_COMMAND=codex.exe, CURSOR_COMMAND=cursor-agent.cmd, or COPILOT_COMMAND=copilot.exe without a path separator gets available: false even when the executable is on PATH.
Probe the bare name first, then the PATHEXT variants.
🐛 Proposed fix
const extensions = process.platform === "win32"
- ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)
+ ? ["", ...(env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)]
: [""];📝 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.
| const extensions = process.platform === "win32" | |
| ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD") | |
| .split(";") | |
| .filter(Boolean) | |
| ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) | |
| : [""]; | |
| const candidates: string[] = []; | |
| for (const directory of path.split(delimiter)) { | |
| if (!directory) continue; | |
| for (const extension of extensions) { | |
| candidates.push(resolve(directory, `${command}${extension}`)); | |
| const candidate = resolve(directory, `${command}${extension}`); | |
| if (executableExists(candidate)) return candidate; | |
| } | |
| } | |
| return candidates; | |
| return undefined; | |
| const extensions = process.platform === "win32" | |
| ? ["", ...(env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)] | |
| : [""]; | |
| for (const directory of path.split(delimiter)) { | |
| if (!directory) continue; | |
| for (const extension of extensions) { | |
| const candidate = resolve(directory, `${command}${extension}`); | |
| if (executableExists(candidate)) return candidate; | |
| } | |
| } | |
| return undefined; |
🤖 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/local-agent-availability.ts` around lines 105 - 115, Update
resolveCommand so the Windows extensions list always probes the bare command
name before PATHEXT variants by including an empty extension first. Preserve the
existing PATHEXT fallback and path iteration behavior, ensuring commands already
ending in extensions such as .exe or .cmd are checked directly.
| runtimeKey(context: LocalAgentRuntimeContext): string { | ||
| return `claude:${context.agentId}`; | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does the Claude Agent SDK query object apply sandbox settings changes to a running session at runtime?
💡 Result:
The Claude Agent SDK does not support applying changes to sandbox settings at runtime for a running session [1][2]. While the SDK provides an applyFlagSettings() method (available in the Query object) to update certain settings on a running session, this method is intended for general settings like permissions or models [1][3]. The sandbox configuration is defined within the ClaudeAgentOptions object at the time the session (or query instance) is initialized [2][4]. If you need to change sandbox settings mid-session, you must start a new session or reinitialize the query [3]. Additionally, some configurations, such as system prompt options, are resolved once at startup and also require a new session to modify [3]. For dynamic control over tool operations (such as redirecting file access) while a session is running, you can use hooks, which allow you to intercept and modify tool inputs programmatically [5][6].
Citations:
- 1: https://code.claude.com/docs/en/agent-sdk/typescript.md
- 2: https://code.claude.com/docs/en/agent-sdk/python
- 3: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-typescript
- 4: https://anthropics-claude-agent-sdk-python-82.mintlify.app/api/types/claude-agent-options
- 5: https://github.com/anthropics/claude-agent-sdk-python?tab=readme-ov-file
- 6: https://code.claude.com/docs/en/agent-sdk/hooks
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- target file outline ---'
ast-grep outline src/local-agent-claude.ts
printf '%s\n' '--- relevant Claude implementation ---'
sed -n '130,240p' src/local-agent-claude.ts
printf '%s\n' '--- runtime key and write-mode references ---'
rg -n -C 4 'runtimeKey|writeMode|applyFlagSettings|claudeQueryOptions|sandbox' src/local-agent-claude.ts src/local-agent-acp.ts srcRepository: Waishnav/devspace
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- Claude runtime turn behavior ---'
sed -n '60,115p' src/local-agent-claude.ts
printf '%s\n' '--- Claude authority and environment helpers ---'
sed -n '241,318p' src/local-agent-claude.ts
printf '%s\n' '--- runtime-pool reuse path ---'
sed -n '175,235p' src/local-agent-runtime-pool.ts
printf '%s\n' '--- Claude tests around reuse and mode transitions ---'
sed -n '1,155p' src/local-agent-claude.test.ts
printf '%s\n' '--- context and runtime-key contracts ---'
rg -n -C 3 'interface LocalAgentRuntimeContext|type LocalAgentRuntimeContext|agentId:|workspaceRoot:|runtimeKey\\(' src --glob '*.ts'Repository: Waishnav/devspace
Length of output: 12159
🌐 Web query:
site:code.claude.com/docs/en/agent-sdk/typescript applyFlagSettings sandbox options query runtime
💡 Result:
The applyFlagSettings function is a method within the Agent SDK (specifically documented for TypeScript) used to update configuration settings during an active session [1]. It allows developers to modify settings for a running session without needing to restart the query [1]. This method is intended for use cases where a specific setting lacks a dedicated setter function, enabling dynamic configuration changes mid-runtime [1].
Citations:
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- official Claude SDK documentation references ---'
curl -L --fail --silent --show-error 'https://code.claude.com/docs/en/agent-sdk/typescript' |
rg -n -i -C 4 'applyFlagSettings|sandbox|ClaudeAgentOptions|query' | head -n 160
printf '%s\n' '--- runtime context declarations and driver call sites ---'
rg -n -F -C 4 'LocalAgentRuntimeContext' src --glob '*.ts'
rg -n -F -C 4 'driver.runtimeKey' src --glob '*.ts'Repository: Waishnav/devspace
Length of output: 50374
🌐 Web query:
Claude Agent SDK TypeScript applyFlagSettings sandbox setting change running query implementation
💡 Result:
In the Claude Agent SDK for TypeScript, the applyFlagSettings function is designed to modify specific settings on a running session without requiring a restart [1][2]. While applyFlagSettings allows for runtime adjustments of various configuration keys (such as model, agent, or effortLevel), it is primarily used for general settings keys [1]. According to official documentation and SDK behavior, sandbox settings are typically defined during session initialization via the options object passed to query or other session creation functions [1][3]. Key points regarding the use of applyFlagSettings and sandbox configuration: 1. Runtime Adjustments: applyFlagSettings is specifically intended for scenarios where a setting has no dedicated setter and needs to be updated mid-session [1]. While it accepts a subset of settings keys, sandbox-specific configuration is generally managed through the immutable initialization options for a session to ensure the integrity of the isolated environment [4][3]. 2. Sandbox Configuration: Sandbox settings are defined using the SandboxSettings interface within the session options, which includes parameters like enabled, excludedCommands, and allowUnsandboxedCommands [3]. These configurations are established when the agent loop starts [1][5]. 3. Precedence: The SDK uses a hierarchical precedence model for settings, where programmatic options (passed to query) take precedence over filesystem-based settings [2]. Settings applied via applyFlagSettings fall into the "flag-settings" layer, which is designed for programmatic overrides [1][2]. 4. Implementation: If you need to change sandbox behavior, you should generally instantiate a new session with the desired SandboxSettings, as changing fundamental security and isolation boundaries (like the sandbox) on a running process is often restricted to maintain environment stability [1][4]. For authoritative guidance, refer to the TypeScript SDK documentation, which highlights that applyFlagSettings is best used for non-structural settings like model switching or adjusting effort levels while an agent loop is active [1].
Citations:
- 1: https://code.claude.com/docs/en/agent-sdk/typescript.md
- 2: https://deepwiki.com/anthropics/claude-agent-sdk-typescript/3.3-configuration-system
- 3: https://agnt.gg/articles/claude-agent-sdk-cheatsheet
- 4: https://code.claude.com/docs/en/sandboxing
- 5: https://code.claude.com/docs/en/agent-sdk/quickstart.md
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
from urllib.request import urlopen
source = Path("src/local-agent-claude.ts").read_text()
key = re.search(r'return `([^`]*context\.agentId[^`]*)`;', source)
assert key, "Claude runtime key not found"
print("runtime_key_template:", key.group(1))
print("same_key_for_modes:", all(
key.group(1).replace("${context.agentId}", "agt")
== key.group(1).replace("${context.agentId}", "agt")
for _ in ["read_only", "allowed", "full_access"]
))
def authority(mode):
if mode == "full_access":
return {"enabled": False, "allowUnsandboxedCommands": True}
return {"enabled": True, "allowUnsandboxedCommands": False}
print("sandbox_by_mode:", {mode: authority(mode) for mode in ["read_only", "allowed", "full_access"]})
assert len({repr(authority(mode)) for mode in ["read_only", "allowed", "full_access"]}) == 3
html = urlopen("https://code.claude.com/docs/en/agent-sdk/typescript").read().decode()
for term in ["applyFlagSettings", "SandboxSettings", "sandbox configuration"]:
positions = [m.start() for m in re.finditer(term, html, re.I)]
print(f"{term}_occurrences:", len(positions))
for pos in positions[:2]:
excerpt = re.sub(r"<[^>]+>", " ", html[max(0, pos-500):pos+900])
excerpt = re.sub(r"\s+", " ", excerpt)
print(excerpt[:1200])
PYRepository: Waishnav/devspace
Length of output: 536
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
source = Path("src/local-agent-claude.ts").read_text()
key = re.search(r'return `([^`]*context\.agentId[^`]*)`;', source)
assert key, "Claude runtime key not found"
template = key.group(1)
print("runtime_key_template:", template)
print("all_write_modes_share_key: True")
assert "context.writeMode" not in template
modes = ["read_only", "allowed", "full_access"]
sandbox = {
"read_only": {"enabled": True, "allowUnsandboxedCommands": False},
"allowed": {"enabled": True, "allowUnsandboxedCommands": False},
"full_access": {"enabled": False, "allowUnsandboxedCommands": True},
}
assert sandbox["read_only"] == sandbox["allowed"]
assert sandbox["full_access"] != sandbox["read_only"]
print("full_access_differs_from_restricted_modes: True")
print("sandbox_by_mode:", sandbox)
PYRepository: Waishnav/devspace
Length of output: 502
Include the write mode in the Claude runtime key.
The runtime pool reuses the same Claude query for every write mode. A full_access query disables the sandbox and can serve a later restricted turn. Include context.writeMode in the key, as the ACP driver does.
🧰 Tools
🪛 ast-grep (0.45.1)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🤖 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/local-agent-claude.ts` around lines 166 - 168, Update
LocalAgentClaude.runtimeKey to include context.writeMode alongside
context.agentId, ensuring runtime pool entries remain distinct for each write
mode while preserving the existing Claude key prefix.
Source: Coding guidelines
| if (record.workspaceId !== scope.workspaceId) { | ||
| throw new Error(`Subagent ${record.id} belongs to a different workspace.`); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the scope type and every caller of the workspace-scoped manager methods.
ast-grep outline src --items all --match 'LocalAgentWorkspaceScope|LocalAgentListScope'
rg -nP --type=ts -C4 'LocalAgentWorkspaceScope\b'
rg -nP --type=ts -C4 '\.(continue|get)\(\s*[^)]*(workspaceRoot|scope)' -g '!**/*.test.ts'Repository: Waishnav/devspace
Length of output: 527
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- scope and manager definitions ---'
rg -n -C8 'interface LocalAgentWorkspaceScope|type LocalAgentWorkspaceScope|class LocalAgentManager|async? (get|continue)|\b(get|continue)\(' src/local-agent-store.ts src/local-agent-manager.ts src -g '*.ts' | head -n 500
printf '%s\n' '--- all LocalAgentManager method calls and scope construction ---'
rg -n -C5 --type=ts 'localAgentManager|agentManager|LocalAgentWorkspaceScope|decodeWorkspaceScope|workspaceRoot:|workspaceId:' src | head -n 800
printf '%s\n' '--- protocol decoders ---'
cat -n src/local-agent-daemon-protocol.ts | sed -n '1,260p'Repository: Waishnav/devspace
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- manager workspace assertion and nearby methods ---'
cat -n src/local-agent-manager.ts | sed -n '90,155p;300,345p'
printf '%s\n' '--- protocol scope decoders and request schemas ---'
rg -n -C12 'decodeWorkspaceScope|decodeContinueInput|decodeAgent.*Input|agent\.continue|agent\.get' src/local-agent-daemon-protocol.ts src/local-agent-daemon.ts
printf '%s\n' '--- direct client and manager call sites ---'
rg -n -C3 --type=ts '\.(continue|get)\([^;]*\b(scope|workspaceRoot|workspaceId)|\.continue\(|\.get\(' src/local-agent-client.ts src/local-agent-daemon.ts src/server.ts src -g '!local-agent-codex.ts' -g '!local-agent-acp.ts' | rg -v 'sqlite|Map|pending|turns|registry|database|\.get\(' | head -n 300Repository: Waishnav/devspace
Length of output: 31544
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- manager tests and record shapes ---'
cat -n src/local-agent-manager.test.ts | sed -n '1,190p'
printf '%s\n' '--- all local-agent client method invocations ---'
rg -n -C4 --type=ts '\b(localAgentClient|agentClient|client)\.(start|run|continue|get|list)\(' src | head -n 400
printf '%s\n' '--- all workspaceId assignments in local-agent inputs and records ---'
rg -n -C4 --type=ts 'workspaceId' src/local-agent-*.ts | head -n 600Repository: Waishnav/devspace
Length of output: 24527
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- current workspace scope resolution ---'
rg -n -C12 'function resolveCurrentWorkspaceScope|const resolveCurrentWorkspaceScope|resolveCurrentWorkspaceScope' src/cli.ts src -g '*.ts' | head -n 240
printf '%s\n' '--- daemon client scope signatures and protocol tests ---'
cat -n src/local-agent-client.ts | sed -n '45,105p'
rg -n -C5 --type=ts 'workspaceId.*DEVSPACE_WORKSPACE_ID|DEVSPACE_WORKSPACE_ID.*workspaceId|workspaceId.*scope|scope.*workspaceId' src/cli.ts src/local-agent-*.test.ts src | head -n 300
printf '%s\n' '--- behavioral probe of the assertion condition ---'
python3 - <<'PY'
cases = [
("stored workspace ID, root-only scope", "ws_1", None, "/workspace", "/workspace"),
("legacy record, matching root-only scope", None, None, "/workspace", "/workspace"),
("stored workspace ID, matching full scope", "ws_1", "ws_1", "/workspace", "/workspace"),
("stored workspace ID, wrong ID", "ws_1", "ws_2", "/workspace", "/workspace"),
]
for label, record_id, scope_id, record_root, scope_root in cases:
root_mismatch = scope_root != record_root
id_mismatch = record_id != scope_id
print(f"{label}: root_mismatch={root_mismatch}, id_mismatch={id_mismatch}, rejects={root_mismatch or id_mismatch}")
PYRepository: Waishnav/devspace
Length of output: 19284
Make workspace scope mandatory for get and continue.
resolveCurrentWorkspaceScope() can omit workspaceId, so matching root-only scopes reject records with a stored ID. The optional manager scope also lets direct callers skip assertAgentWorkspace. Require workspaceId and scope, then use distinct errors for ID and root mismatches.
🤖 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/local-agent-manager.ts` around lines 318 - 320, Update the get and
continue flows in the agent manager to require both a workspace scope and its
workspaceId, and ensure direct callers invoke assertAgentWorkspace before
accessing records. In the workspace validation around record.workspaceId and
scope, distinguish mismatched workspace IDs from mismatched workspace roots with
separate errors, while preserving validation for matching scopes.
da68ab3 to
aca2f57
Compare
Claude's streaming query API can accept multiple user messages, but DevSpace previously created a fresh query for every prompt. This final stacked change keeps one query warm per logical Claude agent, resumes cold sessions from the persisted provider id, and completes the native driver registry, provider availability checks, package cleanup, and lifecycle documentation for the full runtime stack.
Summary by CodeRabbit