@lazyingart/agintiflow 0.20.304 → 0.20.305
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.305",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -2370,6 +2370,35 @@ try {
|
|
|
2370
2370
|
/outside the active task artifact scope/.test(String(outsideScopedRead.reason || "")),
|
|
2371
2371
|
"task-scoped artifact tools could read an unrelated repository file"
|
|
2372
2372
|
);
|
|
2373
|
+
const writeScopedRead = await executeWorkspaceTool(
|
|
2374
|
+
"read_file",
|
|
2375
|
+
{ path: "unrelated.md" },
|
|
2376
|
+
{
|
|
2377
|
+
commandCwd: workspace,
|
|
2378
|
+
allowFileTools: true,
|
|
2379
|
+
workspaceWritePathScopeRoots: ["output/task-scope"],
|
|
2380
|
+
}
|
|
2381
|
+
);
|
|
2382
|
+
assert(
|
|
2383
|
+
writeScopedRead.content === "unrelated\n",
|
|
2384
|
+
"write-scoped artifact work could not read safe workspace evidence"
|
|
2385
|
+
);
|
|
2386
|
+
const outsideWriteScopedWrite = await executeWorkspaceTool(
|
|
2387
|
+
"write_file",
|
|
2388
|
+
{ path: "outside-scoped-write.md", content: "blocked\n" },
|
|
2389
|
+
{
|
|
2390
|
+
commandCwd: workspace,
|
|
2391
|
+
allowFileTools: true,
|
|
2392
|
+
workspaceWritePathScopeRoots: ["output/task-scope"],
|
|
2393
|
+
}
|
|
2394
|
+
);
|
|
2395
|
+
assert(
|
|
2396
|
+
outsideWriteScopedWrite.blocked === true &&
|
|
2397
|
+
/outside the active task artifact scope/.test(
|
|
2398
|
+
String(outsideWriteScopedWrite.reason || "")
|
|
2399
|
+
),
|
|
2400
|
+
"write-scoped artifact work could mutate an unrelated repository file"
|
|
2401
|
+
);
|
|
2373
2402
|
const filenameSearch = await executeWorkspaceTool(
|
|
2374
2403
|
"search_files",
|
|
2375
2404
|
{ path: ".", query: "routine_entry.py", maxResults: 5 },
|
|
@@ -5575,12 +5575,77 @@ const scopedRuntime = nextStepRuntimeConfig(
|
|
|
5575
5575
|
}
|
|
5576
5576
|
);
|
|
5577
5577
|
assertStrict.equal(scopedRuntime.scopedArtifactTask, true);
|
|
5578
|
-
assertStrict.deepEqual(scopedRuntime.
|
|
5578
|
+
assertStrict.deepEqual(scopedRuntime.workspaceWritePathScopeRoots, ["output/wechat_worker/task"]);
|
|
5579
|
+
assertStrict.equal(
|
|
5580
|
+
scopedRuntime.workspacePathScopeRoots,
|
|
5581
|
+
undefined,
|
|
5582
|
+
"task artifact output incorrectly hid repository evidence from safe reads"
|
|
5583
|
+
);
|
|
5579
5584
|
assertStrict.equal(
|
|
5580
5585
|
scopedRuntime.repositoryGroundingRequired,
|
|
5581
5586
|
undefined,
|
|
5582
5587
|
"an explicit task artifact root still activated generic repository grounding"
|
|
5583
5588
|
);
|
|
5589
|
+
const readOnlyAuditRequest =
|
|
5590
|
+
"Check readiness, read configs/model-policy.json, and report git status without changing source files or sending messages.";
|
|
5591
|
+
const readOnlyAuditPrompt = `AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
|
|
5592
|
+
mode: "task",
|
|
5593
|
+
request: readOnlyAuditRequest,
|
|
5594
|
+
artifact_root: "/workspace/output/webapp/agent/tasks/read-only-audit",
|
|
5595
|
+
})}`;
|
|
5596
|
+
const readOnlyAuditRuntime = nextStepRuntimeConfig(
|
|
5597
|
+
{
|
|
5598
|
+
provider: "localllm",
|
|
5599
|
+
goal: readOnlyAuditPrompt,
|
|
5600
|
+
commandCwd: "/workspace",
|
|
5601
|
+
},
|
|
5602
|
+
{
|
|
5603
|
+
goal: readOnlyAuditPrompt,
|
|
5604
|
+
commandCwd: "/workspace",
|
|
5605
|
+
meta: {
|
|
5606
|
+
goalContract: {
|
|
5607
|
+
revision: 1,
|
|
5608
|
+
currentRequest: readOnlyAuditRequest,
|
|
5609
|
+
},
|
|
5610
|
+
activeExecutionContract: {
|
|
5611
|
+
revision: 1,
|
|
5612
|
+
startedMutationRevision: 0,
|
|
5613
|
+
requiresWorkspaceMutation: false,
|
|
5614
|
+
requiresFileMutation: false,
|
|
5615
|
+
requiresSourceGrounding: false,
|
|
5616
|
+
},
|
|
5617
|
+
projectVerification: { mutationRevision: 0 },
|
|
5618
|
+
},
|
|
5619
|
+
}
|
|
5620
|
+
);
|
|
5621
|
+
assertStrict.equal(
|
|
5622
|
+
readOnlyAuditRuntime.scopedArtifactTask,
|
|
5623
|
+
undefined,
|
|
5624
|
+
"an optional host result directory incorrectly sandboxed a read-only workspace audit"
|
|
5625
|
+
);
|
|
5626
|
+
assertStrict.equal(
|
|
5627
|
+
readOnlyAuditRuntime.workspaceWritePathScopeRoots,
|
|
5628
|
+
undefined,
|
|
5629
|
+
"a read-only workspace audit inherited an unrelated artifact write scope"
|
|
5630
|
+
);
|
|
5631
|
+
const readOnlyAuditTools = selectProgressiveTools(allTools, {
|
|
5632
|
+
config: {
|
|
5633
|
+
provider: "localllm",
|
|
5634
|
+
progressiveTools: true,
|
|
5635
|
+
...readOnlyAuditRuntime,
|
|
5636
|
+
},
|
|
5637
|
+
goal: readOnlyAuditPrompt,
|
|
5638
|
+
profile: "auto",
|
|
5639
|
+
messages: [{ role: "user", content: readOnlyAuditPrompt }],
|
|
5640
|
+
});
|
|
5641
|
+
assert(
|
|
5642
|
+
names(readOnlyAuditTools).includes("run_command"),
|
|
5643
|
+
"a command-evidence audit omitted run_command from the compact local surface"
|
|
5644
|
+
);
|
|
5645
|
+
assert(
|
|
5646
|
+
names(readOnlyAuditTools).includes("read_file"),
|
|
5647
|
+
"an audit with an exact workspace input omitted read_file from the compact local surface"
|
|
5648
|
+
);
|
|
5584
5649
|
const scopedPathWriteDescriptor = {
|
|
5585
5650
|
type: "function",
|
|
5586
5651
|
function: {
|
|
@@ -5683,9 +5748,9 @@ assertStrict.equal(
|
|
|
5683
5748
|
"long-context compaction discarded the host-owned artifact scope"
|
|
5684
5749
|
);
|
|
5685
5750
|
assertStrict.deepEqual(
|
|
5686
|
-
longScopedRuntime.
|
|
5751
|
+
longScopedRuntime.workspaceWritePathScopeRoots,
|
|
5687
5752
|
["output/wechat_worker/long-scoped-task"],
|
|
5688
|
-
"long-context artifact
|
|
5753
|
+
"long-context artifact writes escaped their exact task root"
|
|
5689
5754
|
);
|
|
5690
5755
|
assertStrict.equal(
|
|
5691
5756
|
longScopedRuntime.completionFreshMutationRequired,
|
package/src/agent-runner.js
CHANGED
|
@@ -15034,8 +15034,30 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
15034
15034
|
const scopedRootRelative = resolvedScopedRoot
|
|
15035
15035
|
? path.relative(commandCwd, resolvedScopedRoot)
|
|
15036
15036
|
: "";
|
|
15037
|
-
const
|
|
15037
|
+
const exactScopedOutputs = Array.isArray(groundingTaskContract.exactOutputPaths)
|
|
15038
|
+
? groundingTaskContract.exactOutputPaths
|
|
15039
|
+
.map((item) => String(item || "").trim())
|
|
15040
|
+
.filter(Boolean)
|
|
15041
|
+
: [];
|
|
15042
|
+
const exactOutputsStayInsideScopedRoot = Boolean(
|
|
15038
15043
|
resolvedScopedRoot &&
|
|
15044
|
+
exactScopedOutputs.length > 0 &&
|
|
15045
|
+
exactScopedOutputs.every((item) => {
|
|
15046
|
+
const absoluteOutput = path.resolve(commandCwd, item);
|
|
15047
|
+
const relativeOutput = path.relative(resolvedScopedRoot, absoluteOutput);
|
|
15048
|
+
return (
|
|
15049
|
+
relativeOutput === "" ||
|
|
15050
|
+
(!relativeOutput.startsWith("..") && !path.isAbsolute(relativeOutput))
|
|
15051
|
+
);
|
|
15052
|
+
})
|
|
15053
|
+
);
|
|
15054
|
+
const scopedArtifactTask = Boolean(
|
|
15055
|
+
(
|
|
15056
|
+
groundingTaskContract.scopedArtifactDeliverable === true ||
|
|
15057
|
+
groundingTaskContract.scopedArtifactOperation === true ||
|
|
15058
|
+
exactOutputsStayInsideScopedRoot
|
|
15059
|
+
) &&
|
|
15060
|
+
resolvedScopedRoot &&
|
|
15039
15061
|
scopedRootRelative &&
|
|
15040
15062
|
!scopedRootRelative.startsWith("..") &&
|
|
15041
15063
|
!path.isAbsolute(scopedRootRelative)
|
|
@@ -15043,7 +15065,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
15043
15065
|
if (scopedArtifactTask) {
|
|
15044
15066
|
runtimeConfig.scopedArtifactTask = true;
|
|
15045
15067
|
runtimeConfig.scopedArtifactRoot = scopedRootRelative.replace(/\\/g, "/");
|
|
15046
|
-
runtimeConfig.
|
|
15068
|
+
runtimeConfig.workspaceWritePathScopeRoots = [runtimeConfig.scopedArtifactRoot];
|
|
15047
15069
|
}
|
|
15048
15070
|
if (
|
|
15049
15071
|
(
|
|
@@ -4,7 +4,11 @@ import {
|
|
|
4
4
|
hasLocalResearchWorkspaceIntent,
|
|
5
5
|
shouldStartWithDeepResearch,
|
|
6
6
|
} from "./research-routing.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
deriveScsTaskContract,
|
|
9
|
+
hasAgintiEvidenceScope,
|
|
10
|
+
scopedChatopsEvidenceGoal,
|
|
11
|
+
} from "./scs-evidence.js";
|
|
8
12
|
import {
|
|
9
13
|
INTEGRATION_TEXT_WORKSPACE_PROFILE_ID,
|
|
10
14
|
isIntegrationTextWorkspaceToolAllowed,
|
|
@@ -2204,6 +2208,32 @@ function compactToolNames({ config, goal, profile, messages }) {
|
|
|
2204
2208
|
const explicitBundles = bundlesForProfile(profileId(config, profile));
|
|
2205
2209
|
const inferred = inferredBundles(taskText(goal, config, messages));
|
|
2206
2210
|
const explicitProfileTools = profileToolNames(profile);
|
|
2211
|
+
const taskContract = deriveScsTaskContract({
|
|
2212
|
+
goal: goal || config.goal || "",
|
|
2213
|
+
taskProfile: profileId(config, profile),
|
|
2214
|
+
});
|
|
2215
|
+
const contractRequiredTools = [];
|
|
2216
|
+
if (
|
|
2217
|
+
(Array.isArray(taskContract.requiredEvidence) &&
|
|
2218
|
+
taskContract.requiredEvidence.some(
|
|
2219
|
+
(item) => String(item?.category || "") === "command"
|
|
2220
|
+
)) ||
|
|
2221
|
+
(Array.isArray(taskContract.requiredProjectCommands) &&
|
|
2222
|
+
taskContract.requiredProjectCommands.length > 0)
|
|
2223
|
+
) {
|
|
2224
|
+
contractRequiredTools.push("run_command");
|
|
2225
|
+
}
|
|
2226
|
+
if (
|
|
2227
|
+
Array.isArray(taskContract.exactInputPaths) &&
|
|
2228
|
+
taskContract.exactInputPaths.length > 0
|
|
2229
|
+
) {
|
|
2230
|
+
contractRequiredTools.push("read_file");
|
|
2231
|
+
}
|
|
2232
|
+
for (const name of taskContract.requiredToolCalls || []) {
|
|
2233
|
+
if (COMPACT_ELIGIBLE_TOOL_NAMES.has(String(name || "").trim())) {
|
|
2234
|
+
contractRequiredTools.push(String(name).trim());
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2207
2237
|
const bundleOrder = [];
|
|
2208
2238
|
for (const bundle of explicitBundles) bundleOrder.push(bundle);
|
|
2209
2239
|
for (const bundle of inferred) {
|
|
@@ -2232,7 +2262,10 @@ function compactToolNames({ config, goal, profile, messages }) {
|
|
|
2232
2262
|
for (const name of COMPACT_TOOL_BUNDLES[bundle] || []) append(name);
|
|
2233
2263
|
}
|
|
2234
2264
|
for (const name of explicitProfileTools) append(name);
|
|
2235
|
-
|
|
2265
|
+
const missingContractTools = [
|
|
2266
|
+
...new Set(contractRequiredTools.filter((name) => !seen.has(name))),
|
|
2267
|
+
];
|
|
2268
|
+
return [...missingContractTools, ...names];
|
|
2236
2269
|
}
|
|
2237
2270
|
|
|
2238
2271
|
/**
|
|
@@ -2739,21 +2772,9 @@ export function selectProgressiveTools(
|
|
|
2739
2772
|
if (config.scopedArtifactTask === true && config.scopedArtifactRoot) {
|
|
2740
2773
|
const available = new Map(enabled.map(({ name, tool }) => [name, tool]));
|
|
2741
2774
|
const scopedWorkspaceTools = [
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
{ commandCwd: config.commandCwd }
|
|
2746
|
-
),
|
|
2747
|
-
constrainScopedArtifactPath(
|
|
2748
|
-
available.get("read_file"),
|
|
2749
|
-
config.scopedArtifactRoot,
|
|
2750
|
-
{ commandCwd: config.commandCwd }
|
|
2751
|
-
),
|
|
2752
|
-
constrainScopedArtifactPath(
|
|
2753
|
-
available.get("search_files"),
|
|
2754
|
-
config.scopedArtifactRoot,
|
|
2755
|
-
{ commandCwd: config.commandCwd }
|
|
2756
|
-
),
|
|
2775
|
+
available.get("list_files"),
|
|
2776
|
+
available.get("read_file"),
|
|
2777
|
+
available.get("search_files"),
|
|
2757
2778
|
constrainScopedArtifactPath(
|
|
2758
2779
|
available.get("write_file"),
|
|
2759
2780
|
config.scopedArtifactRoot,
|
|
@@ -2767,9 +2788,9 @@ export function selectProgressiveTools(
|
|
|
2767
2788
|
available.get("run_command"),
|
|
2768
2789
|
].filter(Boolean);
|
|
2769
2790
|
|
|
2770
|
-
//
|
|
2771
|
-
//
|
|
2772
|
-
// inferred non-file tools while
|
|
2791
|
+
// A host-owned artifact root confines artifact writes, but it must not hide
|
|
2792
|
+
// the workspace evidence needed to produce those artifacts. Keep safe reads
|
|
2793
|
+
// and inferred non-file tools available while write tools remain root-scoped.
|
|
2773
2794
|
const scopedWorkspaceToolNames = new Set(
|
|
2774
2795
|
scopedWorkspaceTools.map((tool) => openAiFunctionName(tool)).filter(Boolean)
|
|
2775
2796
|
);
|
package/src/scs-evidence.js
CHANGED
|
@@ -1341,6 +1341,20 @@ function goalRequestsScopedArtifactDeliverable(goal = "") {
|
|
|
1341
1341
|
return !projectSourceMutation;
|
|
1342
1342
|
}
|
|
1343
1343
|
|
|
1344
|
+
function goalRequestsScopedArtifactOperation(goal = "") {
|
|
1345
|
+
const text = normalizedText(stripCompletedWorkNarration(stripForbiddenLanguage(goal)));
|
|
1346
|
+
const artifactOperation =
|
|
1347
|
+
/\b(?:build|compile|create|draft|edit|export|generate|make|prepare|produce|render|repair|revise|save|update|write)\b[^.\n;]{0,180}\b(?:artifact|brief|cad|diagram|document|figure|image|markdown|memo|model|note|paper|pcb|pdf|presentation|prompt|report|research note|slide deck|slides?|spreadsheet|story|summary|transcript|video)\b/.test(text) ||
|
|
1348
|
+
/\b(?:artifact|brief|cad|diagram|document|figure|image|markdown|memo|model|note|paper|pcb|pdf|presentation|prompt|report|research note|slide deck|slides?|spreadsheet|story|summary|transcript|video)\b[^.\n;]{0,120}\b(?:build|compile|create|draft|edit|export|generate|make|prepare|produce|render|repair|revise|save|update|write)\b/.test(text) ||
|
|
1349
|
+
/(?:创建|生成|保存|编写|撰写|制作|导出|准备|修改|修订|修复|更新)[^。;\n]{0,100}(?:报告|笔记|摘要|文档|论文|图表|图片|模型|演示文稿|幻灯片|表格|故事|提示词|转录|视频)/.test(text);
|
|
1350
|
+
if (!artifactOperation) return false;
|
|
1351
|
+
const projectSourceMutation =
|
|
1352
|
+
/\b(?:change|debug|edit|fix|implement|improve|modify|patch|refactor|repair|replace|rewrite|update)\b[^.\n;]{0,140}\b(?:app|application|code|codebase|implementation|library|package|repo|repository|runtime|source\s+code|src\/)\b/.test(text) ||
|
|
1353
|
+
/\b(?:app|application|code|codebase|implementation|library|package|repo|repository|runtime|source\s+code|src\/)\b[^.\n;]{0,140}\b(?:change|debug|edit|fix|implement|improve|modify|patch|refactor|repair|replace|rewrite|update)\b/.test(text) ||
|
|
1354
|
+
/(?:修改|修复|实现|改进|重构|调试|替换|更新)[^。;\n]{0,100}(?:代码|代码库|实现|运行时|应用|仓库|源码)/.test(text);
|
|
1355
|
+
return !projectSourceMutation;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1344
1358
|
function goalRequestsTestExecution(goal = "") {
|
|
1345
1359
|
const text = normalizedText(stripCompletedWorkNarration(stripForbiddenLanguage(goal)));
|
|
1346
1360
|
return (
|
|
@@ -2062,6 +2076,9 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
|
|
|
2062
2076
|
const scopedArtifactDeliverable = Boolean(
|
|
2063
2077
|
artifactRoot && goalRequestsScopedArtifactDeliverable(evidenceGoal)
|
|
2064
2078
|
);
|
|
2079
|
+
const scopedArtifactOperation = Boolean(
|
|
2080
|
+
artifactRoot && goalRequestsScopedArtifactOperation(evidenceGoal)
|
|
2081
|
+
);
|
|
2065
2082
|
return {
|
|
2066
2083
|
version: 1,
|
|
2067
2084
|
outcome: compact(evidenceGoal || "Complete the requested task.", 500),
|
|
@@ -2072,6 +2089,7 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
|
|
|
2072
2089
|
exactOutputPaths,
|
|
2073
2090
|
requiredArtifactKinds,
|
|
2074
2091
|
scopedArtifactDeliverable,
|
|
2092
|
+
scopedArtifactOperation,
|
|
2075
2093
|
excludedOutputPaths,
|
|
2076
2094
|
artifactRoot,
|
|
2077
2095
|
exactInputPaths,
|
package/src/workspace-tools.js
CHANGED
|
@@ -117,10 +117,15 @@ function matchingReadOnlyRoot(config, target) {
|
|
|
117
117
|
.find((root) => isInside(root, target));
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
function configuredWorkspaceScopeRoots(config, root) {
|
|
121
|
-
const values =
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
function configuredWorkspaceScopeRoots(config, root, { writeAccess = false } = {}) {
|
|
121
|
+
const values = [
|
|
122
|
+
...(Array.isArray(config.workspacePathScopeRoots)
|
|
123
|
+
? config.workspacePathScopeRoots
|
|
124
|
+
: []),
|
|
125
|
+
...(writeAccess && Array.isArray(config.workspaceWritePathScopeRoots)
|
|
126
|
+
? config.workspaceWritePathScopeRoots
|
|
127
|
+
: []),
|
|
128
|
+
];
|
|
124
129
|
return values
|
|
125
130
|
.map((item) => String(item || "").trim())
|
|
126
131
|
.filter(Boolean)
|
|
@@ -267,12 +272,16 @@ export function normalizeWorkspaceInputPath(rawPath) {
|
|
|
267
272
|
return rawPath;
|
|
268
273
|
}
|
|
269
274
|
|
|
270
|
-
export function resolveWorkspacePath(
|
|
275
|
+
export function resolveWorkspacePath(
|
|
276
|
+
config,
|
|
277
|
+
inputPath = ".",
|
|
278
|
+
{ allowReadOnlyRoots = false, writeAccess = false } = {}
|
|
279
|
+
) {
|
|
271
280
|
const root = workspaceRoot(config);
|
|
272
281
|
const rawPath = sanitizePathInput(inputPath);
|
|
273
282
|
const workspacePath = normalizeWorkspaceInputPath(rawPath);
|
|
274
283
|
const absolutePath = path.resolve(root, workspacePath);
|
|
275
|
-
const scopedRoots = configuredWorkspaceScopeRoots(config, root);
|
|
284
|
+
const scopedRoots = configuredWorkspaceScopeRoots(config, root, { writeAccess });
|
|
276
285
|
|
|
277
286
|
if (scopedRoots.length && !scopedRoots.some((scopeRoot) => isInside(scopeRoot, absolutePath))) {
|
|
278
287
|
throw new Error(`Path is outside the active task artifact scope: ${rawPath}`);
|
|
@@ -451,7 +460,7 @@ export function checkWorkspaceToolUse(toolName, args, config) {
|
|
|
451
460
|
const operations = parsePatchDocument(args.patch);
|
|
452
461
|
for (const operation of operations) {
|
|
453
462
|
for (const candidate of [operation.path, operation.newPath].filter(Boolean)) {
|
|
454
|
-
const target = resolveWorkspacePath(config, candidate);
|
|
463
|
+
const target = resolveWorkspacePath(config, candidate, { writeAccess: true });
|
|
455
464
|
const policy = pathPolicy(toolName, target.relativePath);
|
|
456
465
|
if (!policy.allowed) return policy;
|
|
457
466
|
}
|
|
@@ -462,6 +471,7 @@ export function checkWorkspaceToolUse(toolName, args, config) {
|
|
|
462
471
|
}
|
|
463
472
|
const target = resolveWorkspacePath(config, args.path || ".", {
|
|
464
473
|
allowReadOnlyRoots: !WORKSPACE_WRITE_TOOL_NAMES.includes(toolName),
|
|
474
|
+
writeAccess: WORKSPACE_WRITE_TOOL_NAMES.includes(toolName),
|
|
465
475
|
});
|
|
466
476
|
const policy = pathPolicy(toolName, target.relativePath);
|
|
467
477
|
if (!policy.allowed) return policy;
|
|
@@ -1006,7 +1016,7 @@ async function deleteChange(target, action = "delete_file", details = {}) {
|
|
|
1006
1016
|
}
|
|
1007
1017
|
|
|
1008
1018
|
async function writeFile(config, args) {
|
|
1009
|
-
const target = resolveWorkspacePath(config, args.path);
|
|
1019
|
+
const target = resolveWorkspacePath(config, args.path, { writeAccess: true });
|
|
1010
1020
|
const mode = args.mode === "overwrite" ? "overwrite" : "create";
|
|
1011
1021
|
const exists = await fs
|
|
1012
1022
|
.stat(target.absolutePath)
|
|
@@ -1033,7 +1043,7 @@ async function applyPatch(config, args) {
|
|
|
1033
1043
|
return applyPatchDocument(config, args);
|
|
1034
1044
|
}
|
|
1035
1045
|
|
|
1036
|
-
const target = resolveWorkspacePath(config, args.path);
|
|
1046
|
+
const target = resolveWorkspacePath(config, args.path, { writeAccess: true });
|
|
1037
1047
|
const { content: beforeText, hash } = await readTextFile(target);
|
|
1038
1048
|
if (args.baseHash && args.baseHash !== hash) {
|
|
1039
1049
|
throw new Error(`Base hash mismatch for ${target.relativePath}; read the file again before patching.`);
|
|
@@ -1234,10 +1244,12 @@ async function applyPatchDocument(config, args) {
|
|
|
1234
1244
|
if (seenPaths.has(operation.path)) throw new Error(`Patch contains duplicate file operations for ${operation.path}.`);
|
|
1235
1245
|
seenPaths.add(operation.path);
|
|
1236
1246
|
|
|
1237
|
-
const target = resolveWorkspacePath(config, operation.path);
|
|
1247
|
+
const target = resolveWorkspacePath(config, operation.path, { writeAccess: true });
|
|
1238
1248
|
const policy = pathPolicy("apply_patch", target.relativePath);
|
|
1239
1249
|
if (!policy.allowed) throw new Error(policy.reason);
|
|
1240
|
-
const newTarget = operation.newPath
|
|
1250
|
+
const newTarget = operation.newPath
|
|
1251
|
+
? resolveWorkspacePath(config, operation.newPath, { writeAccess: true })
|
|
1252
|
+
: null;
|
|
1241
1253
|
if (newTarget) {
|
|
1242
1254
|
const newPolicy = pathPolicy("apply_patch", newTarget.relativePath);
|
|
1243
1255
|
if (!newPolicy.allowed) throw new Error(newPolicy.reason);
|
|
@@ -1300,7 +1312,7 @@ async function applyPatchDocument(config, args) {
|
|
|
1300
1312
|
continue;
|
|
1301
1313
|
}
|
|
1302
1314
|
if (operation.newPath) {
|
|
1303
|
-
const newTarget = resolveWorkspacePath(config, operation.newPath);
|
|
1315
|
+
const newTarget = resolveWorkspacePath(config, operation.newPath, { writeAccess: true });
|
|
1304
1316
|
const policy = pathPolicy("apply_patch", newTarget.relativePath);
|
|
1305
1317
|
if (!policy.allowed) throw new Error(policy.reason);
|
|
1306
1318
|
changes.push(await writeChange(newTarget, item.afterText, "apply_patch_move", { fromPath: target.relativePath, patchFormat: "multi-file" }));
|