teamcopilot 0.1.3 → 0.1.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/frontend/assets/{cssMode-CV1QbDdV.js → cssMode-DHaUFfVN.js} +1 -1
- package/dist/frontend/assets/{freemarker2-SMKJ5iKX.js → freemarker2-CTVtohp4.js} +1 -1
- package/dist/frontend/assets/{handlebars-k8LxWzR3.js → handlebars-CI1GoG3L.js} +1 -1
- package/dist/frontend/assets/{html-ynahYm-q.js → html-C1Kdg4Tl.js} +1 -1
- package/dist/frontend/assets/{htmlMode-CKlgbgGX.js → htmlMode-CslwWXHV.js} +1 -1
- package/dist/frontend/assets/{index-CjZBHWet.js → index-CJMxNDke.js} +3 -3
- package/dist/frontend/assets/index-DrplZfJY.css +1 -0
- package/dist/frontend/assets/{javascript-3tohEroZ.js → javascript-D_jyP6QE.js} +1 -1
- package/dist/frontend/assets/{jsonMode-Bc561-dq.js → jsonMode-BT5z_9Wi.js} +1 -1
- package/dist/frontend/assets/{liquid-DwkCYmXC.js → liquid-CATjnK_z.js} +1 -1
- package/dist/frontend/assets/{mdx-BpoFi6BF.js → mdx-B4zdWJY_.js} +1 -1
- package/dist/frontend/assets/{python-BiLSr3a-.js → python-B_opZ_lQ.js} +1 -1
- package/dist/frontend/assets/{razor-BcYPJYvW.js → razor-BKopqk1g.js} +1 -1
- package/dist/frontend/assets/{tsMode-0Aumq3lP.js → tsMode-CMjXzcRc.js} +1 -1
- package/dist/frontend/assets/{typescript-C2VKs0MK.js → typescript-lbL28oip.js} +1 -1
- package/dist/frontend/assets/{xml-B19fG9u5.js → xml-BB8-GMIl.js} +1 -1
- package/dist/frontend/assets/{yaml-DFv9ENR5.js → yaml-B5S_93u4.js} +1 -1
- package/dist/frontend/index.html +2 -2
- package/dist/workspace_files/.opencode/plugins/apply-patch-session-diff.ts +175 -9
- package/dist/workspace_files/package.json +1 -1
- package/package.json +1 -1
- package/dist/frontend/assets/index-CDt94asq.css +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
1
2
|
import path from "node:path"
|
|
2
3
|
import type { Plugin } from "@opencode-ai/plugin"
|
|
3
4
|
|
|
@@ -17,6 +18,8 @@ interface SessionLookupResponse {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
type ToolArgs = Record<string, unknown> | undefined
|
|
22
|
+
|
|
20
23
|
function findPatchPayload(value: unknown): string | null {
|
|
21
24
|
if (typeof value === "string") {
|
|
22
25
|
const normalized = value.replace(/\r\n/g, "\n")
|
|
@@ -62,6 +65,118 @@ function extractTrackedPathsFromPatch(patchText: string): string[] {
|
|
|
62
65
|
return Array.from(new Set(paths.filter((candidate) => candidate.length > 0)))
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
function findNestedStringByKeys(value: unknown, keys: Set<string>): string | null {
|
|
69
|
+
if (!value || typeof value !== "object") {
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const [key, nestedValue] of Object.entries(value as Record<string, unknown>)) {
|
|
74
|
+
if (keys.has(key) && typeof nestedValue === "string" && nestedValue.trim().length > 0) {
|
|
75
|
+
return nestedValue
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const nestedMatch = findNestedStringByKeys(nestedValue, keys)
|
|
79
|
+
if (nestedMatch) {
|
|
80
|
+
return nestedMatch
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function tokenizeCommand(command: string): string[] {
|
|
88
|
+
const tokens = command.match(/"[^"]*"|'[^']*'|&&|\|\||[;|]|[^\s]+/g) ?? []
|
|
89
|
+
return tokens.map((token) => {
|
|
90
|
+
if (
|
|
91
|
+
(token.startsWith("\"") && token.endsWith("\"")) ||
|
|
92
|
+
(token.startsWith("'") && token.endsWith("'"))
|
|
93
|
+
) {
|
|
94
|
+
return token.slice(1, -1)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return token
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const CONTROL_TOKENS = new Set(["&&", "||", ";", "|"])
|
|
102
|
+
|
|
103
|
+
function resolveExecutionDirectory(rawCwd: unknown, fallbackDirectory: string): string {
|
|
104
|
+
if (typeof rawCwd !== "string" || rawCwd.trim() === "") {
|
|
105
|
+
return fallbackDirectory
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return path.isAbsolute(rawCwd) ? rawCwd : path.resolve(fallbackDirectory, rawCwd)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function resolveTrackedDeleteTargets(command: string, executionDirectory: string): string[] {
|
|
112
|
+
const tokens = tokenizeCommand(command.trim())
|
|
113
|
+
if (tokens.length === 0) {
|
|
114
|
+
return []
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const resolvedTargets: string[] = []
|
|
118
|
+
let currentDirectory = executionDirectory
|
|
119
|
+
let index = 0
|
|
120
|
+
let atCommandStart = true
|
|
121
|
+
|
|
122
|
+
while (index < tokens.length) {
|
|
123
|
+
const token = tokens[index]
|
|
124
|
+
|
|
125
|
+
if (CONTROL_TOKENS.has(token)) {
|
|
126
|
+
atCommandStart = true
|
|
127
|
+
index += 1
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!atCommandStart) {
|
|
132
|
+
index += 1
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (token === "cd") {
|
|
137
|
+
const destination = tokens[index + 1]
|
|
138
|
+
if (destination && !CONTROL_TOKENS.has(destination)) {
|
|
139
|
+
currentDirectory = path.isAbsolute(destination)
|
|
140
|
+
? path.resolve(destination)
|
|
141
|
+
: path.resolve(currentDirectory, destination)
|
|
142
|
+
index += 2
|
|
143
|
+
} else {
|
|
144
|
+
index += 1
|
|
145
|
+
}
|
|
146
|
+
atCommandStart = false
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (path.basename(token) === "rm") {
|
|
151
|
+
index += 1
|
|
152
|
+
while (index < tokens.length && !CONTROL_TOKENS.has(tokens[index])) {
|
|
153
|
+
const candidate = tokens[index]
|
|
154
|
+
if (candidate === "--" || candidate.startsWith("-")) {
|
|
155
|
+
index += 1
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const resolvedCandidate = path.isAbsolute(candidate)
|
|
160
|
+
? path.resolve(candidate)
|
|
161
|
+
: path.resolve(currentDirectory, candidate)
|
|
162
|
+
if (fs.existsSync(resolvedCandidate) && fs.statSync(resolvedCandidate).isDirectory()) {
|
|
163
|
+
index += 1
|
|
164
|
+
continue
|
|
165
|
+
}
|
|
166
|
+
resolvedTargets.push(resolvedCandidate)
|
|
167
|
+
index += 1
|
|
168
|
+
}
|
|
169
|
+
atCommandStart = false
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
atCommandStart = false
|
|
174
|
+
index += 1
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return Array.from(new Set(resolvedTargets))
|
|
178
|
+
}
|
|
179
|
+
|
|
65
180
|
function normalizeRelativePath(rawPath: string, workspaceDir: string): string {
|
|
66
181
|
const trimmed = rawPath.trim()
|
|
67
182
|
if (!trimmed) {
|
|
@@ -80,6 +195,14 @@ function normalizeRelativePath(rawPath: string, workspaceDir: string): string {
|
|
|
80
195
|
return relativePath.split(path.sep).join("/")
|
|
81
196
|
}
|
|
82
197
|
|
|
198
|
+
function tryNormalizeRelativePath(rawPath: string, workspaceDir: string): string | null {
|
|
199
|
+
try {
|
|
200
|
+
return normalizeRelativePath(rawPath, workspaceDir)
|
|
201
|
+
} catch {
|
|
202
|
+
return null
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
83
206
|
async function readErrorMessageFromResponse(
|
|
84
207
|
response: Response,
|
|
85
208
|
fallbackMessage: string
|
|
@@ -104,6 +227,51 @@ async function readErrorMessageFromResponse(
|
|
|
104
227
|
}
|
|
105
228
|
}
|
|
106
229
|
|
|
230
|
+
function collectTrackedPathsForTool(
|
|
231
|
+
tool: string,
|
|
232
|
+
inputArgs: ToolArgs,
|
|
233
|
+
outputArgs: ToolArgs,
|
|
234
|
+
workspaceDir: string
|
|
235
|
+
): string[] {
|
|
236
|
+
if (tool === "apply_patch") {
|
|
237
|
+
const patchPayload = findPatchPayload(outputArgs) ?? findPatchPayload(inputArgs)
|
|
238
|
+
if (!patchPayload) {
|
|
239
|
+
return []
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return extractTrackedPathsFromPatch(patchPayload)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (tool === "write") {
|
|
246
|
+
const filepath =
|
|
247
|
+
findNestedStringByKeys(outputArgs, new Set(["filepath", "filePath"])) ??
|
|
248
|
+
findNestedStringByKeys(inputArgs, new Set(["filepath", "filePath"]))
|
|
249
|
+
if (!filepath) {
|
|
250
|
+
return []
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return [filepath]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (tool === "bash") {
|
|
257
|
+
const command =
|
|
258
|
+
findNestedStringByKeys(outputArgs, new Set(["command", "cmd", "script", "arguments"])) ??
|
|
259
|
+
findNestedStringByKeys(inputArgs, new Set(["command", "cmd", "script", "arguments"]))
|
|
260
|
+
if (!command) {
|
|
261
|
+
return []
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const rawCwd =
|
|
265
|
+
(outputArgs && (outputArgs.workdir ?? outputArgs.cwd)) ??
|
|
266
|
+
(inputArgs && (inputArgs.workdir ?? inputArgs.cwd))
|
|
267
|
+
const executionDirectory = resolveExecutionDirectory(rawCwd, workspaceDir)
|
|
268
|
+
|
|
269
|
+
return resolveTrackedDeleteTargets(command, executionDirectory)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return []
|
|
273
|
+
}
|
|
274
|
+
|
|
107
275
|
export const ApplyPatchSessionDiffPlugin: Plugin = async ({ client, directory }) => {
|
|
108
276
|
async function resolveRootSessionID(sessionID: string): Promise<string> {
|
|
109
277
|
let currentSessionID = sessionID
|
|
@@ -150,24 +318,22 @@ export const ApplyPatchSessionDiffPlugin: Plugin = async ({ client, directory })
|
|
|
150
318
|
|
|
151
319
|
return {
|
|
152
320
|
"tool.execute.before": async (input, output) => {
|
|
153
|
-
if (
|
|
321
|
+
if (!["apply_patch", "write", "bash"].includes(input.tool)) {
|
|
154
322
|
return
|
|
155
323
|
}
|
|
156
324
|
|
|
157
325
|
const rawSessionID = typeof input.sessionID === "string" ? input.sessionID.trim() : ""
|
|
158
326
|
if (!rawSessionID) {
|
|
159
|
-
|
|
327
|
+
return
|
|
160
328
|
}
|
|
161
329
|
|
|
162
330
|
const rootSessionID = await resolveRootSessionID(rawSessionID)
|
|
163
|
-
const
|
|
164
|
-
if (!patchPayload) {
|
|
165
|
-
throw new Error("apply_patch hook could not find patch payload.")
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const paths = extractTrackedPathsFromPatch(patchPayload)
|
|
331
|
+
const paths = collectTrackedPathsForTool(input.tool, input.args, output.args, directory)
|
|
169
332
|
for (const candidatePath of paths) {
|
|
170
|
-
const relativePath =
|
|
333
|
+
const relativePath = tryNormalizeRelativePath(candidatePath, directory)
|
|
334
|
+
if (!relativePath) {
|
|
335
|
+
continue
|
|
336
|
+
}
|
|
171
337
|
await captureBaselineForPath(rootSessionID, relativePath)
|
|
172
338
|
}
|
|
173
339
|
},
|