@carboncode/cli 0.1.0 → 0.1.2
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/README.md +15 -24
- package/README.zh-CN.md +13 -11
- package/dist/cli/{acp-35C4ME6Y.js → acp-6J54TVVC.js} +17 -16
- package/dist/cli/acp-6J54TVVC.js.map +1 -0
- package/dist/cli/{chat-A6UJDPGV.js → chat-636MFZ7W.js} +21 -21
- package/dist/cli/{chunk-JKGYMRX5.js → chunk-3N7FTZVE.js} +2 -2
- package/dist/cli/{chunk-4TVNJWMA.js → chunk-ACHQFKW2.js} +178 -18
- package/dist/cli/chunk-ACHQFKW2.js.map +1 -0
- package/dist/cli/{chunk-7L2WTRNU.js → chunk-ANVEA3RU.js} +2 -2
- package/dist/cli/{chunk-QVC75MR3.js → chunk-BXMMGFAL.js} +2 -2
- package/dist/cli/{chunk-UI66BH6D.js → chunk-COTWTQQZ.js} +2 -2
- package/dist/cli/{chunk-J5BYPUB5.js → chunk-CZCPIK5K.js} +1508 -1176
- package/dist/cli/chunk-CZCPIK5K.js.map +1 -0
- package/dist/cli/{chunk-XJ5SRLKK.js → chunk-D3ACJ6D5.js} +2 -2
- package/dist/cli/{chunk-WRN65TRD.js → chunk-DSQNSP7F.js} +2 -2
- package/dist/cli/{chunk-QJG7OF27.js → chunk-FKSYTVWZ.js} +27 -10
- package/dist/cli/chunk-FKSYTVWZ.js.map +1 -0
- package/dist/cli/{chunk-BSINVTTL.js → chunk-FXG7CSGY.js} +7 -7
- package/dist/cli/{chunk-4MQ3VURH.js → chunk-K43DXH3G.js} +52 -83
- package/dist/cli/chunk-K43DXH3G.js.map +1 -0
- package/dist/cli/{chunk-BSGCXZQN.js → chunk-LNU3CR7X.js} +2 -2
- package/dist/cli/{chunk-TH756VLN.js → chunk-MXUSER5C.js} +240 -191
- package/dist/cli/chunk-MXUSER5C.js.map +1 -0
- package/dist/cli/{chunk-3T6VBZCL.js → chunk-NQJYZKEU.js} +2 -2
- package/dist/cli/{chunk-IX6XI2RG.js → chunk-OB5XR5HG.js} +2 -2
- package/dist/cli/{chunk-ILJOIQ5W.js → chunk-OY5GGU6D.js} +2 -2
- package/dist/cli/{chunk-IAUOP25G.js → chunk-R677DIFU.js} +38 -22
- package/dist/cli/chunk-R677DIFU.js.map +1 -0
- package/dist/cli/{chunk-CPKCNHRR.js → chunk-RSQMO6CF.js} +5 -5
- package/dist/cli/{chunk-3OAR6NVL.js → chunk-RUPXIRNL.js} +2 -2
- package/dist/cli/{chunk-S2KIUQKQ.js → chunk-S4YD3N3X.js} +7 -6
- package/dist/cli/{chunk-S2KIUQKQ.js.map → chunk-S4YD3N3X.js.map} +1 -1
- package/dist/cli/{chunk-4IBIPQVB.js → chunk-T6SBUSG2.js} +3 -3
- package/dist/cli/{chunk-D5NFKRGO.js → chunk-UGPC4LPM.js} +2 -2
- package/dist/cli/{chunk-T5TQ4NDT.js → chunk-X4UJ6Q6M.js} +3 -3
- package/dist/cli/{code-4TUTAGO5.js → code-TBC3K5AZ.js} +24 -33
- package/dist/cli/code-TBC3K5AZ.js.map +1 -0
- package/dist/cli/{commands-KMOZEYCF.js → commands-HMQPRVNT.js} +4 -4
- package/dist/cli/{commit-DTFA56VQ.js → commit-WIY4B3X4.js} +3 -3
- package/dist/cli/{desktop-7N3MHNBD.js → desktop-MGOG3AWV.js} +17 -17
- package/dist/cli/{diff-E5OWTF4C.js → diff-57LRKCB7.js} +8 -8
- package/dist/cli/{doctor-IEJQRJMN.js → doctor-5FDRBIXE.js} +8 -8
- package/dist/cli/index.js +32 -32
- package/dist/cli/{mcp-PDI2PDLG.js → mcp-HJHTNRZF.js} +2 -2
- package/dist/cli/{mcp-browse-OSPXOFPZ.js → mcp-browse-C2PJRQBO.js} +2 -2
- package/dist/cli/{mcp-inspect-QRFVTHMF.js → mcp-inspect-JBFXV2II.js} +2 -2
- package/dist/cli/{prompt-3CDII3UO.js → prompt-U62OVZNY.js} +3 -3
- package/dist/cli/{replay-HYOSRQIV.js → replay-M3YKBVAM.js} +8 -8
- package/dist/cli/{run-2ZHADOUP.js → run-V6X5GXCR.js} +13 -13
- package/dist/cli/{server-X75PAZG5.js → server-5WVJQUOR.js} +10 -10
- package/dist/cli/{sessions-POOZA5CQ.js → sessions-B266WVM3.js} +12 -12
- package/dist/cli/{setup-YLPFI3OH.js → setup-SWX5E3W2.js} +5 -5
- package/dist/cli/{stats-NXJ3TO2D.js → stats-VPPKS6UF.js} +6 -6
- package/dist/cli/{version-NXXWE3WN.js → version-TVHAEHWY.js} +12 -12
- package/dist/index.d.ts +17 -2
- package/dist/index.js +360 -150
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/cli/acp-35C4ME6Y.js.map +0 -1
- package/dist/cli/chunk-4MQ3VURH.js.map +0 -1
- package/dist/cli/chunk-4TVNJWMA.js.map +0 -1
- package/dist/cli/chunk-IAUOP25G.js.map +0 -1
- package/dist/cli/chunk-J5BYPUB5.js.map +0 -1
- package/dist/cli/chunk-QJG7OF27.js.map +0 -1
- package/dist/cli/chunk-TH756VLN.js.map +0 -1
- package/dist/cli/code-4TUTAGO5.js.map +0 -1
- /package/dist/cli/{chat-A6UJDPGV.js.map → chat-636MFZ7W.js.map} +0 -0
- /package/dist/cli/{chunk-JKGYMRX5.js.map → chunk-3N7FTZVE.js.map} +0 -0
- /package/dist/cli/{chunk-7L2WTRNU.js.map → chunk-ANVEA3RU.js.map} +0 -0
- /package/dist/cli/{chunk-QVC75MR3.js.map → chunk-BXMMGFAL.js.map} +0 -0
- /package/dist/cli/{chunk-UI66BH6D.js.map → chunk-COTWTQQZ.js.map} +0 -0
- /package/dist/cli/{chunk-XJ5SRLKK.js.map → chunk-D3ACJ6D5.js.map} +0 -0
- /package/dist/cli/{chunk-WRN65TRD.js.map → chunk-DSQNSP7F.js.map} +0 -0
- /package/dist/cli/{chunk-BSINVTTL.js.map → chunk-FXG7CSGY.js.map} +0 -0
- /package/dist/cli/{chunk-BSGCXZQN.js.map → chunk-LNU3CR7X.js.map} +0 -0
- /package/dist/cli/{chunk-3T6VBZCL.js.map → chunk-NQJYZKEU.js.map} +0 -0
- /package/dist/cli/{chunk-IX6XI2RG.js.map → chunk-OB5XR5HG.js.map} +0 -0
- /package/dist/cli/{chunk-ILJOIQ5W.js.map → chunk-OY5GGU6D.js.map} +0 -0
- /package/dist/cli/{chunk-CPKCNHRR.js.map → chunk-RSQMO6CF.js.map} +0 -0
- /package/dist/cli/{chunk-3OAR6NVL.js.map → chunk-RUPXIRNL.js.map} +0 -0
- /package/dist/cli/{chunk-4IBIPQVB.js.map → chunk-T6SBUSG2.js.map} +0 -0
- /package/dist/cli/{chunk-D5NFKRGO.js.map → chunk-UGPC4LPM.js.map} +0 -0
- /package/dist/cli/{chunk-T5TQ4NDT.js.map → chunk-X4UJ6Q6M.js.map} +0 -0
- /package/dist/cli/{commands-KMOZEYCF.js.map → commands-HMQPRVNT.js.map} +0 -0
- /package/dist/cli/{commit-DTFA56VQ.js.map → commit-WIY4B3X4.js.map} +0 -0
- /package/dist/cli/{desktop-7N3MHNBD.js.map → desktop-MGOG3AWV.js.map} +0 -0
- /package/dist/cli/{diff-E5OWTF4C.js.map → diff-57LRKCB7.js.map} +0 -0
- /package/dist/cli/{doctor-IEJQRJMN.js.map → doctor-5FDRBIXE.js.map} +0 -0
- /package/dist/cli/{mcp-PDI2PDLG.js.map → mcp-HJHTNRZF.js.map} +0 -0
- /package/dist/cli/{mcp-browse-OSPXOFPZ.js.map → mcp-browse-C2PJRQBO.js.map} +0 -0
- /package/dist/cli/{mcp-inspect-QRFVTHMF.js.map → mcp-inspect-JBFXV2II.js.map} +0 -0
- /package/dist/cli/{prompt-3CDII3UO.js.map → prompt-U62OVZNY.js.map} +0 -0
- /package/dist/cli/{replay-HYOSRQIV.js.map → replay-M3YKBVAM.js.map} +0 -0
- /package/dist/cli/{run-2ZHADOUP.js.map → run-V6X5GXCR.js.map} +0 -0
- /package/dist/cli/{server-X75PAZG5.js.map → server-5WVJQUOR.js.map} +0 -0
- /package/dist/cli/{sessions-POOZA5CQ.js.map → sessions-B266WVM3.js.map} +0 -0
- /package/dist/cli/{setup-YLPFI3OH.js.map → setup-SWX5E3W2.js.map} +0 -0
- /package/dist/cli/{stats-NXJ3TO2D.js.map → stats-VPPKS6UF.js.map} +0 -0
- /package/dist/cli/{version-NXXWE3WN.js.map → version-TVHAEHWY.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -33,35 +33,35 @@ function defineTheme(base) {
|
|
|
33
33
|
}
|
|
34
34
|
var githubDark = defineTheme({
|
|
35
35
|
fg: {
|
|
36
|
-
strong: "#
|
|
37
|
-
body: "#
|
|
38
|
-
sub: "#
|
|
39
|
-
meta: "#
|
|
40
|
-
faint: "#
|
|
36
|
+
strong: "#f8fafc",
|
|
37
|
+
body: "#e5e7eb",
|
|
38
|
+
sub: "#a1a1aa",
|
|
39
|
+
meta: "#71717a",
|
|
40
|
+
faint: "#52525b"
|
|
41
41
|
},
|
|
42
42
|
tone: {
|
|
43
|
-
brand: "#
|
|
44
|
-
accent: "#
|
|
45
|
-
violet: "#
|
|
46
|
-
ok: "#
|
|
47
|
-
warn: "#
|
|
48
|
-
err: "#
|
|
49
|
-
info: "#
|
|
43
|
+
brand: "#f8fafc",
|
|
44
|
+
accent: "#a78bfa",
|
|
45
|
+
violet: "#c084fc",
|
|
46
|
+
ok: "#22c55e",
|
|
47
|
+
warn: "#eab308",
|
|
48
|
+
err: "#ef4444",
|
|
49
|
+
info: "#60a5fa"
|
|
50
50
|
},
|
|
51
51
|
toneActive: {
|
|
52
|
-
brand: "#
|
|
53
|
-
accent: "#
|
|
54
|
-
violet: "#
|
|
55
|
-
ok: "#
|
|
56
|
-
warn: "#
|
|
57
|
-
err: "#
|
|
58
|
-
info: "#
|
|
52
|
+
brand: "#ffffff",
|
|
53
|
+
accent: "#c4b5fd",
|
|
54
|
+
violet: "#d8b4fe",
|
|
55
|
+
ok: "#4ade80",
|
|
56
|
+
warn: "#facc15",
|
|
57
|
+
err: "#f87171",
|
|
58
|
+
info: "#93c5fd"
|
|
59
59
|
},
|
|
60
60
|
surface: {
|
|
61
|
-
bg: "#
|
|
62
|
-
bgInput: "#
|
|
63
|
-
bgCode: "#
|
|
64
|
-
bgElev: "#
|
|
61
|
+
bg: "#09090b",
|
|
62
|
+
bgInput: "#111113",
|
|
63
|
+
bgCode: "#050507",
|
|
64
|
+
bgElev: "#18181b"
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
var dark = defineTheme({
|
|
@@ -97,39 +97,40 @@ var dark = defineTheme({
|
|
|
97
97
|
bgElev: "#151d2f"
|
|
98
98
|
}
|
|
99
99
|
});
|
|
100
|
-
var
|
|
100
|
+
var codexLightBase = {
|
|
101
101
|
fg: {
|
|
102
|
-
strong: "#
|
|
103
|
-
body: "#
|
|
104
|
-
sub: "#
|
|
105
|
-
meta: "#
|
|
106
|
-
faint: "#
|
|
102
|
+
strong: "#0d0d0d",
|
|
103
|
+
body: "#111111",
|
|
104
|
+
sub: "#666666",
|
|
105
|
+
meta: "#9a9a9a",
|
|
106
|
+
faint: "#c7c7c7"
|
|
107
107
|
},
|
|
108
108
|
tone: {
|
|
109
|
-
brand: "#
|
|
110
|
-
accent: "#
|
|
111
|
-
violet: "#
|
|
112
|
-
ok: "#
|
|
113
|
-
warn: "#
|
|
114
|
-
err: "#
|
|
115
|
-
info: "#
|
|
109
|
+
brand: "#0096a6",
|
|
110
|
+
accent: "#c000c0",
|
|
111
|
+
violet: "#7a5cff",
|
|
112
|
+
ok: "#238636",
|
|
113
|
+
warn: "#8a7a00",
|
|
114
|
+
err: "#c62828",
|
|
115
|
+
info: "#0096a6"
|
|
116
116
|
},
|
|
117
117
|
toneActive: {
|
|
118
|
-
brand: "#
|
|
119
|
-
accent: "#
|
|
120
|
-
violet: "#
|
|
121
|
-
ok: "#
|
|
122
|
-
warn: "#
|
|
123
|
-
err: "#
|
|
124
|
-
info: "#
|
|
118
|
+
brand: "#00a3b5",
|
|
119
|
+
accent: "#d000d0",
|
|
120
|
+
violet: "#8a6dff",
|
|
121
|
+
ok: "#2ea043",
|
|
122
|
+
warn: "#9a8700",
|
|
123
|
+
err: "#d32f2f",
|
|
124
|
+
info: "#00a3b5"
|
|
125
125
|
},
|
|
126
126
|
surface: {
|
|
127
127
|
bg: "#ffffff",
|
|
128
|
-
bgInput: "#
|
|
129
|
-
bgCode: "#
|
|
130
|
-
bgElev: "#
|
|
128
|
+
bgInput: "#f2f2f2",
|
|
129
|
+
bgCode: "#f5f5f5",
|
|
130
|
+
bgElev: "#e7e7e7"
|
|
131
131
|
}
|
|
132
|
-
}
|
|
132
|
+
};
|
|
133
|
+
var light = defineTheme(codexLightBase);
|
|
133
134
|
var tokyoNight = defineTheme({
|
|
134
135
|
fg: {
|
|
135
136
|
strong: "#c0caf5",
|
|
@@ -163,39 +164,7 @@ var tokyoNight = defineTheme({
|
|
|
163
164
|
bgElev: "#24283b"
|
|
164
165
|
}
|
|
165
166
|
});
|
|
166
|
-
var githubLight = defineTheme(
|
|
167
|
-
fg: {
|
|
168
|
-
strong: "#1f2328",
|
|
169
|
-
body: "#24292f",
|
|
170
|
-
sub: "#57606a",
|
|
171
|
-
meta: "#6e7781",
|
|
172
|
-
faint: "#8c959f"
|
|
173
|
-
},
|
|
174
|
-
tone: {
|
|
175
|
-
brand: "#0969da",
|
|
176
|
-
accent: "#8250df",
|
|
177
|
-
violet: "#6639ba",
|
|
178
|
-
ok: "#1a7f37",
|
|
179
|
-
warn: "#9a6700",
|
|
180
|
-
err: "#cf222e",
|
|
181
|
-
info: "#0969da"
|
|
182
|
-
},
|
|
183
|
-
toneActive: {
|
|
184
|
-
brand: "#0550ae",
|
|
185
|
-
accent: "#6639ba",
|
|
186
|
-
violet: "#512a97",
|
|
187
|
-
ok: "#116329",
|
|
188
|
-
warn: "#7d4e00",
|
|
189
|
-
err: "#a40e26",
|
|
190
|
-
info: "#0550ae"
|
|
191
|
-
},
|
|
192
|
-
surface: {
|
|
193
|
-
bg: "#ffffff",
|
|
194
|
-
bgInput: "#f6f8fa",
|
|
195
|
-
bgCode: "#f6f8fa",
|
|
196
|
-
bgElev: "#eaeef2"
|
|
197
|
-
}
|
|
198
|
-
});
|
|
167
|
+
var githubLight = defineTheme(codexLightBase);
|
|
199
168
|
var highContrast = defineTheme({
|
|
200
169
|
fg: {
|
|
201
170
|
strong: "#ffffff",
|
|
@@ -230,7 +199,7 @@ var highContrast = defineTheme({
|
|
|
230
199
|
}
|
|
231
200
|
});
|
|
232
201
|
var THEMES = {
|
|
233
|
-
default:
|
|
202
|
+
default: githubLight,
|
|
234
203
|
dark,
|
|
235
204
|
light,
|
|
236
205
|
"tokyo-night": tokyoNight,
|
|
@@ -238,7 +207,7 @@ var THEMES = {
|
|
|
238
207
|
"github-light": githubLight,
|
|
239
208
|
"high-contrast": highContrast
|
|
240
209
|
};
|
|
241
|
-
var DEFAULT_THEME_NAME = "
|
|
210
|
+
var DEFAULT_THEME_NAME = "github-light";
|
|
242
211
|
var DEFAULT_THEME = THEMES[DEFAULT_THEME_NAME];
|
|
243
212
|
var activeTheme = DEFAULT_THEME;
|
|
244
213
|
function proxyTokens(select) {
|
|
@@ -1139,13 +1108,16 @@ var EN = {
|
|
|
1139
1108
|
},
|
|
1140
1109
|
ui: {
|
|
1141
1110
|
welcome: "Run `carboncode` any time to start chatting \u2014 your settings are remembered.",
|
|
1142
|
-
taglineChat: "
|
|
1143
|
-
taglineCode: "
|
|
1144
|
-
taglineSub: "
|
|
1145
|
-
startSessionHint: "type a
|
|
1111
|
+
taglineChat: "terminal coding agent",
|
|
1112
|
+
taglineCode: "terminal coding agent",
|
|
1113
|
+
taglineSub: "read the repo, edit files, run validation",
|
|
1114
|
+
startSessionHint: "type a task to start",
|
|
1146
1115
|
inputPlaceholder: "Ask anything... (type / for commands, @ for files)",
|
|
1147
1116
|
busy: "Thinking...",
|
|
1148
1117
|
thinking: "\u25B8 thinking...",
|
|
1118
|
+
activityWaitingForModel: "waiting for model\u2026",
|
|
1119
|
+
activityThinking: "thinking\u2026",
|
|
1120
|
+
activityProcessing: "processing\u2026",
|
|
1149
1121
|
undo: "Undo",
|
|
1150
1122
|
undoHint: "press u within 5s to undo",
|
|
1151
1123
|
applied: "applied",
|
|
@@ -1623,6 +1595,7 @@ var EN = {
|
|
|
1623
1595
|
app: {
|
|
1624
1596
|
walkCancelledRemaining: "\u25B8 walk cancelled \u2014 {count} block(s) still pending.",
|
|
1625
1597
|
walkCancelled: "\u25B8 walk cancelled.",
|
|
1598
|
+
turnInterrupted: "\u25B8 turn interrupted \u2014 type a follow-up to continue.",
|
|
1626
1599
|
editModeYolo: "\u25B8 edit mode: YOLO \u2014 edits AND shell commands auto-run. /undo still rolls back edits. Use carefully.",
|
|
1627
1600
|
editModeAuto: "\u25B8 edit mode: AUTO \u2014 edits apply immediately; press u within 5s to undo (space pauses the timer). Shell commands still ask.",
|
|
1628
1601
|
editModeReview: "\u25B8 edit mode: review \u2014 edits queue for /apply (or y) / /discard (or n)",
|
|
@@ -2103,10 +2076,13 @@ var EN = {
|
|
|
2103
2076
|
queuedApplyDiscard: "{count} queued \xB7 y apply \xB7 n discard",
|
|
2104
2077
|
editsQueued: "edits queued \xB7 y apply \xB7 n discard",
|
|
2105
2078
|
shiftTabFlip: " {mid} \xB7 Shift+Tab to flip",
|
|
2106
|
-
queuedDots: "queued\u2026"
|
|
2079
|
+
queuedDots: "queued\u2026",
|
|
2080
|
+
undoApplied: "applied {ok}/{total}",
|
|
2081
|
+
undoHint: "u undo \xB7 Space pause",
|
|
2082
|
+
undoPausedHint: "u undo \xB7 Space resume"
|
|
2107
2083
|
},
|
|
2108
2084
|
composer: {
|
|
2109
|
-
placeholder: "
|
|
2085
|
+
placeholder: "Ask for a code change",
|
|
2110
2086
|
waitingForResponse: "\u2026waiting for response\u2026",
|
|
2111
2087
|
hintSend: "send",
|
|
2112
2088
|
hintNewline: "newline",
|
|
@@ -2130,7 +2106,7 @@ var EN = {
|
|
|
2130
2106
|
denyTitle: "Deny \u2014 provide context",
|
|
2131
2107
|
optional: "optional",
|
|
2132
2108
|
denyFooter: "type context \xB7 \u23CE submit with reason \xB7 esc skip (deny without reason)",
|
|
2133
|
-
pickFooter: "\u2191\u2193 pick \xB7 \u23CE confirm \xB7
|
|
2109
|
+
pickFooter: "\u2191\u2193 pick \xB7 \u23CE confirm \xB7 esc cancel",
|
|
2134
2110
|
allowOnce: "allow once",
|
|
2135
2111
|
allowOnceDesc: "permit this access; remember the directory for the rest of this session",
|
|
2136
2112
|
allowAlways: "allow always",
|
|
@@ -2150,7 +2126,7 @@ var EN = {
|
|
|
2150
2126
|
optional: "optional",
|
|
2151
2127
|
denyFooter: "type context \xB7 \u23CE submit with reason \xB7 esc skip (deny without reason)",
|
|
2152
2128
|
awaiting: "awaiting",
|
|
2153
|
-
pickFooter: "\u2191\u2193 pick \xB7 \u23CE confirm \xB7
|
|
2129
|
+
pickFooter: "\u2191\u2193 pick \xB7 \u23CE confirm \xB7 esc cancel",
|
|
2154
2130
|
allowOnce: "allow once",
|
|
2155
2131
|
allowOnceDesc: "run this command, ask again next time",
|
|
2156
2132
|
allowAlways: "allow always",
|
|
@@ -2164,7 +2140,7 @@ var EN = {
|
|
|
2164
2140
|
previewMorePlural: "\u2026 {n} more lines hidden \u2014 press esc, ask the model to split it"
|
|
2165
2141
|
},
|
|
2166
2142
|
editConfirm: {
|
|
2167
|
-
footer: "
|
|
2143
|
+
footer: "Enter apply \xB7 n reject \xB7 \u2191\u2193 scroll \xB7 Esc cancel",
|
|
2168
2144
|
newTag: "NEW",
|
|
2169
2145
|
editTag: "EDIT",
|
|
2170
2146
|
linesCount: "-{removed} +{added} lines",
|
|
@@ -2286,7 +2262,8 @@ var EN = {
|
|
|
2286
2262
|
startup: {
|
|
2287
2263
|
codeRooted: '\u25B8 carboncode code: rooted at {rootDir}, session "{session}" \xB7 {tools} native tool(s){semantic}',
|
|
2288
2264
|
ephemeral: "(ephemeral)",
|
|
2289
|
-
semanticOn: " \xB7 semantic_search on"
|
|
2265
|
+
semanticOn: " \xB7 semantic_search on",
|
|
2266
|
+
updateAvailable: "\u25B8 Update available: {current} -> {latest}\n Run `npm install -g @carboncode/cli` to update."
|
|
2290
2267
|
},
|
|
2291
2268
|
doctorErrors: {
|
|
2292
2269
|
unreadable: "{path} unreadable \u2014 {message}",
|
|
@@ -2583,13 +2560,16 @@ var zhCN = {
|
|
|
2583
2560
|
},
|
|
2584
2561
|
ui: {
|
|
2585
2562
|
welcome: "\u968F\u65F6\u8FD0\u884C `carboncode` \u5F00\u59CB\u804A\u5929 \u2014 \u60A8\u7684\u8BBE\u7F6E\u5C06\u88AB\u8BB0\u4F4F\u3002",
|
|
2586
|
-
taglineChat: "
|
|
2587
|
-
taglineCode: "
|
|
2588
|
-
taglineSub: "\
|
|
2589
|
-
startSessionHint: "\u8F93\u5165\
|
|
2563
|
+
taglineChat: "\u7EC8\u7AEF\u4EE3\u7801\u667A\u80FD\u4F53",
|
|
2564
|
+
taglineCode: "\u7EC8\u7AEF\u4EE3\u7801\u667A\u80FD\u4F53",
|
|
2565
|
+
taglineSub: "\u8BFB\u53D6\u4ED3\u5E93\u3001\u7F16\u8F91\u6587\u4EF6\u3001\u8FD0\u884C\u9A8C\u8BC1",
|
|
2566
|
+
startSessionHint: "\u8F93\u5165\u4EFB\u52A1\u5F00\u59CB",
|
|
2590
2567
|
inputPlaceholder: "\u8F93\u5165\u4EFB\u4F55\u5185\u5BB9... (\u8F93\u5165 / \u4F7F\u7528\u547D\u4EE4, @ \u5F15\u7528\u6587\u4EF6)",
|
|
2591
2568
|
busy: "\u601D\u8003\u4E2D...",
|
|
2592
2569
|
thinking: "\u25B8 \u601D\u8003\u4E2D...",
|
|
2570
|
+
activityWaitingForModel: "\u7B49\u5F85\u6A21\u578B\u2026",
|
|
2571
|
+
activityThinking: "\u601D\u8003\u4E2D\u2026",
|
|
2572
|
+
activityProcessing: "\u5904\u7406\u4E2D\u2026",
|
|
2593
2573
|
undo: "\u64A4\u6D88",
|
|
2594
2574
|
undoHint: "\u5728 5 \u79D2\u5185\u6309 u \u64A4\u6D88",
|
|
2595
2575
|
applied: "\u5DF2\u5E94\u7528",
|
|
@@ -3068,6 +3048,7 @@ var zhCN = {
|
|
|
3068
3048
|
app: {
|
|
3069
3049
|
walkCancelledRemaining: "\u25B8 \u6D4F\u89C8\u5DF2\u53D6\u6D88 \u2014 \u8FD8\u6709 {count} \u4E2A\u5F85\u5904\u7406\u7F16\u8F91\u5757\u3002",
|
|
3070
3050
|
walkCancelled: "\u25B8 \u6D4F\u89C8\u5DF2\u53D6\u6D88\u3002",
|
|
3051
|
+
turnInterrupted: "\u25B8 \u672C\u8F6E\u5DF2\u4E2D\u65AD \u2014 \u8F93\u5165\u540E\u7EED\u5185\u5BB9\u53EF\u7EE7\u7EED\u3002",
|
|
3071
3052
|
editModeYolo: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AYOLO \u2014 \u7F16\u8F91\u548C shell \u547D\u4EE4\u90FD\u81EA\u52A8\u6267\u884C\u3002/undo \u4ECD\u53EF\u64A4\u9500\u7F16\u8F91\u3002\u8BF7\u8C28\u614E\u4F7F\u7528\u3002",
|
|
3072
3053
|
editModeAuto: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AAUTO \u2014 \u7F16\u8F91\u7ACB\u5373\u5E94\u7528\uFF1B5 \u79D2\u5185\u6309 u \u64A4\u9500\uFF08\u7A7A\u683C\u6682\u505C\u8BA1\u65F6\uFF09\u3002shell \u547D\u4EE4\u4ECD\u4F1A\u8BE2\u95EE\u3002",
|
|
3073
3054
|
editModeReview: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1Areview \u2014 \u7F16\u8F91\u5165\u961F\u5F85 /apply\uFF08\u6216 y\uFF09/ /discard\uFF08\u6216 n\uFF09",
|
|
@@ -3548,10 +3529,13 @@ var zhCN = {
|
|
|
3548
3529
|
queuedApplyDiscard: "{count} \u4E2A\u5F85\u5904\u7406 \xB7 y \u5E94\u7528 \xB7 n \u4E22\u5F03",
|
|
3549
3530
|
editsQueued: "\u7F16\u8F91\u5DF2\u6392\u961F \xB7 y \u5E94\u7528 \xB7 n \u4E22\u5F03",
|
|
3550
3531
|
shiftTabFlip: " {mid} \xB7 Shift+Tab \u5207\u6362",
|
|
3551
|
-
queuedDots: "\u6392\u961F\u4E2D\u2026"
|
|
3532
|
+
queuedDots: "\u6392\u961F\u4E2D\u2026",
|
|
3533
|
+
undoApplied: "\u5DF2\u5E94\u7528 {ok}/{total}",
|
|
3534
|
+
undoHint: "u \u64A4\u6D88 \xB7 Space \u6682\u505C",
|
|
3535
|
+
undoPausedHint: "u \u64A4\u6D88 \xB7 Space \u7EE7\u7EED"
|
|
3552
3536
|
},
|
|
3553
3537
|
composer: {
|
|
3554
|
-
placeholder: "\u8F93\u5165\u4EFB\
|
|
3538
|
+
placeholder: "\u8F93\u5165\u4EFB\u52A1",
|
|
3555
3539
|
waitingForResponse: "\u2026\u7B49\u5F85\u54CD\u5E94\u2026",
|
|
3556
3540
|
hintSend: "\u53D1\u9001",
|
|
3557
3541
|
hintNewline: "\u6362\u884C",
|
|
@@ -3575,7 +3559,7 @@ var zhCN = {
|
|
|
3575
3559
|
denyTitle: "\u62D2\u7EDD \u2014 \u63D0\u4F9B\u539F\u56E0",
|
|
3576
3560
|
optional: "\u53EF\u9009",
|
|
3577
3561
|
denyFooter: "\u8F93\u5165\u539F\u56E0 \xB7 \u23CE \u63D0\u4EA4 \xB7 Esc \u8DF3\u8FC7\uFF08\u76F4\u63A5\u62D2\u7EDD\uFF09",
|
|
3578
|
-
pickFooter: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7
|
|
3562
|
+
pickFooter: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7 Esc \u53D6\u6D88",
|
|
3579
3563
|
allowOnce: "\u5141\u8BB8\u4E00\u6B21",
|
|
3580
3564
|
allowOnceDesc: "\u672C\u6B21\u5141\u8BB8\uFF0C\u672C\u4F1A\u8BDD\u5185\u6B64\u76EE\u5F55\u4E0D\u518D\u8BE2\u95EE",
|
|
3581
3565
|
allowAlways: "\u59CB\u7EC8\u5141\u8BB8",
|
|
@@ -3595,7 +3579,7 @@ var zhCN = {
|
|
|
3595
3579
|
optional: "\u53EF\u9009",
|
|
3596
3580
|
denyFooter: "\u8F93\u5165\u539F\u56E0 \xB7 \u23CE \u63D0\u4EA4 \xB7 Esc \u8DF3\u8FC7\uFF08\u76F4\u63A5\u62D2\u7EDD\uFF09",
|
|
3597
3581
|
awaiting: "\u7B49\u5F85\u4E2D",
|
|
3598
|
-
pickFooter: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7
|
|
3582
|
+
pickFooter: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u786E\u8BA4 \xB7 Esc \u53D6\u6D88",
|
|
3599
3583
|
allowOnce: "\u5141\u8BB8\u4E00\u6B21",
|
|
3600
3584
|
allowOnceDesc: "\u6267\u884C\u6B64\u547D\u4EE4\uFF0C\u4E0B\u6B21\u518D\u95EE",
|
|
3601
3585
|
allowAlways: "\u59CB\u7EC8\u5141\u8BB8",
|
|
@@ -3609,7 +3593,7 @@ var zhCN = {
|
|
|
3609
3593
|
previewMorePlural: "\u2026 \u8FD8\u6709 {n} \u884C\u672A\u663E\u793A \u2014 \u6309 esc \u53D6\u6D88\uFF0C\u8BA9\u6A21\u578B\u62C6\u5206\u540E\u518D\u8BD5"
|
|
3610
3594
|
},
|
|
3611
3595
|
editConfirm: {
|
|
3612
|
-
footer: "
|
|
3596
|
+
footer: "Enter \u5E94\u7528 \xB7 n \u62D2\u7EDD \xB7 \u2191\u2193 \u6EDA\u52A8 \xB7 Esc \u53D6\u6D88",
|
|
3613
3597
|
newTag: "\u65B0\u589E",
|
|
3614
3598
|
editTag: "\u7F16\u8F91",
|
|
3615
3599
|
linesCount: "-{removed} +{added} \u884C",
|
|
@@ -3731,7 +3715,8 @@ var zhCN = {
|
|
|
3731
3715
|
startup: {
|
|
3732
3716
|
codeRooted: '\u25B8 carboncode code\uFF1A\u6839\u76EE\u5F55 {rootDir}\uFF0C\u4F1A\u8BDD "{session}" \xB7 {tools} \u4E2A\u539F\u751F\u5DE5\u5177{semantic}',
|
|
3733
3717
|
ephemeral: "\uFF08\u4E34\u65F6\uFF09",
|
|
3734
|
-
semanticOn: " \xB7 \u8BED\u4E49\u641C\u7D22\u5DF2\u5F00\u542F"
|
|
3718
|
+
semanticOn: " \xB7 \u8BED\u4E49\u641C\u7D22\u5DF2\u5F00\u542F",
|
|
3719
|
+
updateAvailable: "\u25B8 \u6709\u65B0\u7248\u672C\u53EF\u7528\uFF1A{current} -> {latest}\n \u8FD0\u884C `npm install -g @carboncode/cli` \u66F4\u65B0\u3002"
|
|
3735
3720
|
},
|
|
3736
3721
|
doctorErrors: {
|
|
3737
3722
|
unreadable: "{path} \u65E0\u6CD5\u8BFB\u53D6 \u2014 {message}",
|
|
@@ -4785,9 +4770,14 @@ var ToolRegistry = class {
|
|
|
4785
4770
|
rejectedReason: "plan-mode"
|
|
4786
4771
|
});
|
|
4787
4772
|
}
|
|
4773
|
+
const dispatchCtx = {
|
|
4774
|
+
signal: opts.signal,
|
|
4775
|
+
confirmationGate: opts.confirmationGate,
|
|
4776
|
+
onInteractiveWait: opts.onInteractiveWait
|
|
4777
|
+
};
|
|
4788
4778
|
if (this._interceptor) {
|
|
4789
4779
|
try {
|
|
4790
|
-
const short = await this._interceptor(name, args);
|
|
4780
|
+
const short = await this._interceptor(name, args, dispatchCtx);
|
|
4791
4781
|
if (typeof short === "string") return short;
|
|
4792
4782
|
} catch (err) {
|
|
4793
4783
|
return JSON.stringify({
|
|
@@ -4801,10 +4791,7 @@ var ToolRegistry = class {
|
|
|
4801
4791
|
this._auditListener?.({ name, args });
|
|
4802
4792
|
} catch {
|
|
4803
4793
|
}
|
|
4804
|
-
const result = await tool.fn(args,
|
|
4805
|
-
signal: opts.signal,
|
|
4806
|
-
confirmationGate: opts.confirmationGate
|
|
4807
|
-
});
|
|
4794
|
+
const result = await tool.fn(args, dispatchCtx);
|
|
4808
4795
|
const str = typeof result === "string" ? result : JSON.stringify(result);
|
|
4809
4796
|
let clipped = str;
|
|
4810
4797
|
if (opts.maxResultTokens !== void 0) {
|
|
@@ -6834,6 +6821,8 @@ var CacheFirstLoop = class {
|
|
|
6834
6821
|
const name = call.function?.name ?? "";
|
|
6835
6822
|
const args = call.function?.arguments ?? "{}";
|
|
6836
6823
|
const parsedArgs = safeParseToolArgs(args);
|
|
6824
|
+
const startedAt = Date.now();
|
|
6825
|
+
let interactiveWaitMs = 0;
|
|
6837
6826
|
this._inflight.add(this.inflightIdFor(call));
|
|
6838
6827
|
try {
|
|
6839
6828
|
const preReport = await runHooks({
|
|
@@ -6853,13 +6842,17 @@ var CacheFirstLoop = class {
|
|
|
6853
6842
|
preWarnings,
|
|
6854
6843
|
postWarnings: [],
|
|
6855
6844
|
result: `[hook block] ${blocking?.hook.command ?? "<unknown>"}
|
|
6856
|
-
${reason}
|
|
6845
|
+
${reason}`,
|
|
6846
|
+
elapsedMs: Date.now() - startedAt
|
|
6857
6847
|
};
|
|
6858
6848
|
}
|
|
6859
6849
|
const result = await this.tools.dispatch(name, args, {
|
|
6860
6850
|
signal,
|
|
6861
6851
|
maxResultTokens: DEFAULT_MAX_RESULT_TOKENS,
|
|
6862
|
-
confirmationGate: this.confirmationGate
|
|
6852
|
+
confirmationGate: this.confirmationGate,
|
|
6853
|
+
onInteractiveWait: (elapsedMs) => {
|
|
6854
|
+
interactiveWaitMs += Math.max(0, elapsedMs);
|
|
6855
|
+
}
|
|
6863
6856
|
});
|
|
6864
6857
|
const postReport = await runHooks({
|
|
6865
6858
|
hooks: this.hooks,
|
|
@@ -6872,7 +6865,12 @@ ${reason}`
|
|
|
6872
6865
|
}
|
|
6873
6866
|
});
|
|
6874
6867
|
const postWarnings = [...hookWarnings(postReport.outcomes, this._turn)];
|
|
6875
|
-
return {
|
|
6868
|
+
return {
|
|
6869
|
+
preWarnings,
|
|
6870
|
+
postWarnings,
|
|
6871
|
+
result,
|
|
6872
|
+
elapsedMs: Math.max(0, Date.now() - startedAt - interactiveWaitMs)
|
|
6873
|
+
};
|
|
6876
6874
|
} finally {
|
|
6877
6875
|
this._inflight.delete(this.inflightIdFor(call));
|
|
6878
6876
|
}
|
|
@@ -7357,12 +7355,14 @@ ${reason}`
|
|
|
7357
7355
|
const args = call.function?.arguments ?? "{}";
|
|
7358
7356
|
const s = settled[k];
|
|
7359
7357
|
let result;
|
|
7358
|
+
let elapsedMs = 0;
|
|
7360
7359
|
let preWarnings = [];
|
|
7361
7360
|
let postWarnings = [];
|
|
7362
7361
|
if (s.status === "fulfilled") {
|
|
7363
7362
|
preWarnings = s.value.preWarnings;
|
|
7364
7363
|
postWarnings = s.value.postWarnings;
|
|
7365
7364
|
result = s.value.result;
|
|
7365
|
+
elapsedMs = s.value.elapsedMs;
|
|
7366
7366
|
} else {
|
|
7367
7367
|
const err = s.reason instanceof Error ? s.reason : new Error(String(s.reason));
|
|
7368
7368
|
result = JSON.stringify({ error: `${err.name}: ${err.message}` });
|
|
@@ -7381,7 +7381,8 @@ ${reason}`
|
|
|
7381
7381
|
content: result,
|
|
7382
7382
|
toolName: name,
|
|
7383
7383
|
toolArgs: args,
|
|
7384
|
-
callId: this.inflightIdFor(call)
|
|
7384
|
+
callId: this.inflightIdFor(call),
|
|
7385
|
+
elapsedMs
|
|
7385
7386
|
};
|
|
7386
7387
|
}
|
|
7387
7388
|
}
|
|
@@ -8931,27 +8932,51 @@ async function applyMultiEdit(rootDir, edits) {
|
|
|
8931
8932
|
);
|
|
8932
8933
|
}
|
|
8933
8934
|
const rel = displayRel(rootDir, e.abs);
|
|
8934
|
-
if (e.search.length === 0) {
|
|
8935
|
-
throw new Error(
|
|
8936
|
-
`multi_edit: edit #${i + 1} (${rel}) search cannot be empty (no edits applied)`
|
|
8937
|
-
);
|
|
8938
|
-
}
|
|
8939
8935
|
let state = filesByPath.get(e.abs);
|
|
8940
8936
|
if (!state) {
|
|
8941
8937
|
let before;
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8938
|
+
if (e.search.length === 0) {
|
|
8939
|
+
try {
|
|
8940
|
+
await fs.readFile(e.abs, "utf8");
|
|
8941
|
+
throw new Error("empty SEARCH only creates new files \u2014 this file already exists");
|
|
8942
|
+
} catch (err) {
|
|
8943
|
+
const code = err.code;
|
|
8944
|
+
if (code !== "ENOENT") {
|
|
8945
|
+
throw new Error(
|
|
8946
|
+
`multi_edit: edit #${i + 1} cannot create ${rel}: ${err.message} (no edits applied)`
|
|
8947
|
+
);
|
|
8948
|
+
}
|
|
8949
|
+
}
|
|
8950
|
+
state = { buf: "", le: "\n", hunks: [], deltaChars: 0, touched: 0, created: true };
|
|
8951
|
+
filesByPath.set(e.abs, state);
|
|
8952
|
+
} else {
|
|
8953
|
+
try {
|
|
8954
|
+
before = await fs.readFile(e.abs, "utf8");
|
|
8955
|
+
} catch (err) {
|
|
8956
|
+
throw new Error(
|
|
8957
|
+
`multi_edit: edit #${i + 1} cannot read ${rel}: ${err.message} (no edits applied)`
|
|
8958
|
+
);
|
|
8959
|
+
}
|
|
8960
|
+
const le = before.includes("\r\n") ? "\r\n" : "\n";
|
|
8961
|
+
state = { buf: before, le, hunks: [], deltaChars: 0, touched: 0, created: false };
|
|
8962
|
+
filesByPath.set(e.abs, state);
|
|
8948
8963
|
}
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8964
|
+
}
|
|
8965
|
+
if (e.search.length === 0 && (!state.created || state.touched > 0)) {
|
|
8966
|
+
throw new Error(
|
|
8967
|
+
`multi_edit: edit #${i + 1} (${rel}) empty search only creates new files (no edits applied)`
|
|
8968
|
+
);
|
|
8952
8969
|
}
|
|
8953
8970
|
const adaptedSearch = e.search.replace(/\r?\n/g, state.le);
|
|
8954
8971
|
const adaptedReplace = e.replace.replace(/\r?\n/g, state.le);
|
|
8972
|
+
if (adaptedSearch.length === 0) {
|
|
8973
|
+
state.buf = adaptedReplace;
|
|
8974
|
+
state.hunks.push(`# ${rel}
|
|
8975
|
+
${renderCreateDiff(adaptedReplace)}`);
|
|
8976
|
+
state.deltaChars += adaptedReplace.length;
|
|
8977
|
+
state.touched++;
|
|
8978
|
+
continue;
|
|
8979
|
+
}
|
|
8955
8980
|
const firstIdx = state.buf.indexOf(adaptedSearch);
|
|
8956
8981
|
if (firstIdx < 0) {
|
|
8957
8982
|
throw new Error(
|
|
@@ -8972,6 +8997,7 @@ ${renderEditDiff(adaptedSearch, adaptedReplace, startLine)}`);
|
|
|
8972
8997
|
state.touched++;
|
|
8973
8998
|
}
|
|
8974
8999
|
for (const [abs, state] of filesByPath) {
|
|
9000
|
+
if (state.created) await fs.mkdir(pathMod.dirname(abs), { recursive: true });
|
|
8975
9001
|
await fs.writeFile(abs, state.buf, "utf8");
|
|
8976
9002
|
}
|
|
8977
9003
|
const fileCount = filesByPath.size;
|
|
@@ -8998,6 +9024,13 @@ function renderEditDiff(search, replace, startLine) {
|
|
|
8998
9024
|
return `${hunk}
|
|
8999
9025
|
${body}`;
|
|
9000
9026
|
}
|
|
9027
|
+
function renderCreateDiff(replace) {
|
|
9028
|
+
const lines = replace.length === 0 ? [] : replace.split(/\r?\n/);
|
|
9029
|
+
const hunk = `@@ -1,0 +1,${lines.length} @@`;
|
|
9030
|
+
const body = lines.map((line) => `+ ${line}`).join("\n");
|
|
9031
|
+
return body ? `${hunk}
|
|
9032
|
+
${body}` : hunk;
|
|
9033
|
+
}
|
|
9001
9034
|
function lineDiff(a, b) {
|
|
9002
9035
|
const n = a.length;
|
|
9003
9036
|
const m = b.length;
|
|
@@ -9281,6 +9314,110 @@ function formatOutline(entries) {
|
|
|
9281
9314
|
].join("\n");
|
|
9282
9315
|
}
|
|
9283
9316
|
|
|
9317
|
+
// src/tools/fs/patch.ts
|
|
9318
|
+
function parseUnifiedPatch(patch) {
|
|
9319
|
+
if (typeof patch !== "string" || patch.trim().length === 0) {
|
|
9320
|
+
throw new Error("apply_patch: patch must be a non-empty string");
|
|
9321
|
+
}
|
|
9322
|
+
const lines = patch.split(/\n/);
|
|
9323
|
+
const files = [];
|
|
9324
|
+
let current = null;
|
|
9325
|
+
const ensureCurrent = () => {
|
|
9326
|
+
if (!current) {
|
|
9327
|
+
current = { oldPath: null, newPath: null, blocks: [] };
|
|
9328
|
+
files.push(current);
|
|
9329
|
+
}
|
|
9330
|
+
return current;
|
|
9331
|
+
};
|
|
9332
|
+
let i = 0;
|
|
9333
|
+
while (i < lines.length) {
|
|
9334
|
+
const line = lines[i];
|
|
9335
|
+
if (line.startsWith("diff --git ")) {
|
|
9336
|
+
current = { oldPath: null, newPath: null, blocks: [] };
|
|
9337
|
+
files.push(current);
|
|
9338
|
+
i++;
|
|
9339
|
+
continue;
|
|
9340
|
+
}
|
|
9341
|
+
if (line.startsWith("--- ")) {
|
|
9342
|
+
ensureCurrent().oldPath = parsePatchPath(line.slice(4));
|
|
9343
|
+
i++;
|
|
9344
|
+
continue;
|
|
9345
|
+
}
|
|
9346
|
+
if (line.startsWith("+++ ")) {
|
|
9347
|
+
ensureCurrent().newPath = parsePatchPath(line.slice(4));
|
|
9348
|
+
i++;
|
|
9349
|
+
continue;
|
|
9350
|
+
}
|
|
9351
|
+
if (line.startsWith("@@")) {
|
|
9352
|
+
const file = ensureCurrent();
|
|
9353
|
+
const path2 = file.newPath ?? file.oldPath;
|
|
9354
|
+
if (!path2) throw new Error("apply_patch: hunk is missing a file path");
|
|
9355
|
+
const searchLines = [];
|
|
9356
|
+
const replaceLines = [];
|
|
9357
|
+
i++;
|
|
9358
|
+
while (i < lines.length) {
|
|
9359
|
+
const hunkLine = lines[i];
|
|
9360
|
+
if (hunkLine.startsWith("diff --git ") || hunkLine.startsWith("@@") || hunkLine.startsWith("--- ")) {
|
|
9361
|
+
break;
|
|
9362
|
+
}
|
|
9363
|
+
if (hunkLine === "" && i === lines.length - 1) {
|
|
9364
|
+
break;
|
|
9365
|
+
}
|
|
9366
|
+
if (hunkLine.startsWith("\")) {
|
|
9367
|
+
i++;
|
|
9368
|
+
continue;
|
|
9369
|
+
}
|
|
9370
|
+
const marker = hunkLine[0];
|
|
9371
|
+
const body = hunkLine.slice(1);
|
|
9372
|
+
if (marker === " ") {
|
|
9373
|
+
searchLines.push(body);
|
|
9374
|
+
replaceLines.push(body);
|
|
9375
|
+
} else if (marker === "-") {
|
|
9376
|
+
searchLines.push(body);
|
|
9377
|
+
} else if (marker === "+") {
|
|
9378
|
+
replaceLines.push(body);
|
|
9379
|
+
} else if (hunkLine.trim().length === 0) {
|
|
9380
|
+
} else {
|
|
9381
|
+
throw new Error(`apply_patch: invalid hunk line: ${hunkLine}`);
|
|
9382
|
+
}
|
|
9383
|
+
i++;
|
|
9384
|
+
}
|
|
9385
|
+
file.blocks.push({
|
|
9386
|
+
path: path2,
|
|
9387
|
+
search: file.oldPath === null ? "" : linesToText(searchLines),
|
|
9388
|
+
replace: linesToText(replaceLines),
|
|
9389
|
+
offset: 0
|
|
9390
|
+
});
|
|
9391
|
+
continue;
|
|
9392
|
+
}
|
|
9393
|
+
i++;
|
|
9394
|
+
}
|
|
9395
|
+
const blocks = files.flatMap((file) => file.blocks);
|
|
9396
|
+
if (blocks.length === 0) throw new Error("apply_patch: patch did not contain any hunks");
|
|
9397
|
+
return blocks;
|
|
9398
|
+
}
|
|
9399
|
+
function linesToText(lines) {
|
|
9400
|
+
if (lines.length === 0) return "";
|
|
9401
|
+
return `${lines.join("\n")}
|
|
9402
|
+
`;
|
|
9403
|
+
}
|
|
9404
|
+
function parsePatchPath(raw) {
|
|
9405
|
+
const cleaned = unquotePath(raw.trim().split(/\t/, 1)[0] ?? "");
|
|
9406
|
+
if (cleaned === "/dev/null") return null;
|
|
9407
|
+
const withoutPrefix = cleaned.replace(/^[ab]\//, "");
|
|
9408
|
+
const normalized = withoutPrefix.replace(/^[/\\]+/, "");
|
|
9409
|
+
if (!normalized) throw new Error(`apply_patch: invalid patch path: ${raw}`);
|
|
9410
|
+
return normalized.replaceAll("\\", "/");
|
|
9411
|
+
}
|
|
9412
|
+
function unquotePath(path2) {
|
|
9413
|
+
if (path2.length < 2 || !path2.startsWith('"') || !path2.endsWith('"')) return path2;
|
|
9414
|
+
try {
|
|
9415
|
+
return JSON.parse(path2);
|
|
9416
|
+
} catch {
|
|
9417
|
+
return path2.slice(1, -1);
|
|
9418
|
+
}
|
|
9419
|
+
}
|
|
9420
|
+
|
|
9284
9421
|
// src/tools/fs/search.ts
|
|
9285
9422
|
import { promises as fs3 } from "fs";
|
|
9286
9423
|
import * as pathMod4 from "path";
|
|
@@ -9578,10 +9715,14 @@ ${body}`;
|
|
|
9578
9715
|
let pending = inflightGate.get(allowPrefix);
|
|
9579
9716
|
if (!pending) {
|
|
9580
9717
|
const gate = ctx?.confirmationGate ?? pauseGate;
|
|
9718
|
+
const waitStartedAt = Date.now();
|
|
9581
9719
|
pending = gate.ask({
|
|
9582
9720
|
kind: "path_access",
|
|
9583
9721
|
payload: { path: abs, intent, toolName, sandboxRoot: normRoot, allowPrefix }
|
|
9584
9722
|
});
|
|
9723
|
+
pending = pending.finally(() => {
|
|
9724
|
+
ctx?.onInteractiveWait?.(Date.now() - waitStartedAt);
|
|
9725
|
+
});
|
|
9585
9726
|
inflightGate.set(allowPrefix, pending);
|
|
9586
9727
|
void pending.finally(() => inflightGate.delete(allowPrefix));
|
|
9587
9728
|
}
|
|
@@ -10001,7 +10142,7 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
10001
10142
|
});
|
|
10002
10143
|
registry.register({
|
|
10003
10144
|
name: "multi_edit",
|
|
10004
|
-
description: "Apply N SEARCH/REPLACE edits across ONE OR MORE files in a single atomic call. Edits run sequentially in array order; for edits that touch the same file, a later edit can match text inserted by an earlier one. If ANY edit fails (search not found, ambiguous match,
|
|
10145
|
+
description: "Apply N SEARCH/REPLACE edits across ONE OR MORE files in a single atomic call. Edits run sequentially in array order; for edits that touch the same file, a later edit can match text inserted by an earlier one. If ANY edit fails (search not found, ambiguous match, file unreadable, invalid create), NO files are written \u2014 atomic at the validation layer. Same per-edit rules as edit_file: `search` is exact text (whitespace sensitive, no regex) and must be unique in its target file at the moment that edit applies. To create a new file, use an empty `search`; empty `search` is refused for existing files. Use this for renames spanning multiple files, cross-file refactors, or any batch where you'd otherwise loop edit_file.",
|
|
10005
10146
|
parameters: {
|
|
10006
10147
|
type: "object",
|
|
10007
10148
|
properties: {
|
|
@@ -10038,6 +10179,41 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
10038
10179
|
return applyMultiEdit(rootDir, resolved);
|
|
10039
10180
|
}
|
|
10040
10181
|
});
|
|
10182
|
+
registry.register({
|
|
10183
|
+
name: "apply_patch",
|
|
10184
|
+
description: "Apply a unified git-style patch atomically under the sandbox root. Use this for non-trivial code edits because it lets the UI review the whole patch as one batch. If any hunk fails, no files are written.",
|
|
10185
|
+
parameters: {
|
|
10186
|
+
type: "object",
|
|
10187
|
+
properties: {
|
|
10188
|
+
patch: {
|
|
10189
|
+
type: "string",
|
|
10190
|
+
description: "Unified diff text with diff --git / --- / +++ headers and @@ hunks. Paths should be project-relative or a/ b/-prefixed."
|
|
10191
|
+
}
|
|
10192
|
+
},
|
|
10193
|
+
required: ["patch"]
|
|
10194
|
+
},
|
|
10195
|
+
fn: async (args, ctx) => {
|
|
10196
|
+
try {
|
|
10197
|
+
const blocks = parseUnifiedPatch(args.patch);
|
|
10198
|
+
const resolved = await Promise.all(
|
|
10199
|
+
blocks.map(async (block) => ({
|
|
10200
|
+
abs: await safePath(block.path, "apply_patch", ctx, "write"),
|
|
10201
|
+
search: block.search,
|
|
10202
|
+
replace: block.replace,
|
|
10203
|
+
rel: block.path,
|
|
10204
|
+
created: block.search.length === 0
|
|
10205
|
+
}))
|
|
10206
|
+
);
|
|
10207
|
+
const output = await applyMultiEdit(rootDir, resolved);
|
|
10208
|
+
const fileCount = new Set(resolved.map((edit) => edit.rel)).size;
|
|
10209
|
+
const fileNoun = fileCount === 1 ? "file" : "files";
|
|
10210
|
+
const created = resolved.filter((edit) => edit.created).map((edit) => `created ${edit.rel}`);
|
|
10211
|
+
return [`apply_patch: applied ${fileCount} ${fileNoun}`, ...created, output].join("\n");
|
|
10212
|
+
} catch (err) {
|
|
10213
|
+
return `apply_patch: no files written \u2014 ${err.message}`;
|
|
10214
|
+
}
|
|
10215
|
+
}
|
|
10216
|
+
});
|
|
10041
10217
|
registry.register({
|
|
10042
10218
|
name: "create_directory",
|
|
10043
10219
|
description: "Create a directory (and any missing parents) under the sandbox root.",
|
|
@@ -12269,7 +12445,7 @@ function hasSensitivePathArgs(argv, projectRoot, extraPrefixes = [], extraPatter
|
|
|
12269
12445
|
}
|
|
12270
12446
|
return false;
|
|
12271
12447
|
}
|
|
12272
|
-
function isAllowed(cmd, extra = [], projectRoot, sensitivePathConfig) {
|
|
12448
|
+
function isAllowed(cmd, extra = [], projectRoot, sensitivePathConfig, opts = {}) {
|
|
12273
12449
|
let argv;
|
|
12274
12450
|
try {
|
|
12275
12451
|
argv = tokenizeCommand(cmd);
|
|
@@ -12277,7 +12453,7 @@ function isAllowed(cmd, extra = [], projectRoot, sensitivePathConfig) {
|
|
|
12277
12453
|
return false;
|
|
12278
12454
|
}
|
|
12279
12455
|
if (argv.length === 0) return false;
|
|
12280
|
-
const allowlist = [...BUILTIN_ALLOWLIST, ...extra];
|
|
12456
|
+
const allowlist = [...opts.includeBuiltin === false ? [] : BUILTIN_ALLOWLIST, ...extra];
|
|
12281
12457
|
for (const prefix of allowlist) {
|
|
12282
12458
|
const prefixTokens = prefix.split(" ");
|
|
12283
12459
|
if (argv.length < prefixTokens.length) continue;
|
|
@@ -12302,15 +12478,18 @@ function isAllowed(cmd, extra = [], projectRoot, sensitivePathConfig) {
|
|
|
12302
12478
|
}
|
|
12303
12479
|
return false;
|
|
12304
12480
|
}
|
|
12305
|
-
function isCommandAllowed(cmd, extra = [], projectRoot, sensitivePathConfig) {
|
|
12481
|
+
function isCommandAllowed(cmd, extra = [], projectRoot, sensitivePathConfig, opts = {}) {
|
|
12306
12482
|
let chain;
|
|
12307
12483
|
try {
|
|
12308
12484
|
chain = parseCommandChain(cmd);
|
|
12309
12485
|
} catch {
|
|
12310
12486
|
return false;
|
|
12311
12487
|
}
|
|
12312
|
-
if (chain === null) return isAllowed(cmd, extra, projectRoot, sensitivePathConfig);
|
|
12313
|
-
return chainAllowed(
|
|
12488
|
+
if (chain === null) return isAllowed(cmd, extra, projectRoot, sensitivePathConfig, opts);
|
|
12489
|
+
return chainAllowed(
|
|
12490
|
+
chain,
|
|
12491
|
+
(seg) => isAllowed(seg, extra, projectRoot, sensitivePathConfig, opts)
|
|
12492
|
+
);
|
|
12314
12493
|
}
|
|
12315
12494
|
|
|
12316
12495
|
// src/tools/shell/exec.ts
|
|
@@ -12610,9 +12789,19 @@ function registerShellTools(registry, opts) {
|
|
|
12610
12789
|
return () => snapshot2;
|
|
12611
12790
|
})();
|
|
12612
12791
|
const isAllowAll = typeof opts.allowAll === "function" ? opts.allowAll : () => opts.allowAll === true;
|
|
12792
|
+
const isAutoAllowed = (cmd) => isCommandAllowed(cmd, getExtraAllowed(), rootDir, opts.sensitivePaths, {
|
|
12793
|
+
includeBuiltin: opts.requireApprovalForBuiltin !== true
|
|
12794
|
+
});
|
|
12795
|
+
const approvalPolicy = opts.requireApprovalForBuiltin ? "Model-requested shell commands ask the user before they run unless the user has explicitly always-allowed a project prefix or yolo mode is active. Prefer this over asking the user to run a command manually \u2014 after edits, run the project's tests to verify." : "Allowlisted read-only / test / lint / typecheck commands run immediately; anything that could mutate state, install deps, or touch the network is gated by user confirmation. Prefer this over asking the user to run a command manually \u2014 after edits, run the project's tests to verify.";
|
|
12613
12796
|
registry.register({
|
|
12614
12797
|
name: "run_command",
|
|
12615
|
-
description:
|
|
12798
|
+
description: `Run a shell command in the project root; returns combined stdout+stderr. ${approvalPolicy}
|
|
12799
|
+
|
|
12800
|
+
Constraints (no real shell \u2014 argv is parsed natively for cross-platform parity):
|
|
12801
|
+
\u2022 Supported: chain ops \`|\` / \`||\` / \`&&\` / \`;\` (each segment allowlist-checked individually), file redirects \`>\` / \`>>\` / \`<\` / \`2>\` / \`2>>\` / \`2>&1\` / \`&>\` (target paths resolve relative to project root, max one redirect per fd per segment).
|
|
12802
|
+
\u2022 NOT supported: background \`&\`, heredoc \`<<\`, command substitution \`$(\u2026)\`, subshells \`(\u2026)\`, process substitution \`<(\u2026)\`, \`$VAR\` env expansion, glob expansion. To pass an operator char as literal arg, quote it (\`grep "a|b" file\`).
|
|
12803
|
+
\u2022 \`cd\` does NOT persist \u2014 between calls OR within a chain like \`cd dir && cmd\`. Use the binary's own cwd flag: \`npm --prefix <dir>\`, \`git -C <dir>\`, \`cargo -C <dir>\`, \`pytest <dir>/tests\`.
|
|
12804
|
+
\u2022 Filter at source \u2014 unbounded output (\`netstat -ano\`, \`find /\`) wastes tokens. Use \`grep -c\`, \`wc -l\`, narrower paths, etc.`,
|
|
12616
12805
|
// Plan-mode gate: allow allowlisted commands through (git status,
|
|
12617
12806
|
// cargo check, ls, grep …) so the model can actually investigate
|
|
12618
12807
|
// during planning. Anything that would otherwise trigger a
|
|
@@ -12641,12 +12830,14 @@ function registerShellTools(registry, opts) {
|
|
|
12641
12830
|
const cmd = args.command.trim();
|
|
12642
12831
|
if (!cmd) throw new Error("run_command: empty command");
|
|
12643
12832
|
const effectiveTimeout = Math.max(1, Math.min(600, args.timeoutSec ?? timeoutSec));
|
|
12644
|
-
if (!isAllowAll() && !
|
|
12833
|
+
if (!isAllowAll() && !isAutoAllowed(cmd)) {
|
|
12645
12834
|
const gate = ctx?.confirmationGate ?? pauseGate;
|
|
12835
|
+
const waitStartedAt = Date.now();
|
|
12646
12836
|
const choice = await gate.ask({
|
|
12647
12837
|
kind: "run_command",
|
|
12648
12838
|
payload: { command: cmd, cwd: rootDir, timeoutSec: effectiveTimeout }
|
|
12649
12839
|
});
|
|
12840
|
+
ctx?.onInteractiveWait?.(Date.now() - waitStartedAt);
|
|
12650
12841
|
if (choice.type === "deny") {
|
|
12651
12842
|
throw new Error(
|
|
12652
12843
|
`user denied: ${cmd}${choice.denyContext ? ` \u2014 ${choice.denyContext}` : ""}`
|
|
@@ -12690,12 +12881,14 @@ function registerShellTools(registry, opts) {
|
|
|
12690
12881
|
const cmd = args.command.trim();
|
|
12691
12882
|
if (!cmd) throw new Error("run_background: empty command");
|
|
12692
12883
|
const cwd = resolveCwdInsideRoot(rootDir, args.cwd);
|
|
12693
|
-
if (!isAllowAll() && !
|
|
12884
|
+
if (!isAllowAll() && !isAutoAllowed(cmd)) {
|
|
12694
12885
|
const gate = ctx?.confirmationGate ?? pauseGate;
|
|
12886
|
+
const waitStartedAt = Date.now();
|
|
12695
12887
|
const choice = await gate.ask({
|
|
12696
12888
|
kind: "run_background",
|
|
12697
12889
|
payload: { command: cmd, cwd, waitSec: args.waitSec }
|
|
12698
12890
|
});
|
|
12891
|
+
ctx?.onInteractiveWait?.(Date.now() - waitStartedAt);
|
|
12699
12892
|
if (choice.type === "deny") {
|
|
12700
12893
|
throw new Error(
|
|
12701
12894
|
`user denied: ${cmd}${choice.denyContext ? ` \u2014 ${choice.denyContext}` : ""}`
|
|
@@ -13766,14 +13959,14 @@ function truncate(s, n) {
|
|
|
13766
13959
|
// src/version.ts
|
|
13767
13960
|
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
|
|
13768
13961
|
import { homedir as homedir7 } from "os";
|
|
13769
|
-
import { dirname as
|
|
13962
|
+
import { dirname as dirname8, join as join14 } from "path";
|
|
13770
13963
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13771
13964
|
var REGISTRY_URL = "https://registry.npmjs.org/@carboncode/cli/latest";
|
|
13772
13965
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
13773
13966
|
var LATEST_FETCH_TIMEOUT_MS = 2e3;
|
|
13774
13967
|
function readPackageVersion() {
|
|
13775
13968
|
try {
|
|
13776
|
-
let dir =
|
|
13969
|
+
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
13777
13970
|
for (let i = 0; i < 6; i++) {
|
|
13778
13971
|
const p = join14(dir, "package.json");
|
|
13779
13972
|
if (existsSync10(p)) {
|
|
@@ -13782,7 +13975,7 @@ function readPackageVersion() {
|
|
|
13782
13975
|
return pkg.version;
|
|
13783
13976
|
}
|
|
13784
13977
|
}
|
|
13785
|
-
const parent =
|
|
13978
|
+
const parent = dirname8(dir);
|
|
13786
13979
|
if (parent === dir) break;
|
|
13787
13980
|
dir = parent;
|
|
13788
13981
|
}
|
|
@@ -13808,7 +14001,7 @@ function readCache(homeDirOverride) {
|
|
|
13808
14001
|
function writeCache(entry, homeDirOverride) {
|
|
13809
14002
|
try {
|
|
13810
14003
|
const p = cachePath(homeDirOverride);
|
|
13811
|
-
mkdirSync5(
|
|
14004
|
+
mkdirSync5(dirname8(p), { recursive: true });
|
|
13812
14005
|
writeFileSync5(p, JSON.stringify(entry), "utf8");
|
|
13813
14006
|
} catch {
|
|
13814
14007
|
}
|
|
@@ -14578,7 +14771,7 @@ import {
|
|
|
14578
14771
|
writeFileSync as writeFileSync6,
|
|
14579
14772
|
writeSync
|
|
14580
14773
|
} from "fs";
|
|
14581
|
-
import { dirname as
|
|
14774
|
+
import { dirname as dirname9, resolve as resolve12 } from "path";
|
|
14582
14775
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
14583
14776
|
function parseEditBlocks(text) {
|
|
14584
14777
|
const out = [];
|
|
@@ -14608,7 +14801,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
14608
14801
|
const searchEmpty = block.search.length === 0;
|
|
14609
14802
|
if (searchEmpty) {
|
|
14610
14803
|
try {
|
|
14611
|
-
mkdirSync6(
|
|
14804
|
+
mkdirSync6(dirname9(absTarget), { recursive: true });
|
|
14612
14805
|
const fd = openSync2(absTarget, "wx");
|
|
14613
14806
|
try {
|
|
14614
14807
|
writeSync(fd, block.replace);
|
|
@@ -14748,7 +14941,7 @@ var DEFAULT_CODE_MODEL = "deepseek-v4-flash";
|
|
|
14748
14941
|
function codeSystemBase(modelId) {
|
|
14749
14942
|
return CODE_SYSTEM_TEMPLATE.replace("__ESCALATION_CONTRACT__", escalationContract(modelId));
|
|
14750
14943
|
}
|
|
14751
|
-
var CODE_SYSTEM_TEMPLATE = `You are Carbon Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, multi_edit, list_directory, directory_tree, search_files, search_content, glob, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell, plus \`todo_write\` for in-session multi-step tracking.
|
|
14944
|
+
var CODE_SYSTEM_TEMPLATE = `You are Carbon Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, multi_edit, apply_patch, list_directory, directory_tree, search_files, search_content, glob, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell, plus \`todo_write\` for in-session multi-step tracking.
|
|
14752
14945
|
|
|
14753
14946
|
# Identity is fixed by this prompt \u2014 never inferred from the workspace
|
|
14754
14947
|
|
|
@@ -14831,8 +15024,8 @@ Call shape: \`{ todos: [{ content, activeForm, status }, ...] }\` \u2014 \`conte
|
|
|
14831
15024
|
# Plan mode (/plan)
|
|
14832
15025
|
|
|
14833
15026
|
The user can ALSO enter "plan mode" via /plan, which is a stronger, explicit constraint:
|
|
14834
|
-
- Write tools (edit_file, multi_edit, write_file, create_directory, move_file, copy_file, delete_file, delete_directory) and non-allowlisted run_command calls are BOUNCED at dispatch \u2014 you'll get a tool result like "unavailable in plan mode". Don't retry them.
|
|
14835
|
-
- Read tools (read_file, list_directory, search_files, directory_tree, get_file_info) and allowlisted read-only / test shell commands still work \u2014 use them to investigate.
|
|
15027
|
+
- Write tools (edit_file, multi_edit, apply_patch, write_file, create_directory, move_file, copy_file, delete_file, delete_directory) and non-allowlisted run_command calls are BOUNCED at dispatch \u2014 you'll get a tool result like "unavailable in plan mode". Don't retry them.
|
|
15028
|
+
- Read tools (read_file, list_directory, search_files, directory_tree, get_file_info) and allowlisted read-only / test shell commands still work after user approval \u2014 use them to investigate.
|
|
14836
15029
|
- You MUST call submit_plan before anything will execute. Approve exits plan mode; Refine stays in; Cancel exits without implementing.
|
|
14837
15030
|
|
|
14838
15031
|
|
|
@@ -14874,8 +15067,8 @@ When you do propose edits, the user will review them and decide whether to \`/ap
|
|
|
14874
15067
|
|
|
14875
15068
|
Carbon Code runs an **edit gate**. The user's current mode (\`review\` or \`auto\`) decides what happens to your writes; you DO NOT see which mode is active, and you SHOULD NOT ask. Write the same way in both cases.
|
|
14876
15069
|
|
|
14877
|
-
- In \`auto\` mode \`edit_file\` / \`write_file\` calls land on disk immediately with an undo window \u2014 you'll get the normal
|
|
14878
|
-
- In \`review\` mode EACH \`edit_file\` / \`write_file\` call pauses tool dispatch while the user decides. You'll get one of these responses:
|
|
15070
|
+
- In \`auto\` mode \`edit_file\` / \`write_file\` / \`multi_edit\` / \`apply_patch\` calls land on disk immediately with an undo window \u2014 you'll get the normal applied-edit response.
|
|
15071
|
+
- In \`review\` mode EACH \`edit_file\` / \`write_file\` / \`multi_edit\` / \`apply_patch\` call pauses tool dispatch while the user decides. You'll get one of these responses:
|
|
14879
15072
|
- \`"edit blocks: 1/1 applied"\` \u2014 user approved it. Continue as normal.
|
|
14880
15073
|
- \`"User rejected this edit to <path>. Don't retry the same SEARCH/REPLACE\u2026"\` \u2014 user said no to THIS specific edit. Do NOT re-emit the same block, do NOT switch tools to sneak it past the gate (write_file \u2192 edit_file, or text-form SEARCH/REPLACE). Either take a clearly different approach or stop and ask the user what they want instead.
|
|
14881
15074
|
- Text-form SEARCH/REPLACE blocks in your assistant reply queue for end-of-turn /apply \u2014 same "don't retry on rejection" rule.
|
|
@@ -14883,7 +15076,20 @@ Carbon Code runs an **edit gate**. The user's current mode (\`review\` or \`auto
|
|
|
14883
15076
|
|
|
14884
15077
|
# Editing files
|
|
14885
15078
|
|
|
14886
|
-
|
|
15079
|
+
Default loop: inspect, patch, verify, summarize. After tests pass, summarize briefly and cite the files or commands that matter.
|
|
15080
|
+
|
|
15081
|
+
When you've been asked to change a file, prefer \`apply_patch\` for non-trivial edits. It accepts a unified git-style patch and lets the user review the whole batch at once:
|
|
15082
|
+
|
|
15083
|
+
\`\`\`diff
|
|
15084
|
+
diff --git a/path/to/file.ext b/path/to/file.ext
|
|
15085
|
+
--- a/path/to/file.ext
|
|
15086
|
+
+++ b/path/to/file.ext
|
|
15087
|
+
@@ -1 +1 @@
|
|
15088
|
+
-old line
|
|
15089
|
+
+new line
|
|
15090
|
+
\`\`\`
|
|
15091
|
+
|
|
15092
|
+
For tiny exact replacements, \`edit_file\` is fine. For generated programmatic batches, \`multi_edit\` is also fine. If you are writing text-form edits in your final answer instead of calling tools, output one or more SEARCH/REPLACE blocks in this exact format:
|
|
14887
15093
|
|
|
14888
15094
|
path/to/file.ext
|
|
14889
15095
|
<<<<<<< SEARCH
|
|
@@ -14903,7 +15109,7 @@ Rules:
|
|
|
14903
15109
|
>>>>>>> REPLACE
|
|
14904
15110
|
- Do NOT use write_file to change existing files \u2014 the user reviews your edits as SEARCH/REPLACE. write_file is only for files you explicitly want to overwrite wholesale (rare).
|
|
14905
15111
|
- Paths are relative to the working directory. Don't use absolute paths.
|
|
14906
|
-
- For multi-site changes \u2014 same file or across files \u2014 prefer \`multi_edit\` over N \`edit_file\` calls.
|
|
15112
|
+
- For multi-site changes \u2014 same file or across files \u2014 prefer \`apply_patch\` or \`multi_edit\` over N \`edit_file\` calls. \`multi_edit\` shape: \`{ edits: [{ path, search, replace }, ...] }\`. Both batch tools validate before any file is written; any failure \u2192 ALL files untouched. Per-file edits run in array order, so a later edit can match text inserted by an earlier one. To create a new file inside a \`multi_edit\`, use an empty \`search\` for that file.
|
|
14907
15113
|
|
|
14908
15114
|
# Trust what you already know
|
|
14909
15115
|
|
|
@@ -14912,7 +15118,7 @@ Before exploring the filesystem to answer a factual question, check whether the
|
|
|
14912
15118
|
# Exploration
|
|
14913
15119
|
|
|
14914
15120
|
- Skip dependency, build, and VCS directories unless the user explicitly asks. The pinned .gitignore block (if any, below) is your authoritative denylist.
|
|
14915
|
-
- Prefer \`search_files\` over \`list_directory\` when you know roughly what you're looking for \u2014 it saves context and avoids enumerating huge trees. Note: \`search_files\` matches file NAMES; for searching file CONTENTS use \`search_content\`.
|
|
15121
|
+
- Prefer \`search_files\` over \`list_directory\` when you know roughly what you're looking for \u2014 it saves context and avoids enumerating huge trees. Use \`search_files\` for a filename query. Use \`glob\` for wildcard file patterns. Note: \`search_files\` matches file NAMES; for searching file CONTENTS use \`search_content\`.
|
|
14916
15122
|
- Available exploration tools: \`read_file\`, \`list_directory\`, \`directory_tree\`, \`search_files\` (filename match), \`glob\` (mtime-sorted glob \u2014 use for "what changed lately", "all *.ts under src/"), \`search_content\` (content grep \u2014 use for "where is X called", "find all references to Y"; pass \`context:N\` for grep -C N around hits), \`get_file_info\`. Don't call \`grep\` or other tools that aren't in this list \u2014 they don't exist as functions.
|
|
14917
15123
|
|
|
14918
15124
|
# Path conventions
|
|
@@ -14939,6 +15145,10 @@ You have TWO tools for running shell commands, and picking the right one is non-
|
|
|
14939
15145
|
|
|
14940
15146
|
**Never use run_command for a dev server or a download likely to exceed a minute.** It will block, time out, and the user will see a frozen tool call while the work was actually running fine. Always \`run_background\` + \`wait_for_job\` / \`job_output\`.
|
|
14941
15147
|
|
|
15148
|
+
# Explicit command order
|
|
15149
|
+
|
|
15150
|
+
If the user explicitly asks you to run a command first (for example "\u5148\u8FD0\u884C\u6D4B\u8BD5", "run tests first", or "\u5148\u770B npm test \u5931\u8D25"), do that command before reading files or proposing edits. Do not substitute file reading, test-file inspection, or inference for the requested command execution. If the command is denied, say so and continue only within the user's constraint.
|
|
15151
|
+
|
|
14942
15152
|
After \`run_background\`, tools available to you:
|
|
14943
15153
|
- \`job_output(jobId, tailLines?)\` \u2014 read recent logs to verify startup / debug errors.
|
|
14944
15154
|
- \`wait_for_job(jobId, timeoutMs?, waitFor?)\` \u2014 block server-side until the job finishes (or, with \`waitFor: 'output-or-exit'\`, until it writes a new line). ONE tool call per wait regardless of duration. \`timeoutMs\` clamps at 300_000. For downloads / installs / builds: leave \`waitFor\` at the default \`'exit'\` and set \`timeoutMs\` to the slowest reasonable end-to-end. For tailing a dev server and reacting to a specific log line: pass \`waitFor: 'output-or-exit'\` with a short \`timeoutMs\`.
|
|
@@ -15041,7 +15251,7 @@ import {
|
|
|
15041
15251
|
writeFileSync as writeFileSync7
|
|
15042
15252
|
} from "fs";
|
|
15043
15253
|
import { homedir as homedir8 } from "os";
|
|
15044
|
-
import { dirname as
|
|
15254
|
+
import { dirname as dirname10, join as join16 } from "path";
|
|
15045
15255
|
function defaultUsageLogPath(homeDirOverride) {
|
|
15046
15256
|
return join16(homeDirOverride ?? homedir8(), ".carboncode", "usage.jsonl");
|
|
15047
15257
|
}
|
|
@@ -15108,7 +15318,7 @@ function appendUsage(input) {
|
|
|
15108
15318
|
if (input.subagent) record.subagent = input.subagent;
|
|
15109
15319
|
const path2 = input.path ?? defaultUsageLogPath();
|
|
15110
15320
|
try {
|
|
15111
|
-
mkdirSync7(
|
|
15321
|
+
mkdirSync7(dirname10(path2), { recursive: true });
|
|
15112
15322
|
appendFileSync2(path2, `${JSON.stringify(record)}
|
|
15113
15323
|
`, "utf8");
|
|
15114
15324
|
compactUsageLogIfLarge(path2, record.ts);
|