chainlesschain 0.45.63 → 0.45.65
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 +1 -1
- package/src/gateways/ws/session-protocol.js +162 -105
- package/src/gateways/ws/worktree-protocol.js +134 -141
- package/src/lib/agent-core.js +173 -13
- package/src/lib/interaction-adapter.js +45 -0
- package/src/lib/plan-mode.js +3 -1
- package/src/lib/session-manager.js +45 -8
- package/src/lib/web-ui-envelope.js +94 -0
- package/src/lib/web-ui-server.js +13 -1
- package/src/lib/ws-agent-handler.js +8 -1
- package/src/lib/ws-session-manager.js +388 -20
- package/src/runtime/agent-runtime.js +140 -37
- package/src/runtime/coding-agent-contract.js +294 -0
- package/src/runtime/coding-agent-events.cjs +372 -0
- package/src/runtime/coding-agent-managed-tool-policy.cjs +294 -0
- package/src/runtime/coding-agent-policy.cjs +354 -0
- package/src/runtime/coding-agent-shell-policy.cjs +233 -0
- package/src/runtime/contracts/session-record.js +13 -0
- package/src/runtime/index.js +14 -0
- package/src/runtime/runtime-events.js +27 -0
- package/src/tools/index.js +12 -0
- package/src/tools/legacy-agent-tools.js +12 -157
|
@@ -2,44 +2,57 @@ import { createWorktreeRecord } from "../../runtime/contracts/worktree-record.js
|
|
|
2
2
|
import {
|
|
3
3
|
RUNTIME_EVENTS,
|
|
4
4
|
createRuntimeEvent,
|
|
5
|
+
createCodingAgentEvent,
|
|
6
|
+
CODING_AGENT_EVENT_TYPES,
|
|
5
7
|
} from "../../runtime/runtime-events.js";
|
|
6
8
|
|
|
9
|
+
function envelopeResponse(type, id, payload) {
|
|
10
|
+
return createCodingAgentEvent(type, payload || {}, {
|
|
11
|
+
requestId: id,
|
|
12
|
+
source: "cli-runtime",
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function envelopeError(id, code, message) {
|
|
17
|
+
return createCodingAgentEvent(
|
|
18
|
+
CODING_AGENT_EVENT_TYPES.ERROR,
|
|
19
|
+
{ code, message },
|
|
20
|
+
{ requestId: id, source: "cli-runtime" },
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
export async function handleWorktreeDiff(server, id, ws, message) {
|
|
8
25
|
try {
|
|
9
26
|
const { diffWorktree } = await import("../../lib/worktree-isolator.js");
|
|
10
27
|
const { branch, baseBranch, filePath } = message;
|
|
11
28
|
if (!branch) {
|
|
12
|
-
server._send(ws,
|
|
13
|
-
id,
|
|
14
|
-
type: "error",
|
|
15
|
-
code: "NO_BRANCH",
|
|
16
|
-
message: "branch required",
|
|
17
|
-
});
|
|
29
|
+
server._send(ws, envelopeError(id, "NO_BRANCH", "branch required"));
|
|
18
30
|
return;
|
|
19
31
|
}
|
|
20
32
|
const result = diffWorktree(process.cwd(), branch, {
|
|
21
33
|
baseBranch,
|
|
22
34
|
filePath,
|
|
23
35
|
});
|
|
24
|
-
server._send(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
summary: result.summary,
|
|
30
|
-
diff: result.diff,
|
|
31
|
-
record: createWorktreeRecord({
|
|
32
|
-
branch,
|
|
33
|
-
baseBranch,
|
|
36
|
+
server._send(
|
|
37
|
+
ws,
|
|
38
|
+
envelopeResponse(CODING_AGENT_EVENT_TYPES.WORKTREE_DIFF, id, {
|
|
39
|
+
filePath: result.filePath || filePath || null,
|
|
40
|
+
files: result.files,
|
|
34
41
|
summary: result.summary,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
diff: result.diff,
|
|
43
|
+
record: createWorktreeRecord({
|
|
44
|
+
branch,
|
|
45
|
+
baseBranch,
|
|
46
|
+
summary: result.summary,
|
|
47
|
+
previewEntrypoints: [
|
|
48
|
+
{
|
|
49
|
+
type: "worktree-diff",
|
|
50
|
+
branch,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
}),
|
|
41
54
|
}),
|
|
42
|
-
|
|
55
|
+
);
|
|
43
56
|
server.emit(
|
|
44
57
|
RUNTIME_EVENTS.WORKTREE_DIFF_READY,
|
|
45
58
|
createRuntimeEvent(
|
|
@@ -64,12 +77,7 @@ export async function handleWorktreeDiff(server, id, ws, message) {
|
|
|
64
77
|
),
|
|
65
78
|
);
|
|
66
79
|
} catch (err) {
|
|
67
|
-
server._send(ws,
|
|
68
|
-
id,
|
|
69
|
-
type: "error",
|
|
70
|
-
code: "WORKTREE_DIFF_FAILED",
|
|
71
|
-
message: err.message,
|
|
72
|
-
});
|
|
80
|
+
server._send(ws, envelopeError(id, "WORKTREE_DIFF_FAILED", err.message));
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
|
|
@@ -78,35 +86,31 @@ export async function handleWorktreeMerge(server, id, ws, message) {
|
|
|
78
86
|
const { mergeWorktree } = await import("../../lib/worktree-isolator.js");
|
|
79
87
|
const { branch, strategy, commitMessage } = message;
|
|
80
88
|
if (!branch) {
|
|
81
|
-
server._send(ws,
|
|
82
|
-
id,
|
|
83
|
-
type: "error",
|
|
84
|
-
code: "NO_BRANCH",
|
|
85
|
-
message: "branch required",
|
|
86
|
-
});
|
|
89
|
+
server._send(ws, envelopeError(id, "NO_BRANCH", "branch required"));
|
|
87
90
|
return;
|
|
88
91
|
}
|
|
89
92
|
const result = mergeWorktree(process.cwd(), branch, {
|
|
90
93
|
strategy: strategy || "merge",
|
|
91
94
|
message: commitMessage,
|
|
92
95
|
});
|
|
93
|
-
server._send(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
96
|
+
server._send(
|
|
97
|
+
ws,
|
|
98
|
+
envelopeResponse(CODING_AGENT_EVENT_TYPES.WORKTREE_MERGED, id, {
|
|
99
|
+
...result,
|
|
100
|
+
record: createWorktreeRecord(
|
|
101
|
+
{
|
|
102
|
+
branch,
|
|
103
|
+
summary: result.summary || null,
|
|
104
|
+
conflicts: result.conflicts || [],
|
|
105
|
+
previewEntrypoints: result.previewEntrypoints || [],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
strategy: strategy || "merge",
|
|
109
|
+
success: result.success,
|
|
110
|
+
},
|
|
111
|
+
),
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
110
114
|
server.emit(
|
|
111
115
|
RUNTIME_EVENTS.WORKTREE_MERGED,
|
|
112
116
|
createRuntimeEvent(
|
|
@@ -131,12 +135,7 @@ export async function handleWorktreeMerge(server, id, ws, message) {
|
|
|
131
135
|
),
|
|
132
136
|
);
|
|
133
137
|
} catch (err) {
|
|
134
|
-
server._send(ws,
|
|
135
|
-
id,
|
|
136
|
-
type: "error",
|
|
137
|
-
code: "WORKTREE_MERGE_FAILED",
|
|
138
|
-
message: err.message,
|
|
139
|
-
});
|
|
138
|
+
server._send(ws, envelopeError(id, "WORKTREE_MERGE_FAILED", err.message));
|
|
140
139
|
}
|
|
141
140
|
}
|
|
142
141
|
|
|
@@ -146,12 +145,7 @@ export async function handleWorktreeMergePreview(server, id, ws, message) {
|
|
|
146
145
|
await import("../../lib/worktree-isolator.js");
|
|
147
146
|
const { branch, baseBranch, strategy } = message;
|
|
148
147
|
if (!branch) {
|
|
149
|
-
server._send(ws,
|
|
150
|
-
id,
|
|
151
|
-
type: "error",
|
|
152
|
-
code: "NO_BRANCH",
|
|
153
|
-
message: "branch required",
|
|
154
|
-
});
|
|
148
|
+
server._send(ws, envelopeError(id, "NO_BRANCH", "branch required"));
|
|
155
149
|
return;
|
|
156
150
|
}
|
|
157
151
|
|
|
@@ -159,32 +153,31 @@ export async function handleWorktreeMergePreview(server, id, ws, message) {
|
|
|
159
153
|
baseBranch,
|
|
160
154
|
strategy: strategy || "merge",
|
|
161
155
|
});
|
|
162
|
-
server._send(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
156
|
+
server._send(
|
|
157
|
+
ws,
|
|
158
|
+
envelopeResponse(CODING_AGENT_EVENT_TYPES.WORKTREE_MERGE_PREVIEW, id, {
|
|
159
|
+
...result,
|
|
160
|
+
record: createWorktreeRecord(
|
|
161
|
+
{
|
|
162
|
+
branch,
|
|
163
|
+
baseBranch: result.baseBranch || baseBranch || null,
|
|
164
|
+
summary: result.summary || null,
|
|
165
|
+
conflicts: result.conflicts || [],
|
|
166
|
+
previewEntrypoints: result.previewEntrypoints || [],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
strategy: strategy || "merge",
|
|
170
|
+
success: result.success,
|
|
171
|
+
previewOnly: true,
|
|
172
|
+
},
|
|
173
|
+
),
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
181
176
|
} catch (err) {
|
|
182
|
-
server._send(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
message: err.message,
|
|
187
|
-
});
|
|
177
|
+
server._send(
|
|
178
|
+
ws,
|
|
179
|
+
envelopeError(id, "WORKTREE_MERGE_PREVIEW_FAILED", err.message),
|
|
180
|
+
);
|
|
188
181
|
}
|
|
189
182
|
}
|
|
190
183
|
|
|
@@ -194,21 +187,18 @@ export async function handleWorktreeAutomationApply(server, id, ws, message) {
|
|
|
194
187
|
await import("../../lib/worktree-isolator.js");
|
|
195
188
|
const { branch, baseBranch, filePath, candidateId, conflictType } = message;
|
|
196
189
|
if (!branch) {
|
|
197
|
-
server._send(ws,
|
|
198
|
-
id,
|
|
199
|
-
type: "error",
|
|
200
|
-
code: "NO_BRANCH",
|
|
201
|
-
message: "branch required",
|
|
202
|
-
});
|
|
190
|
+
server._send(ws, envelopeError(id, "NO_BRANCH", "branch required"));
|
|
203
191
|
return;
|
|
204
192
|
}
|
|
205
193
|
if (!filePath || !candidateId) {
|
|
206
|
-
server._send(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
194
|
+
server._send(
|
|
195
|
+
ws,
|
|
196
|
+
envelopeError(
|
|
197
|
+
id,
|
|
198
|
+
"INVALID_WORKTREE_AUTOMATION",
|
|
199
|
+
"filePath and candidateId are required",
|
|
200
|
+
),
|
|
201
|
+
);
|
|
212
202
|
return;
|
|
213
203
|
}
|
|
214
204
|
|
|
@@ -219,43 +209,46 @@ export async function handleWorktreeAutomationApply(server, id, ws, message) {
|
|
|
219
209
|
conflictType,
|
|
220
210
|
});
|
|
221
211
|
|
|
222
|
-
server._send(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
{
|
|
228
|
-
branch,
|
|
229
|
-
baseBranch: result.baseBranch || baseBranch || null,
|
|
230
|
-
hasChanges: (result.summary?.filesChanged || 0) > 0,
|
|
231
|
-
summary: result.summary || null,
|
|
232
|
-
conflicts: [],
|
|
233
|
-
previewEntrypoints:
|
|
234
|
-
result.filePath && (result.summary?.filesChanged || 0) > 0
|
|
235
|
-
? [
|
|
236
|
-
{
|
|
237
|
-
type: "worktree-diff",
|
|
238
|
-
branch,
|
|
239
|
-
filePath: result.filePath,
|
|
240
|
-
},
|
|
241
|
-
]
|
|
242
|
-
: [],
|
|
243
|
-
},
|
|
212
|
+
server._send(
|
|
213
|
+
ws,
|
|
214
|
+
envelopeResponse(
|
|
215
|
+
CODING_AGENT_EVENT_TYPES.WORKTREE_AUTOMATION_APPLIED,
|
|
216
|
+
id,
|
|
244
217
|
{
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
218
|
+
...result,
|
|
219
|
+
record: createWorktreeRecord(
|
|
220
|
+
{
|
|
221
|
+
branch,
|
|
222
|
+
baseBranch: result.baseBranch || baseBranch || null,
|
|
223
|
+
hasChanges: (result.summary?.filesChanged || 0) > 0,
|
|
224
|
+
summary: result.summary || null,
|
|
225
|
+
conflicts: [],
|
|
226
|
+
previewEntrypoints:
|
|
227
|
+
result.filePath && (result.summary?.filesChanged || 0) > 0
|
|
228
|
+
? [
|
|
229
|
+
{
|
|
230
|
+
type: "worktree-diff",
|
|
231
|
+
branch,
|
|
232
|
+
filePath: result.filePath,
|
|
233
|
+
},
|
|
234
|
+
]
|
|
235
|
+
: [],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
candidateId,
|
|
239
|
+
filePath,
|
|
240
|
+
conflictType: conflictType || null,
|
|
241
|
+
success: true,
|
|
242
|
+
},
|
|
243
|
+
),
|
|
249
244
|
},
|
|
250
245
|
),
|
|
251
|
-
|
|
246
|
+
);
|
|
252
247
|
} catch (err) {
|
|
253
|
-
server._send(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
message: err.message,
|
|
258
|
-
});
|
|
248
|
+
server._send(
|
|
249
|
+
ws,
|
|
250
|
+
envelopeError(id, "WORKTREE_AUTOMATION_FAILED", err.message),
|
|
251
|
+
);
|
|
259
252
|
}
|
|
260
253
|
}
|
|
261
254
|
|
|
@@ -265,14 +258,14 @@ export async function handleWorktreeList(server, id, ws) {
|
|
|
265
258
|
const worktrees = listWorktrees(process.cwd()).filter(
|
|
266
259
|
(wt) => wt.branch && wt.branch.startsWith("agent/"),
|
|
267
260
|
);
|
|
268
|
-
server._send(
|
|
261
|
+
server._send(
|
|
262
|
+
ws,
|
|
263
|
+
envelopeResponse(CODING_AGENT_EVENT_TYPES.WORKTREE_LIST, id, {
|
|
264
|
+
worktrees,
|
|
265
|
+
}),
|
|
266
|
+
);
|
|
269
267
|
} catch (err) {
|
|
270
|
-
server._send(ws,
|
|
271
|
-
id,
|
|
272
|
-
type: "error",
|
|
273
|
-
code: "WORKTREE_LIST_FAILED",
|
|
274
|
-
message: err.message,
|
|
275
|
-
});
|
|
268
|
+
server._send(ws, envelopeError(id, "WORKTREE_LIST_FAILED", err.message));
|
|
276
269
|
}
|
|
277
270
|
}
|
|
278
271
|
|