jaitus 0.3.12 → 0.3.14
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/bin/jaitus.js +86 -73
- package/package.json +2 -2
- package/src/agent/loop.js +998 -980
- package/src/agent/tools.js +11 -5
- package/src/api.js +55 -21
- package/src/commands/update.js +75 -49
- package/src/errors.js +120 -106
- package/src/index.js +3152 -3142
- package/src/rewind.js +149 -148
- package/src/serviceNotice.js +151 -0
- package/src/sessions.js +8 -0
- package/src/tui/clipboard.js +172 -161
- package/src/tui-ink.js +2841 -2605
- package/src/tui.js +2560 -2559
package/bin/jaitus.js
CHANGED
|
@@ -1,73 +1,86 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The app is imported only after an unfinished update has completed: importing it
|
|
3
|
-
// statically would load a half-installed copy and crash before any check could run.
|
|
4
|
-
// Node 20 is the floor — checked FIRST: loading the app on an older Node crashed in its
|
|
5
|
-
// dependencies before this friendly message could print.
|
|
6
|
-
if (Number(process.versions.node.split('.')[0]) < 20) {
|
|
7
|
-
process.stderr.write(`jaitus needs Node 20 or newer (you have ${process.versions.node}).
|
|
8
|
-
`);
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
import { waitForPendingUpdate } from '../src/pendingUpdate.js';
|
|
13
|
-
|
|
14
|
-
await waitForPendingUpdate().catch(() => false);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
36
|
-
process.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
process
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The app is imported only after an unfinished update has completed: importing it
|
|
3
|
+
// statically would load a half-installed copy and crash before any check could run.
|
|
4
|
+
// Node 20 is the floor — checked FIRST: loading the app on an older Node crashed in its
|
|
5
|
+
// dependencies before this friendly message could print.
|
|
6
|
+
if (Number(process.versions.node.split('.')[0]) < 20) {
|
|
7
|
+
process.stderr.write(`jaitus needs Node 20 or newer (you have ${process.versions.node}).
|
|
8
|
+
`);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
import { waitForPendingUpdate } from '../src/pendingUpdate.js';
|
|
13
|
+
|
|
14
|
+
await waitForPendingUpdate().catch(() => false);
|
|
15
|
+
// React picks its build from NODE_ENV the moment it is first loaded, and the app is
|
|
16
|
+
// loaded right here. Unset (or a developer's own NODE_ENV=development), it picked the
|
|
17
|
+
// DEVELOPMENT build, which records a performance.measure() for every component of
|
|
18
|
+
// every frame — and Node keeps every one of them. At the spinner's frame rate that is
|
|
19
|
+
// thousands a minute: a long session grew past 4 GB and died in "JavaScript heap out
|
|
20
|
+
// of memory", getting slower the whole way (each step cost ~5× the CPU, then GC
|
|
21
|
+
// thrash). So the app always loads production React, and the user's own NODE_ENV is
|
|
22
|
+
// put back straight after: every command the agent runs inherits this environment,
|
|
23
|
+
// and NODE_ENV=production would make `npm install` skip devDependencies.
|
|
24
|
+
const userNodeEnv = process.env.NODE_ENV;
|
|
25
|
+
process.env.NODE_ENV = 'production';
|
|
26
|
+
const { default: main } = await import('../src/index.js');
|
|
27
|
+
if (userNodeEnv === undefined) delete process.env.NODE_ENV;
|
|
28
|
+
else process.env.NODE_ENV = userNodeEnv;
|
|
29
|
+
|
|
30
|
+
// Node 20 is the floor: the CLI uses global fetch, and on 18 it exists but streaming
|
|
31
|
+
// bodies behave differently enough to matter. Better a clear message than a confusing
|
|
32
|
+
// failure halfway through a task.
|
|
33
|
+
const major = Number(process.versions.node.split('.')[0]);
|
|
34
|
+
if (major < 20) {
|
|
35
|
+
process.stderr.write(`jaitus needs Node 20 or newer (you have ${process.versions.node}).\n`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Ctrl-C should leave the terminal usable rather than mid-escape-sequence. Mouse
|
|
40
|
+
// reporting has to be turned off here too: the terminal keeps sending reports after the
|
|
41
|
+
// process is gone, and every click in the shell afterwards prints escape codes.
|
|
42
|
+
const restoreTerminal = () => {
|
|
43
|
+
// Only to a real terminal. Written unconditionally, these codes end up in the output
|
|
44
|
+
// of every piped invocation — `jaitus models --json | jq` would be handed a JSON
|
|
45
|
+
// document with escape sequences glued to the end of it.
|
|
46
|
+
if (!process.stdout.isTTY) return;
|
|
47
|
+
try { process.stdout.write('\x1b[?1006l\x1b[?1002l\x1b[?1000l\x1b[?25h'); } catch { /* going away anyway */ }
|
|
48
|
+
};
|
|
49
|
+
process.on('SIGINT', () => {
|
|
50
|
+
restoreTerminal();
|
|
51
|
+
process.stdout.write('\n');
|
|
52
|
+
process.exit(130);
|
|
53
|
+
});
|
|
54
|
+
process.on('exit', restoreTerminal);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Finish WITHOUT process.exit().
|
|
58
|
+
*
|
|
59
|
+
* Calling process.exit() after two fetches have shared a keep-alive connection crashes
|
|
60
|
+
* Node on Windows with `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)` — a
|
|
61
|
+
* libuv teardown race, not something this code does wrong, but it would print a crash
|
|
62
|
+
* after every successful run. Closing undici's dispatcher first does not help; only not
|
|
63
|
+
* calling exit() does.
|
|
64
|
+
*
|
|
65
|
+
* Setting exitCode and letting the loop drain is also measurably faster (295ms vs 406ms
|
|
66
|
+
* on the same work), because exit() was racing teardown rather than waiting for it. The
|
|
67
|
+
* dispatcher is still closed first so idle sockets are released immediately instead of
|
|
68
|
+
* holding the process open for their keep-alive timeout.
|
|
69
|
+
*/
|
|
70
|
+
async function finish(code) {
|
|
71
|
+
process.exitCode = code ?? 0;
|
|
72
|
+
try {
|
|
73
|
+
const dispatcher = globalThis[Symbol.for('undici.globalDispatcher.1')];
|
|
74
|
+
if (dispatcher?.close) await dispatcher.close();
|
|
75
|
+
} catch {
|
|
76
|
+
// Internal and version-dependent; if it is gone, natural drain still gets there.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
main(process.argv.slice(2))
|
|
81
|
+
.then(finish)
|
|
82
|
+
.catch(async (err) => {
|
|
83
|
+
process.stderr.write(`\x1b[31m✗\x1b[39m ${err?.message || err}\n`);
|
|
84
|
+
if (process.env.JAITUS_DEBUG) process.stderr.write(`${err?.stack}\n`);
|
|
85
|
+
await finish(1);
|
|
86
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaitus",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "Jaitus — a coding agent in your terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"node": ">=20"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"test": "node tests/source-sanity.js && node tests/rules.js && node tests/run.js && node tests/commands.js && node tests/login.js && node tests/session.js && node tests/openUrl.js && node tests/ink-tui.js && node tests/tui-render.js && node tests/mouse-e2e.js && node tests/environment.js && node tests/update.js && node tests/continuation.js && node tests/steps.js && node tests/files.js && node tests/processes.js && node tests/security.js && node tests/context-budget.js && node tests/context-trim.js",
|
|
19
|
+
"test": "node tests/source-sanity.js && node tests/react-build.js && node tests/stalls.js && node tests/clipboard-write.js && node tests/rewind-images.js && node tests/rules.js && node tests/run.js && node tests/commands.js && node tests/login.js && node tests/session.js && node tests/openUrl.js && node tests/ink-tui.js && node tests/tui-render.js && node tests/mouse-e2e.js && node tests/environment.js && node tests/update.js && node tests/service-notices.js && node tests/continuation.js && node tests/steps.js && node tests/files.js && node tests/processes.js && node tests/security.js && node tests/context-budget.js && node tests/context-trim.js",
|
|
20
20
|
"preview": "node scripts/tui-preview.js",
|
|
21
21
|
"prepublishOnly": "npm test"
|
|
22
22
|
},
|