@giovannijecha/jecode 0.6.0 → 0.7.1
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 +242 -256
- package/dist/batch.js +5 -1
- package/dist/commands.js +38 -10
- package/dist/config.js +46 -21
- package/dist/context/compactor.js +3 -1
- package/dist/context/manual.js +69 -0
- package/dist/credential-safety.js +9 -5
- package/dist/providers/anthropic-wire.js +5 -4
- package/dist/providers/ollama-wire.js +3 -2
- package/dist/providers/openai-wire.js +6 -5
- package/dist/providers/wire-usage.js +6 -0
- package/dist/settings-command.js +1 -1
- package/dist/timeline.js +90 -0
- package/dist/tui/app-state.js +1 -0
- package/dist/tui/app-workflows.js +30 -4
- package/dist/tui/app.js +68 -39
- package/dist/tui/components/misc.js +4 -2
- package/dist/tui/picker.js +2 -2
- package/dist/ui/terminal-text.js +4 -1
- package/package.json +1 -1
package/dist/tui/app.js
CHANGED
|
@@ -32,6 +32,7 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
32
32
|
const workspace = await workspaceLabel(session.config.root);
|
|
33
33
|
const state = appState();
|
|
34
34
|
state.blocks.push(...session.conversation.transcript);
|
|
35
|
+
state.committedNodeId = session.conversation.activeNodeId;
|
|
35
36
|
const permissions = sessionPermissions(session.tools, session.config.autoApprove);
|
|
36
37
|
let closed;
|
|
37
38
|
let frameTimer;
|
|
@@ -39,12 +40,21 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
39
40
|
let escapeTimer;
|
|
40
41
|
let stopResize = () => { };
|
|
41
42
|
let stopInput = () => { };
|
|
43
|
+
let failure;
|
|
42
44
|
// Timers outlive the teardown they were scheduled before. Painting after the
|
|
43
45
|
// terminal has been handed back would write escapes into the user's shell.
|
|
44
46
|
let live = true;
|
|
45
47
|
const done = new Promise((resolve) => {
|
|
46
48
|
closed = resolve;
|
|
47
49
|
});
|
|
50
|
+
const guard = (action) => {
|
|
51
|
+
try {
|
|
52
|
+
action();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
fail(error);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
48
58
|
const view = () => {
|
|
49
59
|
const now = Date.now();
|
|
50
60
|
return {
|
|
@@ -93,8 +103,9 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
93
103
|
const render = (block) => {
|
|
94
104
|
if (block !== undefined)
|
|
95
105
|
transcript.invalidate(block);
|
|
96
|
-
if (live && frameTimer === undefined)
|
|
97
|
-
frameTimer = setTimeout(draw, FRAME_MS);
|
|
106
|
+
if (live && frameTimer === undefined) {
|
|
107
|
+
frameTimer = setTimeout(() => guard(draw), FRAME_MS);
|
|
108
|
+
}
|
|
98
109
|
};
|
|
99
110
|
const feedback = feedbackController((next) => {
|
|
100
111
|
state.feedback = next;
|
|
@@ -116,6 +127,16 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
116
127
|
if (state.follow)
|
|
117
128
|
state.unseen = 0;
|
|
118
129
|
};
|
|
130
|
+
const replaceTranscript = () => {
|
|
131
|
+
state.blocks.splice(0, state.blocks.length, ...session.conversation.transcript);
|
|
132
|
+
state.scroll = 0;
|
|
133
|
+
state.follow = true;
|
|
134
|
+
state.unseen = 0;
|
|
135
|
+
state.lastMaxScroll = 0;
|
|
136
|
+
transcript.invalidate();
|
|
137
|
+
paint.invalidate();
|
|
138
|
+
render();
|
|
139
|
+
};
|
|
119
140
|
function quit() {
|
|
120
141
|
if (!live)
|
|
121
142
|
return;
|
|
@@ -132,6 +153,10 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
132
153
|
terminal.leave();
|
|
133
154
|
closed?.();
|
|
134
155
|
}
|
|
156
|
+
function fail(error) {
|
|
157
|
+
failure ??= { error };
|
|
158
|
+
quit();
|
|
159
|
+
}
|
|
135
160
|
function requestQuit() {
|
|
136
161
|
const activity = state.activity;
|
|
137
162
|
if (activity === undefined) {
|
|
@@ -148,7 +173,7 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
148
173
|
const activity = begin(kind, label);
|
|
149
174
|
state.activity = activity;
|
|
150
175
|
state.status = label;
|
|
151
|
-
spinTimer = setInterval(() => {
|
|
176
|
+
spinTimer = setInterval(() => guard(() => {
|
|
152
177
|
if (!session.config.reducedMotion)
|
|
153
178
|
state.spin++;
|
|
154
179
|
let activeTool;
|
|
@@ -160,7 +185,7 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
160
185
|
break;
|
|
161
186
|
}
|
|
162
187
|
render(activeTool);
|
|
163
|
-
}, session.config.reducedMotion ? 1_000 : SPIN_MS);
|
|
188
|
+
}), session.config.reducedMotion ? 1_000 : SPIN_MS);
|
|
164
189
|
render();
|
|
165
190
|
return activity;
|
|
166
191
|
}
|
|
@@ -187,6 +212,7 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
187
212
|
emit,
|
|
188
213
|
commandNotice,
|
|
189
214
|
render,
|
|
215
|
+
replaceTranscript,
|
|
190
216
|
refreshSettings: () => {
|
|
191
217
|
terminal.setReducedMotion(session.config.reducedMotion);
|
|
192
218
|
paint.invalidate();
|
|
@@ -229,14 +255,9 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
229
255
|
return;
|
|
230
256
|
try {
|
|
231
257
|
await launch.open(candidate.id);
|
|
232
|
-
|
|
258
|
+
replaceTranscript();
|
|
259
|
+
state.committedNodeId = session.conversation.activeNodeId;
|
|
233
260
|
state.past.length = 0;
|
|
234
|
-
state.scroll = 0;
|
|
235
|
-
state.follow = true;
|
|
236
|
-
state.unseen = 0;
|
|
237
|
-
state.lastMaxScroll = 0;
|
|
238
|
-
transcript.invalidate();
|
|
239
|
-
paint.invalidate();
|
|
240
261
|
finishActivity(activity);
|
|
241
262
|
return;
|
|
242
263
|
}
|
|
@@ -246,39 +267,47 @@ export async function runApp(session, transcriptRoot, environment = {}) {
|
|
|
246
267
|
}
|
|
247
268
|
}
|
|
248
269
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return;
|
|
264
|
-
escapeTimer = setTimeout(() => {
|
|
265
|
-
escapeTimer = undefined;
|
|
270
|
+
try {
|
|
271
|
+
terminal.enter(session.config.reducedMotion);
|
|
272
|
+
stopResize = terminal.onResize(() => guard(() => {
|
|
273
|
+
paint.invalidate();
|
|
274
|
+
draw();
|
|
275
|
+
}));
|
|
276
|
+
stopInput = terminal.onInput((chunk) => guard(() => {
|
|
277
|
+
if (escapeTimer !== undefined)
|
|
278
|
+
clearTimeout(escapeTimer);
|
|
279
|
+
for (const key of keys.push(chunk)) {
|
|
280
|
+
if (!live)
|
|
281
|
+
break;
|
|
282
|
+
input.handle(key);
|
|
283
|
+
}
|
|
266
284
|
if (!live)
|
|
267
285
|
return;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
286
|
+
escapeTimer = setTimeout(() => guard(() => {
|
|
287
|
+
escapeTimer = undefined;
|
|
288
|
+
if (!live)
|
|
289
|
+
return;
|
|
290
|
+
for (const key of keys.flush())
|
|
291
|
+
input.handle(key);
|
|
292
|
+
if (live)
|
|
293
|
+
render();
|
|
294
|
+
}), ESCAPE_MS);
|
|
295
|
+
render();
|
|
296
|
+
}));
|
|
297
|
+
draw();
|
|
298
|
+
if (resumeAtLaunch !== undefined)
|
|
299
|
+
await Promise.race([resumeAtLaunch, done]);
|
|
278
300
|
if (live)
|
|
279
301
|
await done;
|
|
302
|
+
if (failure !== undefined)
|
|
303
|
+
throw failure.error;
|
|
280
304
|
}
|
|
281
305
|
finally {
|
|
282
|
-
|
|
306
|
+
try {
|
|
307
|
+
quit();
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
await session.persistence?.close();
|
|
311
|
+
}
|
|
283
312
|
}
|
|
284
313
|
}
|
|
@@ -5,11 +5,13 @@ export function renderNotice(block, width, pal) {
|
|
|
5
5
|
warn: pal.ink.attention,
|
|
6
6
|
error: pal.ink.removed,
|
|
7
7
|
};
|
|
8
|
-
const mark = block.tone === "error" ? "× " : block.tone === "warn" ? "! " :
|
|
8
|
+
const mark = block.tone === "error" ? "× " : block.tone === "warn" ? "! " : undefined;
|
|
9
9
|
return [
|
|
10
10
|
"",
|
|
11
11
|
...wrap(block.text, Math.max(1, width - 3)).map((line, index) => row(width, [
|
|
12
|
-
|
|
12
|
+
...(mark === undefined
|
|
13
|
+
? []
|
|
14
|
+
: [{ text: index === 0 ? mark : " ", fg: fg[block.tone], bold: index === 0 }]),
|
|
13
15
|
{ text: line, fg: fg[block.tone] },
|
|
14
16
|
], [], undefined, 1)),
|
|
15
17
|
];
|
package/dist/tui/picker.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// One interaction model for every terminal selector.
|
|
2
2
|
import { row } from "../ui/render.js";
|
|
3
|
-
import { elide } from "../ui/width.js";
|
|
3
|
+
import { elide, graphemes } from "../ui/width.js";
|
|
4
4
|
import { menuWindow, renderMenuRows } from "./components/menu.js";
|
|
5
5
|
import { promptCursor, promptLine } from "./components/prompt.js";
|
|
6
6
|
const WINDOW = 6;
|
|
@@ -33,7 +33,7 @@ export function type(picker, text) {
|
|
|
33
33
|
export function backspace(picker) {
|
|
34
34
|
if (picker.searchable !== true || (picker.query ?? "") === "")
|
|
35
35
|
return picker;
|
|
36
|
-
return withQuery(picker,
|
|
36
|
+
return withQuery(picker, graphemes(picker.query ?? "").slice(0, -1).join(""));
|
|
37
37
|
}
|
|
38
38
|
export function clear(picker) {
|
|
39
39
|
return withQuery(picker, "");
|
package/dist/ui/terminal-text.js
CHANGED
|
@@ -38,5 +38,8 @@ export function terminalText(text, options = {}) {
|
|
|
38
38
|
return safe;
|
|
39
39
|
}
|
|
40
40
|
function isBidiControl(code) {
|
|
41
|
-
return
|
|
41
|
+
return code === 0x061c ||
|
|
42
|
+
(code >= 0x200e && code <= 0x200f) ||
|
|
43
|
+
(code >= 0x202a && code <= 0x202e) ||
|
|
44
|
+
(code >= 0x2066 && code <= 0x2069);
|
|
42
45
|
}
|