@waishnav/devspace 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apply-patch.js +67 -64
- package/dist/cli.js +243 -4
- package/dist/config.js +6 -9
- package/dist/db/migrations.js +34 -0
- package/dist/db/schema.js +19 -0
- package/dist/local-agent-adapters.js +653 -0
- package/dist/local-agent-availability.js +119 -0
- package/dist/local-agent-path.js +24 -0
- package/dist/local-agent-profiles.js +135 -0
- package/dist/local-agent-runtime.js +48 -0
- package/dist/local-agent-store.js +145 -0
- package/dist/local-agent-targets.js +80 -0
- package/dist/process-sessions.js +11 -3
- package/dist/server.js +88 -50
- package/dist/skills.js +27 -3
- package/dist/ui/.vite/manifest.json +281 -281
- package/dist/ui/assets/{angular-html-D6nc7PYw.js → angular-html-CKeFzaPY.js} +1 -1
- package/dist/ui/assets/{angular-ts-BAIStLeI.js → angular-ts-0wcM_Zxf.js} +1 -1
- package/dist/ui/assets/{apl-CtEv5pop.js → apl-C7UdkNb2.js} +1 -1
- package/dist/ui/assets/{astro-CVFIMXc6.js → astro-DMqju4MJ.js} +1 -1
- package/dist/ui/assets/{blade-BgSlZ6jY.js → blade-DHanNgN5.js} +1 -1
- package/dist/ui/assets/{c-bxLlCV26.js → c-_iPKYPcx.js} +1 -1
- package/dist/ui/assets/{cobol-BuZ-r51r.js → cobol-CagdLJsE.js} +1 -1
- package/dist/ui/assets/{coffee-_JP0Joa7.js → coffee-CkNGriPi.js} +1 -1
- package/dist/ui/assets/{cpp-CP_eaz-H.js → cpp-CqmKOWIQ.js} +1 -1
- package/dist/ui/assets/{crystal-DZ-sEZd0.js → crystal-DbAbDEO1.js} +1 -1
- package/dist/ui/assets/{css-CZnyti9s.js → css-xwljL6Kw.js} +1 -1
- package/dist/ui/assets/{edge-DjsoDMTR.js → edge-CX3sYz15.js} +1 -1
- package/dist/ui/assets/{elixir-C5b04AkY.js → elixir-B3qL9hqd.js} +1 -1
- package/dist/ui/assets/{elm-Ddx-rgVY.js → elm-CH4vrjBp.js} +1 -1
- package/dist/ui/assets/{erb-cjF7oPcT.js → erb-CupHqynN.js} +1 -1
- package/dist/ui/assets/{git-rebase-DN5exBTl.js → git-rebase-CDxsU2LC.js} +1 -1
- package/dist/ui/assets/{glimmer-js-CEq0hNwa.js → glimmer-js-emkga3g1.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-4uYGFkon.js → glimmer-ts-D8kQDnUw.js} +1 -1
- package/dist/ui/assets/{glsl-DEJ9tTWm.js → glsl-BtfTaPhi.js} +1 -1
- package/dist/ui/assets/{graphql-Bim5WuQh.js → graphql-DEus8iSO.js} +1 -1
- package/dist/ui/assets/{hack-BcyVIXhE.js → hack-DI8qpBqE.js} +1 -1
- package/dist/ui/assets/{haml-D9YaukDg.js → haml-Br1i1gmi.js} +1 -1
- package/dist/ui/assets/{handlebars-CFaMw9zH.js → handlebars-Ce23mu9x.js} +1 -1
- package/dist/ui/assets/{heavy-payload-B9aTqgfs.js → heavy-payload-BcZ_nGfF.js} +1 -1
- package/dist/ui/assets/{html-CgO_zx4D.js → html-RXVmfixf.js} +1 -1
- package/dist/ui/assets/{html-derivative-BxqkysJT.js → html-derivative-D1aqeobb.js} +1 -1
- package/dist/ui/assets/{http-CO5dv0RA.js → http-BebG00CE.js} +1 -1
- package/dist/ui/assets/{hurl-DRHtrK78.js → hurl-kHMuvenL.js} +1 -1
- package/dist/ui/assets/{java-BvHC_DgR.js → java-DYc2V5RJ.js} +1 -1
- package/dist/ui/assets/{javascript-C-3payQx.js → javascript-BcfzTzr3.js} +1 -1
- package/dist/ui/assets/{jinja-CAOPvEOH.js → jinja-D2RhihUZ.js} +1 -1
- package/dist/ui/assets/{jison-totCB1L-.js → jison-BuoFEePN.js} +1 -1
- package/dist/ui/assets/{json-D0J9rEe1.js → json-BIDkCuJA.js} +1 -1
- package/dist/ui/assets/{jsx-na-XQD_B.js → jsx-DHCL2HA0.js} +1 -1
- package/dist/ui/assets/{julia-CqrTtZ4-.js → julia-CvUQXscF.js} +1 -1
- package/dist/ui/assets/{just-pmrVSkMc.js → just-etc9R2qw.js} +1 -1
- package/dist/ui/assets/{latex-Cd_geX3E.js → latex-BB3zRnxC.js} +1 -1
- package/dist/ui/assets/{liquid-C6ky5sJ-.js → liquid-CIi5Mvpv.js} +1 -1
- package/dist/ui/assets/{lua-dgyBbeof.js → lua-Cox7XDiW.js} +1 -1
- package/dist/ui/assets/{marko-Dy5mfXY9.js → marko-ruBIRV0n.js} +1 -1
- package/dist/ui/assets/{mdc-7NUvxgI1.js → mdc-CcbvB9U5.js} +1 -1
- package/dist/ui/assets/{nginx-C-KiEXbI.js → nginx-DtWz6ZYE.js} +1 -1
- package/dist/ui/assets/{nim-BBw8kfl9.js → nim-BV5BR4P7.js} +1 -1
- package/dist/ui/assets/{perl-CyxhJgbO.js → perl-BvzoSaJ4.js} +1 -1
- package/dist/ui/assets/{php-m4LAOpam.js → php-C-clrAOy.js} +1 -1
- package/dist/ui/assets/{pug-Cpl0baYI.js → pug-E07_GXAr.js} +1 -1
- package/dist/ui/assets/{qml-BoSGNgIb.js → qml-dqt33dti.js} +1 -1
- package/dist/ui/assets/{r-C0JhqQd5.js → r-BcVQxsAw.js} +1 -1
- package/dist/ui/assets/{razor-CntsBNoh.js → razor-BW5T_UZ-.js} +1 -1
- package/dist/ui/assets/{regexp-BNZmOCRl.js → regexp-Ed_DEsuU.js} +1 -1
- package/dist/ui/assets/{review-payload-BgdWHWiv.js → review-payload-Dsmx33pY.js} +1 -1
- package/dist/ui/assets/{rst-BZ2XHIxM.js → rst-BkcGqLs8.js} +1 -1
- package/dist/ui/assets/{ruby-BIthfCTP.js → ruby-Sf_X_YID.js} +1 -1
- package/dist/ui/assets/{sas-5aT3fOla.js → sas-COsombsA.js} +1 -1
- package/dist/ui/assets/{scss-DZPfdkDy.js → scss-K6Ylfa26.js} +1 -1
- package/dist/ui/assets/{shellscript-DbhKc5Xj.js → shellscript-D2EdqkgV.js} +1 -1
- package/dist/ui/assets/{shellsession-X9-bcyHh.js → shellsession-jRXgXrnI.js} +1 -1
- package/dist/ui/assets/{soy-Bd4tecrW.js → soy-BGspKQWW.js} +1 -1
- package/dist/ui/assets/{sql-Chf5JrDn.js → sql-C4lAmYnM.js} +1 -1
- package/dist/ui/assets/{stata-DvMMIc_T.js → stata-DQWvRqxp.js} +1 -1
- package/dist/ui/assets/{surrealql-D5FMzVF5.js → surrealql-OmKt9XJ_.js} +1 -1
- package/dist/ui/assets/{svelte-CTiVXZrv.js → svelte-D0rUmwDI.js} +1 -1
- package/dist/ui/assets/{templ-ldnfq-7w.js → templ-B-U0RMc0.js} +1 -1
- package/dist/ui/assets/{tex-QW0_7T2r.js → tex-BIHD-btS.js} +1 -1
- package/dist/ui/assets/{ts-tags-CAKiWIBx.js → ts-tags-CGuDWfPC.js} +1 -1
- package/dist/ui/assets/{tsx-Bu9xJJmq.js → tsx-B0-h_HlD.js} +1 -1
- package/dist/ui/assets/{twig-Dp1752_V.js → twig-BN2qDJWN.js} +1 -1
- package/dist/ui/assets/{typescript-RfO03Kmm.js → typescript-BRnwPzY3.js} +1 -1
- package/dist/ui/assets/{useFileDiffInstance-DjqU4y1a.js → useFileDiffInstance-5ivdkUYO.js} +3 -3
- package/dist/ui/assets/{vue-Dlasv57G.js → vue-DekNU1qt.js} +1 -1
- package/dist/ui/assets/{vue-html-BHuJ7anu.js → vue-html-Bjlv-uvH.js} +1 -1
- package/dist/ui/assets/{vue-vine-CavE0PSk.js → vue-vine-C2Doytjq.js} +1 -1
- package/dist/ui/assets/{workspace-app-DGD9R89D.css → workspace-app-DASlX26z.css} +1 -1
- package/dist/ui/assets/{workspace-app-DDV_qdjx.js → workspace-app-DYi7VJam.js} +5 -5
- package/dist/ui/assets/{xml-Bbv64l4W.js → xml-pXbxxgI3.js} +1 -1
- package/dist/ui/assets/{xsl-Sro4gyQY.js → xsl-BEAlgDI2.js} +1 -1
- package/dist/ui/assets/{yaml-Du68c8sA.js → yaml-C1O-To71.js} +1 -1
- package/dist/ui/workspace-app.html +2 -2
- package/dist/user-config.js +21 -1
- package/dist/workspaces.js +3 -0
- package/docs/agent-profile-schema.md +165 -0
- package/docs/chatgpt-coding-workflow.md +24 -10
- package/docs/configuration.md +20 -8
- package/docs/gotchas.md +13 -0
- package/examples/agents/claude-implementer.md +30 -0
- package/examples/agents/codex-explorer.md +27 -0
- package/examples/agents/codex-qa-tester.md +29 -0
- package/examples/agents/codex-worker.md +25 -0
- package/examples/agents/copilot-reviewer.md +25 -0
- package/examples/agents/cursor-agent-worker.md +26 -0
- package/examples/agents/opencode-explorer.md +27 -0
- package/examples/agents/pi-reviewer.md +27 -0
- package/package.json +11 -3
- package/skills/subagent-delegation/SKILL.md +132 -0
- package/docs/codex-tool-mode-qa.md +0 -73
package/dist/server.js
CHANGED
|
@@ -22,6 +22,8 @@ import { createReviewCheckpointManager } from "./review-checkpoints.js";
|
|
|
22
22
|
import { formatPathForPrompt } from "./skills.js";
|
|
23
23
|
import { createWorkspaceStore } from "./workspace-store.js";
|
|
24
24
|
import { formatAgentsPath, WorkspaceRegistry } from "./workspaces.js";
|
|
25
|
+
import { summarizeLocalAgentProfile } from "./local-agent-profiles.js";
|
|
26
|
+
import { formatLocalAgentProviderAvailabilitySummary, getLocalAgentProviderAvailabilitySnapshot, } from "./local-agent-availability.js";
|
|
25
27
|
const WORKSPACE_APP_URI = "ui://devspace/workspace-app.html";
|
|
26
28
|
const WORKSPACE_APP_MANIFEST_ENTRY = "workspace-app.html";
|
|
27
29
|
const WRITE_TOOL_ANNOTATIONS = {
|
|
@@ -64,32 +66,22 @@ function toolWidgetDescriptorMeta(config, kind) {
|
|
|
64
66
|
},
|
|
65
67
|
};
|
|
66
68
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
read: "read_file",
|
|
82
|
-
write: "write_file",
|
|
83
|
-
edit: "edit_file",
|
|
84
|
-
grep: "grep_files",
|
|
85
|
-
glob: "find_files",
|
|
86
|
-
ls: "list_directory",
|
|
87
|
-
shell: "run_shell",
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
function serverInstructions(config, toolNames) {
|
|
69
|
+
const toolNames = {
|
|
70
|
+
openWorkspace: "open_workspace",
|
|
71
|
+
read: "read",
|
|
72
|
+
write: "write",
|
|
73
|
+
edit: "edit",
|
|
74
|
+
grep: "grep",
|
|
75
|
+
glob: "glob",
|
|
76
|
+
ls: "ls",
|
|
77
|
+
shell: "bash",
|
|
78
|
+
};
|
|
79
|
+
function serverInstructions(config) {
|
|
80
|
+
const showChangesInstruction = config.widgets === "changes"
|
|
81
|
+
? " If the turn successfully modifies files by creating, editing, overwriting, deleting, moving, or applying patches, call show_changes exactly once for that workspace after the final related file change and before your final response so the user can inspect the aggregate diff for that turn. Do not call it after every individual file change; do not skip it because individual file-change tools already returned diffs."
|
|
82
|
+
: "";
|
|
91
83
|
if (config.toolMode === "codex") {
|
|
92
|
-
return `Use DevSpace as a local coding workspace. Call ${toolNames.openWorkspace} once per project folder or worktree and reuse its workspaceId. Use ${toolNames.read} for direct file reads, apply_patch for all file modifications, exec_command for inspection, tests, builds, and other commands, and write_stdin to poll or interact with running processes. Follow instructions returned by ${toolNames.openWorkspace}; read applicable instruction and skill files before working in their scope
|
|
84
|
+
return `Use DevSpace as a local coding workspace. Call ${toolNames.openWorkspace} once per project folder or worktree and reuse its workspaceId. Use ${toolNames.read} for direct file reads, apply_patch for all file modifications, exec_command for inspection, tests, builds, and other commands, and write_stdin to poll or interact with running processes. Follow instructions returned by ${toolNames.openWorkspace}; read applicable instruction and skill files before working in their scope.${showChangesInstruction}`;
|
|
93
85
|
}
|
|
94
86
|
const inspection = config.toolMode !== "full"
|
|
95
87
|
? `In minimal tool mode, ${toolNames.grep}, ${toolNames.glob}, and ${toolNames.ls} are disabled; use ${toolNames.shell} with command-line tools such as grep, rg, find, ls, and tree for search and directory inspection. `
|
|
@@ -98,10 +90,18 @@ function serverInstructions(config, toolNames) {
|
|
|
98
90
|
? `When ${toolNames.openWorkspace} returns available skills and a task matches a skill, use ${toolNames.read} to read that skill's path before proceeding. Skill paths may be outside the workspace, but ${toolNames.read} only permits advertised SKILL.md files and files under already-loaded skill directories. `
|
|
99
91
|
: "";
|
|
100
92
|
const agentsMd = `Follow instructions returned by ${toolNames.openWorkspace}. Before working under a path listed in availableAgentsFiles, use ${toolNames.read} to inspect that instruction file and follow it. `;
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
return `Use DevSpace as a local coding workspace. Call ${toolNames.openWorkspace} once per project folder or worktree to obtain a workspaceId. Reuse that same workspaceId for all later file, search, edit, write, show-changes, and shell tools in that folder; do not call ${toolNames.openWorkspace} again unless switching folders/worktrees, changing checkout/worktree mode, the workspaceId is rejected as unknown, or the user explicitly asks to reopen. ${agentsMd}${skills}${inspection}Prefer ${toolNames.edit} for targeted modifications, ${toolNames.write} only for new files or complete rewrites, and ${toolNames.shell} for tests, builds, git inspection, package scripts, and commands that are better executed by the shell. Do not create or modify files with ${toolNames.shell}; avoid shell redirection, heredocs, tee, sed -i, perl -i, node/python/ruby scripts, or any command whose purpose is to write project files.${showChangesInstruction}`;
|
|
94
|
+
}
|
|
95
|
+
function formatVisibleAgent(agent) {
|
|
96
|
+
const model = agent.model ? `, model ${agent.model}` : "";
|
|
97
|
+
const thinking = agent.thinking ? `, thinking ${agent.thinking}` : "";
|
|
98
|
+
const availability = agent.providerAvailable === false
|
|
99
|
+
? `, unavailable: ${agent.providerUnavailableReason ?? "provider unavailable"}`
|
|
103
100
|
: "";
|
|
104
|
-
return
|
|
101
|
+
return `${agent.name} (${agent.provider}${model}${thinking}${availability})`;
|
|
102
|
+
}
|
|
103
|
+
function formatUnavailableAgentProvider(provider) {
|
|
104
|
+
return `${provider.name} (${provider.reason ?? "unavailable"})`;
|
|
105
105
|
}
|
|
106
106
|
function resultOutputSchema(extra = {}) {
|
|
107
107
|
return {
|
|
@@ -120,6 +120,20 @@ const workspaceAgentsFileOutputSchema = z.object({
|
|
|
120
120
|
path: z.string(),
|
|
121
121
|
content: z.string(),
|
|
122
122
|
});
|
|
123
|
+
const workspaceLocalAgentOutputSchema = z.object({
|
|
124
|
+
name: z.string(),
|
|
125
|
+
description: z.string(),
|
|
126
|
+
provider: z.string(),
|
|
127
|
+
model: z.string().optional(),
|
|
128
|
+
thinking: z.string().optional(),
|
|
129
|
+
providerAvailable: z.boolean().optional(),
|
|
130
|
+
providerUnavailableReason: z.string().optional(),
|
|
131
|
+
});
|
|
132
|
+
const workspaceLocalAgentProviderOutputSchema = z.object({
|
|
133
|
+
name: z.string(),
|
|
134
|
+
available: z.boolean(),
|
|
135
|
+
reason: z.string().optional(),
|
|
136
|
+
});
|
|
123
137
|
const workspaceAvailableAgentsFileOutputSchema = z.object({
|
|
124
138
|
path: z.string(),
|
|
125
139
|
});
|
|
@@ -383,6 +397,7 @@ function registerCodexProcessTools(server, config, workspaces, processSessions)
|
|
|
383
397
|
workspaceId,
|
|
384
398
|
command: cmd,
|
|
385
399
|
cwd,
|
|
400
|
+
workspaceRoot: workspace.root,
|
|
386
401
|
tty,
|
|
387
402
|
columns,
|
|
388
403
|
rows,
|
|
@@ -460,15 +475,14 @@ function registerCodexProcessTools(server, config, workspaces, processSessions)
|
|
|
460
475
|
});
|
|
461
476
|
});
|
|
462
477
|
}
|
|
463
|
-
function createMcpServer(config, workspaces, reviewCheckpoints, processSessions) {
|
|
464
|
-
const toolNames = toolNamesFor(config);
|
|
478
|
+
function createMcpServer(config, workspaces, reviewCheckpoints, processSessions, localAgentProviders) {
|
|
465
479
|
const server = new McpServer({
|
|
466
480
|
name: "devspace",
|
|
467
481
|
title: "DevSpace",
|
|
468
482
|
version: "0.1.0",
|
|
469
483
|
description: "Secure local coding workspace for MCP clients. Provides workspace-scoped file, search, edit, write, and shell tools.",
|
|
470
484
|
}, {
|
|
471
|
-
instructions: serverInstructions(config
|
|
485
|
+
instructions: serverInstructions(config),
|
|
472
486
|
});
|
|
473
487
|
registerAppResource(server, "DevSpace Diff Card", WORKSPACE_APP_URI, {
|
|
474
488
|
description: "Interactive card for viewing DevSpace file diffs.",
|
|
@@ -528,6 +542,8 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
528
542
|
agentsFiles: z.array(workspaceAgentsFileOutputSchema),
|
|
529
543
|
availableAgentsFiles: z.array(workspaceAvailableAgentsFileOutputSchema),
|
|
530
544
|
skills: z.array(workspaceSkillOutputSchema),
|
|
545
|
+
agentProviders: z.array(workspaceLocalAgentProviderOutputSchema),
|
|
546
|
+
agents: z.array(workspaceLocalAgentOutputSchema),
|
|
531
547
|
skillDiagnostics: z.array(z.unknown()),
|
|
532
548
|
instruction: z.string(),
|
|
533
549
|
},
|
|
@@ -549,6 +565,16 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
549
565
|
description: skill.description,
|
|
550
566
|
path: formatPathForPrompt(skill.filePath),
|
|
551
567
|
}));
|
|
568
|
+
const visibleAgentProviders = config.subagents ? localAgentProviders : [];
|
|
569
|
+
const visibleAgents = workspace.agentProfiles.map((profile) => {
|
|
570
|
+
const summary = summarizeLocalAgentProfile(profile);
|
|
571
|
+
const availability = visibleAgentProviders.find((provider) => provider.name === summary.provider);
|
|
572
|
+
return {
|
|
573
|
+
...summary,
|
|
574
|
+
providerAvailable: availability?.available,
|
|
575
|
+
providerUnavailableReason: availability?.reason,
|
|
576
|
+
};
|
|
577
|
+
});
|
|
552
578
|
const loadedAgentsFiles = agentsFiles.map((file) => ({
|
|
553
579
|
path: formatAgentsPath(file.path, workspace.root),
|
|
554
580
|
content: file.content,
|
|
@@ -575,6 +601,15 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
575
601
|
visibleSkills.length > 0
|
|
576
602
|
? `Available skills: ${visibleSkills.map((skill) => skill.name).join(", ")}`
|
|
577
603
|
: undefined,
|
|
604
|
+
visibleAgentProviders.some((provider) => provider.available)
|
|
605
|
+
? `Available subagent providers: ${visibleAgentProviders.filter((provider) => provider.available).map((provider) => provider.name).join(", ")}`
|
|
606
|
+
: undefined,
|
|
607
|
+
visibleAgentProviders.some((provider) => !provider.available)
|
|
608
|
+
? `Unavailable subagent providers: ${visibleAgentProviders.filter((provider) => !provider.available).map(formatUnavailableAgentProvider).join(", ")}`
|
|
609
|
+
: undefined,
|
|
610
|
+
visibleAgents.length > 0
|
|
611
|
+
? `Available subagent profiles: ${visibleAgents.map(formatVisibleAgent).join(", ")}`
|
|
612
|
+
: undefined,
|
|
578
613
|
instruction,
|
|
579
614
|
].filter(Boolean).join("\n"),
|
|
580
615
|
},
|
|
@@ -598,6 +633,8 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
598
633
|
agentsFiles: loadedAgentsFiles.length,
|
|
599
634
|
availableAgentsFiles: availableAgentsFileOutputs.length,
|
|
600
635
|
skills: visibleSkills.length,
|
|
636
|
+
agentProviders: visibleAgentProviders.length,
|
|
637
|
+
agents: visibleAgents.length,
|
|
601
638
|
skillDiagnostics: workspace.skillDiagnostics.length,
|
|
602
639
|
},
|
|
603
640
|
},
|
|
@@ -611,6 +648,8 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
611
648
|
agentsFiles: loadedAgentsFiles,
|
|
612
649
|
availableAgentsFiles: availableAgentsFileOutputs,
|
|
613
650
|
skills: visibleSkills,
|
|
651
|
+
agentProviders: visibleAgentProviders,
|
|
652
|
+
agents: visibleAgents,
|
|
614
653
|
skillDiagnostics: workspace.skillDiagnostics,
|
|
615
654
|
instruction,
|
|
616
655
|
},
|
|
@@ -841,7 +880,7 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
841
880
|
if (config.toolMode === "codex") {
|
|
842
881
|
registerAppTool(server, "apply_patch", {
|
|
843
882
|
title: "Apply patch",
|
|
844
|
-
description: "Apply one Codex-style patch inside an open workspace. Supports adding, overwriting, updating, deleting, and moving files.
|
|
883
|
+
description: "Apply one Codex-style patch inside an open workspace. Supports adding, overwriting, updating, deleting, and moving files. Use this for all file modifications. Paths must be relative to the workspace. Call open_workspace first and pass workspaceId.",
|
|
845
884
|
inputSchema: {
|
|
846
885
|
workspaceId: z
|
|
847
886
|
.string()
|
|
@@ -904,31 +943,23 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
904
943
|
if (config.widgets === "changes") {
|
|
905
944
|
registerAppTool(server, "show_changes", {
|
|
906
945
|
title: "Show changes",
|
|
907
|
-
description: "Show aggregate file changes
|
|
946
|
+
description: "Show aggregate file changes for an open workspace. If the current turn successfully modified files, call this exactly once after the final related file change and before your final response so the user can inspect the combined diff for the turn. Do not call it after every individual file change, and do not skip it because prior file-change tools already displayed per-tool diffs.",
|
|
908
947
|
inputSchema: {
|
|
909
948
|
workspaceId: z
|
|
910
949
|
.string()
|
|
911
950
|
.describe("Workspace identifier returned by open_workspace."),
|
|
912
|
-
since: z
|
|
913
|
-
.enum(["last_shown", "workspace_open"])
|
|
914
|
-
.optional()
|
|
915
|
-
.describe("Defaults to last_shown. Use workspace_open to compare against the initial open_workspace checkpoint."),
|
|
916
|
-
markReviewed: z
|
|
917
|
-
.boolean()
|
|
918
|
-
.optional()
|
|
919
|
-
.describe("Defaults to true. When true, advances the last shown checkpoint to the current workspace state."),
|
|
920
951
|
},
|
|
921
952
|
outputSchema: resultOutputSchema(),
|
|
922
953
|
...toolWidgetDescriptorMeta(config, "show_changes"),
|
|
923
954
|
annotations: { readOnlyHint: true },
|
|
924
|
-
}, async ({ workspaceId
|
|
955
|
+
}, async ({ workspaceId }) => {
|
|
925
956
|
const startedAt = performance.now();
|
|
926
957
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
927
958
|
const review = await reviewCheckpoints.reviewChanges({
|
|
928
959
|
workspaceId,
|
|
929
960
|
root: workspace.root,
|
|
930
|
-
since:
|
|
931
|
-
markReviewed:
|
|
961
|
+
since: "last_shown",
|
|
962
|
+
markReviewed: true,
|
|
932
963
|
});
|
|
933
964
|
const content = [textBlock(review.result)];
|
|
934
965
|
logToolCall(config, {
|
|
@@ -958,7 +989,7 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
958
989
|
}
|
|
959
990
|
if (config.toolMode === "full") {
|
|
960
991
|
registerAppTool(server, toolNames.grep, {
|
|
961
|
-
title:
|
|
992
|
+
title: "Grep",
|
|
962
993
|
description: "Search file contents inside an open workspace. Use this before broad reads when looking for symbols, text, or usage sites. Respects project ignore rules. Call open_workspace first and pass workspaceId.",
|
|
963
994
|
inputSchema: {
|
|
964
995
|
workspaceId: z
|
|
@@ -1020,7 +1051,7 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
1020
1051
|
};
|
|
1021
1052
|
});
|
|
1022
1053
|
registerAppTool(server, toolNames.glob, {
|
|
1023
|
-
title:
|
|
1054
|
+
title: "Glob",
|
|
1024
1055
|
description: "Find files by glob pattern inside an open workspace. Use this to discover filenames or narrow file sets before reading. Respects project ignore rules. Call open_workspace first and pass workspaceId.",
|
|
1025
1056
|
inputSchema: {
|
|
1026
1057
|
workspaceId: z
|
|
@@ -1081,7 +1112,7 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
1081
1112
|
};
|
|
1082
1113
|
});
|
|
1083
1114
|
registerAppTool(server, toolNames.ls, {
|
|
1084
|
-
title:
|
|
1115
|
+
title: "Ls",
|
|
1085
1116
|
description: "List a directory inside an open workspace. Use this for directory inspection before reading files. Call open_workspace first and pass workspaceId.",
|
|
1086
1117
|
inputSchema: {
|
|
1087
1118
|
workspaceId: z
|
|
@@ -1137,7 +1168,7 @@ function createMcpServer(config, workspaces, reviewCheckpoints, processSessions)
|
|
|
1137
1168
|
}
|
|
1138
1169
|
if (config.toolMode !== "codex") {
|
|
1139
1170
|
registerAppTool(server, toolNames.shell, {
|
|
1140
|
-
title:
|
|
1171
|
+
title: "Bash",
|
|
1141
1172
|
description: config.toolMode !== "full"
|
|
1142
1173
|
? `Run a shell command inside an open workspace. Use only for tests, builds, git inspection, package scripts, search, file discovery, and directory inspection. In minimal tool mode, ${toolNames.grep}, ${toolNames.glob}, and ${toolNames.ls} are disabled; use command-line tools such as grep, rg, find, ls, and tree for those read-only inspection actions. Do not use ${toolNames.shell} to create or modify files. Do not use shell redirection, heredocs, tee, sed -i, perl -i, node/python/ruby scripts, or generated scripts to write project files; use ${toolNames.edit} for targeted changes and ${toolNames.write} for new files or full rewrites. Prefer ${toolNames.read} for direct file reads. Call open_workspace first and pass workspaceId. This is powerful local execution and should only be exposed behind strong authentication.`
|
|
1143
1174
|
: `Run a shell command inside an open workspace. Use only for tests, builds, git inspection, package scripts, and commands that are better executed by the shell. Do not use ${toolNames.shell} to create or modify files. Do not use shell redirection, heredocs, tee, sed -i, perl -i, node/python/ruby scripts, or generated scripts to write project files; use ${toolNames.edit} for targeted changes and ${toolNames.write} for new files or full rewrites. Prefer ${toolNames.read}, ${toolNames.grep}, ${toolNames.glob}, and ${toolNames.ls} for file inspection. Call open_workspace first and pass workspaceId. This is powerful local execution and should only be exposed behind strong authentication.`,
|
|
@@ -1237,6 +1268,9 @@ export function createServer(config = loadConfig()) {
|
|
|
1237
1268
|
const workspaces = new WorkspaceRegistry(config, workspaceStore);
|
|
1238
1269
|
const reviewCheckpoints = createReviewCheckpointManager();
|
|
1239
1270
|
const processSessions = new ProcessSessionManager();
|
|
1271
|
+
const localAgentProviders = config.subagents
|
|
1272
|
+
? getLocalAgentProviderAvailabilitySnapshot()
|
|
1273
|
+
: [];
|
|
1240
1274
|
if (config.logging.trustProxy) {
|
|
1241
1275
|
app.set("trust proxy", true);
|
|
1242
1276
|
}
|
|
@@ -1345,7 +1379,7 @@ export function createServer(config = loadConfig()) {
|
|
|
1345
1379
|
});
|
|
1346
1380
|
}
|
|
1347
1381
|
};
|
|
1348
|
-
const server = createMcpServer(config, workspaces, reviewCheckpoints, processSessions);
|
|
1382
|
+
const server = createMcpServer(config, workspaces, reviewCheckpoints, processSessions, localAgentProviders);
|
|
1349
1383
|
await server.connect(transport);
|
|
1350
1384
|
}
|
|
1351
1385
|
else {
|
|
@@ -1368,6 +1402,7 @@ export function createServer(config = loadConfig()) {
|
|
|
1368
1402
|
return {
|
|
1369
1403
|
app,
|
|
1370
1404
|
config,
|
|
1405
|
+
localAgentProviders,
|
|
1371
1406
|
close: () => {
|
|
1372
1407
|
if (closed)
|
|
1373
1408
|
return;
|
|
@@ -1386,7 +1421,7 @@ async function isMainModule() {
|
|
|
1386
1421
|
return modulePath === entrypointPath;
|
|
1387
1422
|
}
|
|
1388
1423
|
if (await isMainModule()) {
|
|
1389
|
-
const { app, config, close } = createServer();
|
|
1424
|
+
const { app, config, close, localAgentProviders } = createServer();
|
|
1390
1425
|
const httpServer = app.listen(config.port, config.host, () => {
|
|
1391
1426
|
console.log(`devspace listening on http://${config.host}:${config.port}/mcp`);
|
|
1392
1427
|
console.log(`allowed roots: ${config.allowedRoots.join(", ")}`);
|
|
@@ -1395,6 +1430,9 @@ if (await isMainModule()) {
|
|
|
1395
1430
|
console.log(`request logging: ${config.logging.requests ? "enabled" : "disabled"}`);
|
|
1396
1431
|
console.log(`asset logging: ${config.logging.assets ? "enabled" : "disabled"}`);
|
|
1397
1432
|
console.log(`trust proxy: ${config.logging.trustProxy ? "enabled" : "disabled"}`);
|
|
1433
|
+
if (config.subagents) {
|
|
1434
|
+
console.log(`subagent providers: ${formatLocalAgentProviderAvailabilitySummary(localAgentProviders)}`);
|
|
1435
|
+
}
|
|
1398
1436
|
});
|
|
1399
1437
|
const shutdown = () => {
|
|
1400
1438
|
httpServer.close(() => {
|
package/dist/skills.js
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve, sep } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { loadSkills, } from "@earendil-works/pi-coding-agent";
|
|
5
6
|
import { expandHomePath, isPathInsideRoot } from "./roots.js";
|
|
7
|
+
const SUBAGENT_DELEGATION_NAME = "subagent-delegation";
|
|
8
|
+
const SUBAGENT_DELEGATION_SKILL = join(SUBAGENT_DELEGATION_NAME, "SKILL.md");
|
|
9
|
+
function bundledSkillsDir() {
|
|
10
|
+
return fileURLToPath(new URL("../skills", import.meta.url));
|
|
11
|
+
}
|
|
12
|
+
function hasSubagentDelegationSkill(skillDir) {
|
|
13
|
+
return existsSync(join(skillDir, SUBAGENT_DELEGATION_SKILL));
|
|
14
|
+
}
|
|
6
15
|
export function effectiveSkillPaths(config, cwd) {
|
|
7
|
-
const
|
|
16
|
+
const bundledSkills = bundledSkillsDir();
|
|
17
|
+
const defaultPathCandidates = [
|
|
8
18
|
join(homedir(), ".agents", "skills"),
|
|
9
19
|
resolve(cwd, ".agents", "skills"),
|
|
20
|
+
config.devspaceSkillsDir,
|
|
10
21
|
join(config.agentDir, "skills"),
|
|
11
|
-
|
|
22
|
+
config.subagents && !hasSubagentDelegationSkill(config.devspaceSkillsDir)
|
|
23
|
+
? bundledSkills
|
|
24
|
+
: undefined,
|
|
25
|
+
];
|
|
26
|
+
const defaultPaths = defaultPathCandidates.filter((path) => path !== undefined && existsSync(path));
|
|
12
27
|
const seen = new Set();
|
|
13
28
|
return [...defaultPaths, ...config.skillPaths]
|
|
14
29
|
.map((path) => resolveSkillPath(path, cwd))
|
|
@@ -25,12 +40,21 @@ function resolveSkillPath(path, cwd) {
|
|
|
25
40
|
export function loadWorkspaceSkills(config, cwd) {
|
|
26
41
|
if (!config.skillsEnabled)
|
|
27
42
|
return { skills: [], diagnostics: [] };
|
|
28
|
-
|
|
43
|
+
const result = loadSkills({
|
|
29
44
|
cwd,
|
|
30
45
|
agentDir: config.agentDir,
|
|
31
46
|
skillPaths: effectiveSkillPaths(config, cwd),
|
|
32
47
|
includeDefaults: false,
|
|
33
48
|
});
|
|
49
|
+
if (config.subagents)
|
|
50
|
+
return result;
|
|
51
|
+
return {
|
|
52
|
+
skills: result.skills.filter((skill) => skill.name !== SUBAGENT_DELEGATION_NAME),
|
|
53
|
+
diagnostics: result.diagnostics.filter((diagnostic) => {
|
|
54
|
+
const collision = diagnostic.collision;
|
|
55
|
+
return !(collision?.resourceType === "skill" && collision.name === SUBAGENT_DELEGATION_NAME);
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
34
58
|
}
|
|
35
59
|
export function resolveSkillReadPath(skills, activatedSkillDirs, inputPath) {
|
|
36
60
|
const absolutePath = resolve(expandHomePath(inputPath));
|