@cjhyy/code-shell-capability-coding 0.8.20 → 0.9.0
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.
|
@@ -2,6 +2,8 @@ import { Hunk } from "./types.js";
|
|
|
2
2
|
export interface ApplyPatchOptions {
|
|
3
3
|
/** Working directory for resolving relative paths in the patch. */
|
|
4
4
|
cwd: string;
|
|
5
|
+
/** Immutable roots authorized for this run. Relative patch paths still resolve from cwd. */
|
|
6
|
+
workspaceRoots?: readonly string[];
|
|
5
7
|
/**
|
|
6
8
|
* If true, skip the snapshot/rollback safety net and apply each planned
|
|
7
9
|
* change one at a time, leaving partial work on disk if a later write
|
|
@@ -27,10 +27,10 @@ export async function applyPatch(hunks, options) {
|
|
|
27
27
|
if (hunks.length === 0) {
|
|
28
28
|
throw new Error("No files were modified.");
|
|
29
29
|
}
|
|
30
|
-
const planned = await planHunks(hunks, options.cwd);
|
|
30
|
+
const planned = await planHunks(hunks, options.cwd, options.workspaceRoots ?? [options.cwd]);
|
|
31
31
|
return commitPlanned(planned, !!options.allowPartialOnCommit);
|
|
32
32
|
}
|
|
33
|
-
async function planHunks(hunks, cwd) {
|
|
33
|
+
async function planHunks(hunks, cwd, workspaceRoots) {
|
|
34
34
|
const set = {
|
|
35
35
|
byPath: new Map(),
|
|
36
36
|
added: [],
|
|
@@ -45,7 +45,7 @@ async function planHunks(hunks, cwd) {
|
|
|
45
45
|
}
|
|
46
46
|
for (const hunk of hunks) {
|
|
47
47
|
const original = hunk.path;
|
|
48
|
-
const sourcePath = resolveAgainst(original, cwd);
|
|
48
|
+
const sourcePath = resolveAgainst(original, cwd, workspaceRoots);
|
|
49
49
|
if (hunk.kind === "add") {
|
|
50
50
|
const existed = await readIfExists(sourcePath);
|
|
51
51
|
schedule(sourcePath, {
|
|
@@ -87,7 +87,7 @@ async function planHunks(hunks, cwd) {
|
|
|
87
87
|
const originalText = toLf(originalRaw);
|
|
88
88
|
const newText = applyEol(applyChunksToText(originalText, hunk.chunks, sourcePath), eol);
|
|
89
89
|
if (hunk.movePath !== undefined) {
|
|
90
|
-
const destPath = resolveAgainst(hunk.movePath, cwd);
|
|
90
|
+
const destPath = resolveAgainst(hunk.movePath, cwd, workspaceRoots);
|
|
91
91
|
if (destPath === sourcePath) {
|
|
92
92
|
// Rename to self → degenerate update.
|
|
93
93
|
schedule(sourcePath, {
|
|
@@ -248,12 +248,12 @@ async function writeChange(change) {
|
|
|
248
248
|
* symlink planted inside cwd that points outside — a plain string `resolve()`
|
|
249
249
|
* would look contained while the write follows the link out.
|
|
250
250
|
*/
|
|
251
|
-
function resolveAgainst(p, cwd) {
|
|
251
|
+
function resolveAgainst(p, cwd, workspaceRoots) {
|
|
252
252
|
const resolved = isAbsolute(p) ? p : resolve(cwd, p);
|
|
253
|
-
const realCwd = nearestRealPath(cwd);
|
|
254
253
|
const realTarget = nearestRealPath(resolved);
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
const realRoots = workspaceRoots.map(nearestRealPath);
|
|
255
|
+
if (!realRoots.some((root) => isInside(realTarget, root))) {
|
|
256
|
+
throw new Error(`Refusing to apply patch outside the workspace roots: "${p}" resolves to "${realTarget}".`);
|
|
257
257
|
}
|
|
258
258
|
return resolved;
|
|
259
259
|
}
|
|
@@ -72,7 +72,10 @@ export async function applyPatchTool(args, ctx) {
|
|
|
72
72
|
const cwd = ctx?.cwd ?? process.cwd();
|
|
73
73
|
let result;
|
|
74
74
|
try {
|
|
75
|
-
result = await applyPatch(parsed.hunks, {
|
|
75
|
+
result = await applyPatch(parsed.hunks, {
|
|
76
|
+
cwd,
|
|
77
|
+
workspaceRoots: ctx?.workspace?.roots.map((root) => root.path),
|
|
78
|
+
});
|
|
76
79
|
}
|
|
77
80
|
catch (err) {
|
|
78
81
|
return `Error applying patch: ${err.message}`;
|
package/dist/tools/worktree.js
CHANGED
|
@@ -27,7 +27,7 @@ export async function switchSessionWorkspaceTool(args, ctx) {
|
|
|
27
27
|
const target = stringArg(args.target);
|
|
28
28
|
if (!target)
|
|
29
29
|
return "Error: target is required";
|
|
30
|
-
const bridge = ctx
|
|
30
|
+
const bridge = workspaceBridgeForContext(ctx);
|
|
31
31
|
if (!bridge) {
|
|
32
32
|
return ("SwitchSessionWorkspace is not available in this host. " +
|
|
33
33
|
"Use the host's supported workspace controls instead.");
|
|
@@ -48,6 +48,22 @@ export async function switchSessionWorkspaceTool(args, ctx) {
|
|
|
48
48
|
return `Error: switching workspace failed: ${err.message}`;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
function workspaceBridgeForContext(ctx) {
|
|
52
|
+
if (ctx?.workspaceBridge)
|
|
53
|
+
return ctx.workspaceBridge;
|
|
54
|
+
// Before multi-root authority landed, the host bridge occupied `workspace`.
|
|
55
|
+
// Keep those single-root hosts and injected harnesses working, but never
|
|
56
|
+
// interpret a versioned/root-bearing WorkspaceContext as an executable bridge.
|
|
57
|
+
const legacy = ctx?.workspace;
|
|
58
|
+
if (!legacy || typeof legacy !== "object")
|
|
59
|
+
return undefined;
|
|
60
|
+
if ("version" in legacy || "roots" in legacy || "projectId" in legacy)
|
|
61
|
+
return undefined;
|
|
62
|
+
const candidate = legacy;
|
|
63
|
+
return typeof candidate.switch === "function"
|
|
64
|
+
? candidate
|
|
65
|
+
: undefined;
|
|
66
|
+
}
|
|
51
67
|
export const enterWorktreeToolDef = {
|
|
52
68
|
name: "EnterWorktree",
|
|
53
69
|
description: "Switch the current session workspace. Target can be a new worktree slug, " +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cjhyy/code-shell-capability-coding",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Coding capability pack for the generic code-shell agent core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@cjhyy/code-shell-core": "0.
|
|
42
|
+
"@cjhyy/code-shell-core": "0.9.0"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20.10"
|