jaitus 0.3.23 → 0.3.24
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 +2 -2
- package/src/errors.js +126 -126
- package/src/index.js +3198 -3189
- package/src/updatePolicy.js +54 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaitus",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.24",
|
|
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/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 && node tests/compaction.js && node tests/copy-clean.js && node tests/parallel-tools.js && node tests/plan-percent.js && node tests/orb.js && node tests/update-required.js && node tests/select-scroll.js && node tests/project-identity.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 && node tests/compaction.js && node tests/copy-clean.js && node tests/parallel-tools.js && node tests/plan-percent.js && node tests/orb.js && node tests/update-required.js && node tests/update-policy.js && node tests/select-scroll.js && node tests/project-identity.js",
|
|
20
20
|
"preview": "node scripts/tui-preview.js",
|
|
21
21
|
"prepublishOnly": "npm test"
|
|
22
22
|
},
|
package/src/errors.js
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
// ─── What the CLI says when something fails ─────────────────────────────────────
|
|
2
|
-
//
|
|
3
|
-
// The gateway answers every failure with a `jaitus_*` code from one catalog. This file
|
|
4
|
-
// is the CLI's half of that contract: a code maps to a title and a hint written here,
|
|
5
|
-
// and anything WITHOUT a known code — an HTML page from a proxy, a body in some other
|
|
6
|
-
// shape, a code this build has never heard of — becomes "something went wrong in
|
|
7
|
-
// Jaitus" plus the request id. The CLI never prints an error body it does not
|
|
8
|
-
// recognise, because the only text that is safe to show is text we wrote.
|
|
9
|
-
|
|
10
|
-
const CATALOG = {
|
|
11
|
-
auth_required: { title: 'Not signed in', hint: 'Type /login to sign in (or run `jaitus login`).' },
|
|
12
|
-
session_expired: { title: 'Signed out', hint: 'Type /login to sign in again (or run `jaitus login`).' },
|
|
13
|
-
account_suspended: { title: 'Account suspended', hint: 'Contact support@jaitus.com if you think this is a mistake.' },
|
|
14
|
-
email_unverified: { title: 'Email not verified', hint: 'Open the verification link in your inbox, then retry.' },
|
|
15
|
-
free_limit_reached: { title: 'Free allowance used up', hint: 'Subscribe at jaitus.com/billing, then retry this turn. Pay by UPI, card, net banking or wallet; the plan starts as soon as the payment goes through.' },
|
|
16
|
-
free_machine_limit: { title: 'No free prompts on this account', hint: 'Subscribe at jaitus.com/billing to keep using Jaitus on this account.' },
|
|
17
|
-
free_needs_check: { title: 'Unlock your free prompts', hint: 'A one-time ₹1 UPI check at jaitus.com/billing (refunded). Or subscribe.' },
|
|
18
|
-
free_needs_cli: { title: 'Update Jaitus for free prompts', hint: 'Run npm i -g jaitus, then try again.' },
|
|
19
|
-
// This version is below what Jaitus now requires; the message names both versions.
|
|
20
|
-
update_required: { title: 'Update Jaitus to continue', hint: 'Run npm i -g jaitus@latest, then start jaitus again.' },
|
|
21
|
-
free_request_too_large: { title: 'Too large for the free plan', hint: 'Run /compact or start a new session, or subscribe at jaitus.com/billing.' },
|
|
22
|
-
plan_limit_reached: { title: 'Monthly usage used up', hint: 'To keep going now, switch plans at jaitus.com/billing —
|
|
23
|
-
rate_limited: { title: 'Slow down', hint: 'Wait a moment, then retry.' },
|
|
24
|
-
context_too_long: { title: 'Conversation too long', hint: 'Run /compact, or start a new session.' },
|
|
25
|
-
request_too_large: { title: 'Request too large', hint: 'Usually images: remove some, or run /compact to drop old ones. Images over 3.5 MB are shrunk automatically.' },
|
|
26
|
-
daily_limit_reached: { title: 'Usage limit reached', hint: 'It refills automatically. /usage shows where you are.' },
|
|
27
|
-
plan_expired: { title: 'Your plan has ended', hint: 'Plans last 30 days and do not renew by themselves. Renew at jaitus.com/billing, then retry this turn.' },
|
|
28
|
-
window_limit_reached: { title: 'Usage limit reached', hint: 'It resets by itself — /usage shows your 5-hour window, week and month, and when each resets.' },
|
|
29
|
-
token_expired: { title: 'Signed out', hint: 'Type /login to sign in again (or run `jaitus login`).' },
|
|
30
|
-
refresh_race: { title: 'Sign-in was being renewed', hint: 'Try again.' },
|
|
31
|
-
content_blocked: { title: 'Request refused', hint: 'Rephrase the request and try again.' },
|
|
32
|
-
bad_request: { title: 'Request not accepted', hint: 'Try again; if it repeats, run /debug and send the output to support@jaitus.com.' },
|
|
33
|
-
model_unavailable: { title: 'Model unavailable', hint: 'Run `jaitus config model --unset` so Jaitus picks the model automatically.' },
|
|
34
|
-
busy: { title: 'Jaitus is busy', hint: 'Try again in a minute.' },
|
|
35
|
-
unavailable: { title: 'Jaitus is unavailable', hint: 'Try again shortly. `jaitus doctor` checks your side.' },
|
|
36
|
-
maintenance: { title: 'Down for maintenance', hint: 'Try again shortly.' },
|
|
37
|
-
timeout: { title: 'Timed out', hint: 'Try again.' },
|
|
38
|
-
interrupted: { title: 'Response interrupted', hint: 'Try again.' },
|
|
39
|
-
internal: { title: 'Something went wrong', hint: 'Try again; if it keeps happening, email support@jaitus.com with the request id.' },
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const GENERIC = 'Something went wrong in Jaitus.';
|
|
43
|
-
|
|
44
|
-
export class JaitusError extends Error {
|
|
45
|
-
constructor({ code = 'internal', message, status = 0, requestId = '', retryAfter = null } = {}) {
|
|
46
|
-
const known = Object.prototype.hasOwnProperty.call(CATALOG, code) ? code : 'internal';
|
|
47
|
-
super(message || GENERIC);
|
|
48
|
-
this.name = 'JaitusError';
|
|
49
|
-
this.code = known;
|
|
50
|
-
this.status = status;
|
|
51
|
-
this.requestId = requestId;
|
|
52
|
-
this.retryAfter = retryAfter;
|
|
53
|
-
this.title = CATALOG[known].title;
|
|
54
|
-
this.hint = CATALOG[known].hint;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* An error body from the gateway → a JaitusError.
|
|
60
|
-
*
|
|
61
|
-
* The gateway's message is shown ONLY when the body carries a recognised `jaitus_`
|
|
62
|
-
* code, because only then is it guaranteed to be our wording (it may carry specifics,
|
|
63
|
-
* like how many free prompts there were). Otherwise the message is ours, generic.
|
|
64
|
-
*/
|
|
65
|
-
export function fromGatewayBody(status, body, { requestId = '', retryAfter = null } = {}) {
|
|
66
|
-
let parsed = body;
|
|
67
|
-
if (typeof body === 'string') {
|
|
68
|
-
try { parsed = JSON.parse(body); } catch { parsed = null; }
|
|
69
|
-
}
|
|
70
|
-
const err = parsed?.error || null;
|
|
71
|
-
const rawCode = String(err?.code || '');
|
|
72
|
-
const code = rawCode.startsWith('jaitus_') ? rawCode.slice(7) : '';
|
|
73
|
-
const known = code && Object.prototype.hasOwnProperty.call(CATALOG, code);
|
|
74
|
-
const id = String(parsed?.request_id || requestId || '');
|
|
75
|
-
// No Jaitus code on a gateway-class status: the answer came from the proxy in front of
|
|
76
|
-
// the gateway (its timeout page, a 502 while a deploy restarts the server), not from
|
|
77
|
-
// the gateway. Those are "not right now" — said plainly and retried — never the
|
|
78
|
-
// dead-end "Something went wrong" they used to read as.
|
|
79
|
-
if (!known && (status === 504 || status === 524)) {
|
|
80
|
-
return new JaitusError({ code: 'timeout', status, requestId: id, retryAfter, message: 'Jaitus took too long to answer and the connection was closed on the way. Try again.' });
|
|
81
|
-
}
|
|
82
|
-
if (!known && (status === 502 || status === 503 || (status >= 520 && status <= 530))) {
|
|
83
|
-
return new JaitusError({ code: 'unavailable', status, requestId: id, retryAfter, message: 'Jaitus could not be reached just now. Try again in a moment.' });
|
|
84
|
-
}
|
|
85
|
-
return new JaitusError({
|
|
86
|
-
code: known ? code : 'internal',
|
|
87
|
-
message: known && typeof err?.message === 'string' && err.message.trim() ? err.message.trim() : GENERIC,
|
|
88
|
-
status,
|
|
89
|
-
requestId: id,
|
|
90
|
-
retryAfter,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** A failed fetch Response → a JaitusError, reading the body once. */
|
|
95
|
-
export async function fromResponse(res) {
|
|
96
|
-
const text = await res.text().catch(() => '');
|
|
97
|
-
const requestId = res.headers?.get?.('x-request-id') || '';
|
|
98
|
-
const retryAfter = Number(res.headers?.get?.('retry-after')) || null;
|
|
99
|
-
const error = fromGatewayBody(res.status, text, { requestId, retryAfter });
|
|
100
|
-
// The gateway says trying again cannot help yet (e.g. no provider is switched on):
|
|
101
|
-
// report it at once instead of retrying behind "Working…".
|
|
102
|
-
if (res.headers?.get?.('x-jaitus-retry') === 'no') error.noRetry = true;
|
|
103
|
-
return error;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* fetch() threw before any response — the network, not the service. This is the one
|
|
108
|
-
* failure where the true cause is on the user's side and worth naming plainly.
|
|
109
|
-
*/
|
|
110
|
-
export function fromNetwork(cause) {
|
|
111
|
-
if (cause?.name === 'AbortError') return cause;
|
|
112
|
-
const error = new JaitusError({
|
|
113
|
-
code: 'unavailable',
|
|
114
|
-
message: 'Could not reach Jaitus. Check your internet connection.',
|
|
115
|
-
});
|
|
116
|
-
error.title = 'Cannot reach Jaitus';
|
|
117
|
-
error.hint = 'Check your connection, then run `jaitus doctor`.';
|
|
118
|
-
error.cause = cause;
|
|
119
|
-
return error;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function isJaitusError(e) {
|
|
123
|
-
return e instanceof JaitusError || e?.name === 'JaitusError';
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export const ERROR_CODES = Object.freeze(Object.keys(CATALOG));
|
|
1
|
+
// ─── What the CLI says when something fails ─────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// The gateway answers every failure with a `jaitus_*` code from one catalog. This file
|
|
4
|
+
// is the CLI's half of that contract: a code maps to a title and a hint written here,
|
|
5
|
+
// and anything WITHOUT a known code — an HTML page from a proxy, a body in some other
|
|
6
|
+
// shape, a code this build has never heard of — becomes "something went wrong in
|
|
7
|
+
// Jaitus" plus the request id. The CLI never prints an error body it does not
|
|
8
|
+
// recognise, because the only text that is safe to show is text we wrote.
|
|
9
|
+
|
|
10
|
+
const CATALOG = {
|
|
11
|
+
auth_required: { title: 'Not signed in', hint: 'Type /login to sign in (or run `jaitus login`).' },
|
|
12
|
+
session_expired: { title: 'Signed out', hint: 'Type /login to sign in again (or run `jaitus login`).' },
|
|
13
|
+
account_suspended: { title: 'Account suspended', hint: 'Contact support@jaitus.com if you think this is a mistake.' },
|
|
14
|
+
email_unverified: { title: 'Email not verified', hint: 'Open the verification link in your inbox, then retry.' },
|
|
15
|
+
free_limit_reached: { title: 'Free allowance used up', hint: 'Subscribe at jaitus.com/billing, then retry this turn. Pay by UPI, card, net banking or wallet; the plan starts as soon as the payment goes through.' },
|
|
16
|
+
free_machine_limit: { title: 'No free prompts on this account', hint: 'Subscribe at jaitus.com/billing to keep using Jaitus on this account.' },
|
|
17
|
+
free_needs_check: { title: 'Unlock your free prompts', hint: 'A one-time ₹1 UPI check at jaitus.com/billing (refunded). Or subscribe.' },
|
|
18
|
+
free_needs_cli: { title: 'Update Jaitus for free prompts', hint: 'Run npm i -g jaitus, then try again.' },
|
|
19
|
+
// This version is below what Jaitus now requires; the message names both versions.
|
|
20
|
+
update_required: { title: 'Update Jaitus to continue', hint: 'Run npm i -g jaitus@latest, then start jaitus again.' },
|
|
21
|
+
free_request_too_large: { title: 'Too large for the free plan', hint: 'Run /compact or start a new session, or subscribe at jaitus.com/billing.' },
|
|
22
|
+
plan_limit_reached: { title: 'Monthly usage used up', hint: 'To keep going now, switch plans at jaitus.com/billing — the new plan starts fresh today, for 30 days. Buying another 30 days of the same plan adds days but does not refill this month. /usage shows where you are.' },
|
|
23
|
+
rate_limited: { title: 'Slow down', hint: 'Wait a moment, then retry.' },
|
|
24
|
+
context_too_long: { title: 'Conversation too long', hint: 'Run /compact, or start a new session.' },
|
|
25
|
+
request_too_large: { title: 'Request too large', hint: 'Usually images: remove some, or run /compact to drop old ones. Images over 3.5 MB are shrunk automatically.' },
|
|
26
|
+
daily_limit_reached: { title: 'Usage limit reached', hint: 'It refills automatically. /usage shows where you are.' },
|
|
27
|
+
plan_expired: { title: 'Your plan has ended', hint: 'Plans last 30 days and do not renew by themselves. Renew at jaitus.com/billing, then retry this turn.' },
|
|
28
|
+
window_limit_reached: { title: 'Usage limit reached', hint: 'It resets by itself — /usage shows your 5-hour window, week and month, and when each resets.' },
|
|
29
|
+
token_expired: { title: 'Signed out', hint: 'Type /login to sign in again (or run `jaitus login`).' },
|
|
30
|
+
refresh_race: { title: 'Sign-in was being renewed', hint: 'Try again.' },
|
|
31
|
+
content_blocked: { title: 'Request refused', hint: 'Rephrase the request and try again.' },
|
|
32
|
+
bad_request: { title: 'Request not accepted', hint: 'Try again; if it repeats, run /debug and send the output to support@jaitus.com.' },
|
|
33
|
+
model_unavailable: { title: 'Model unavailable', hint: 'Run `jaitus config model --unset` so Jaitus picks the model automatically.' },
|
|
34
|
+
busy: { title: 'Jaitus is busy', hint: 'Try again in a minute.' },
|
|
35
|
+
unavailable: { title: 'Jaitus is unavailable', hint: 'Try again shortly. `jaitus doctor` checks your side.' },
|
|
36
|
+
maintenance: { title: 'Down for maintenance', hint: 'Try again shortly.' },
|
|
37
|
+
timeout: { title: 'Timed out', hint: 'Try again.' },
|
|
38
|
+
interrupted: { title: 'Response interrupted', hint: 'Try again.' },
|
|
39
|
+
internal: { title: 'Something went wrong', hint: 'Try again; if it keeps happening, email support@jaitus.com with the request id.' },
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const GENERIC = 'Something went wrong in Jaitus.';
|
|
43
|
+
|
|
44
|
+
export class JaitusError extends Error {
|
|
45
|
+
constructor({ code = 'internal', message, status = 0, requestId = '', retryAfter = null } = {}) {
|
|
46
|
+
const known = Object.prototype.hasOwnProperty.call(CATALOG, code) ? code : 'internal';
|
|
47
|
+
super(message || GENERIC);
|
|
48
|
+
this.name = 'JaitusError';
|
|
49
|
+
this.code = known;
|
|
50
|
+
this.status = status;
|
|
51
|
+
this.requestId = requestId;
|
|
52
|
+
this.retryAfter = retryAfter;
|
|
53
|
+
this.title = CATALOG[known].title;
|
|
54
|
+
this.hint = CATALOG[known].hint;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* An error body from the gateway → a JaitusError.
|
|
60
|
+
*
|
|
61
|
+
* The gateway's message is shown ONLY when the body carries a recognised `jaitus_`
|
|
62
|
+
* code, because only then is it guaranteed to be our wording (it may carry specifics,
|
|
63
|
+
* like how many free prompts there were). Otherwise the message is ours, generic.
|
|
64
|
+
*/
|
|
65
|
+
export function fromGatewayBody(status, body, { requestId = '', retryAfter = null } = {}) {
|
|
66
|
+
let parsed = body;
|
|
67
|
+
if (typeof body === 'string') {
|
|
68
|
+
try { parsed = JSON.parse(body); } catch { parsed = null; }
|
|
69
|
+
}
|
|
70
|
+
const err = parsed?.error || null;
|
|
71
|
+
const rawCode = String(err?.code || '');
|
|
72
|
+
const code = rawCode.startsWith('jaitus_') ? rawCode.slice(7) : '';
|
|
73
|
+
const known = code && Object.prototype.hasOwnProperty.call(CATALOG, code);
|
|
74
|
+
const id = String(parsed?.request_id || requestId || '');
|
|
75
|
+
// No Jaitus code on a gateway-class status: the answer came from the proxy in front of
|
|
76
|
+
// the gateway (its timeout page, a 502 while a deploy restarts the server), not from
|
|
77
|
+
// the gateway. Those are "not right now" — said plainly and retried — never the
|
|
78
|
+
// dead-end "Something went wrong" they used to read as.
|
|
79
|
+
if (!known && (status === 504 || status === 524)) {
|
|
80
|
+
return new JaitusError({ code: 'timeout', status, requestId: id, retryAfter, message: 'Jaitus took too long to answer and the connection was closed on the way. Try again.' });
|
|
81
|
+
}
|
|
82
|
+
if (!known && (status === 502 || status === 503 || (status >= 520 && status <= 530))) {
|
|
83
|
+
return new JaitusError({ code: 'unavailable', status, requestId: id, retryAfter, message: 'Jaitus could not be reached just now. Try again in a moment.' });
|
|
84
|
+
}
|
|
85
|
+
return new JaitusError({
|
|
86
|
+
code: known ? code : 'internal',
|
|
87
|
+
message: known && typeof err?.message === 'string' && err.message.trim() ? err.message.trim() : GENERIC,
|
|
88
|
+
status,
|
|
89
|
+
requestId: id,
|
|
90
|
+
retryAfter,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** A failed fetch Response → a JaitusError, reading the body once. */
|
|
95
|
+
export async function fromResponse(res) {
|
|
96
|
+
const text = await res.text().catch(() => '');
|
|
97
|
+
const requestId = res.headers?.get?.('x-request-id') || '';
|
|
98
|
+
const retryAfter = Number(res.headers?.get?.('retry-after')) || null;
|
|
99
|
+
const error = fromGatewayBody(res.status, text, { requestId, retryAfter });
|
|
100
|
+
// The gateway says trying again cannot help yet (e.g. no provider is switched on):
|
|
101
|
+
// report it at once instead of retrying behind "Working…".
|
|
102
|
+
if (res.headers?.get?.('x-jaitus-retry') === 'no') error.noRetry = true;
|
|
103
|
+
return error;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* fetch() threw before any response — the network, not the service. This is the one
|
|
108
|
+
* failure where the true cause is on the user's side and worth naming plainly.
|
|
109
|
+
*/
|
|
110
|
+
export function fromNetwork(cause) {
|
|
111
|
+
if (cause?.name === 'AbortError') return cause;
|
|
112
|
+
const error = new JaitusError({
|
|
113
|
+
code: 'unavailable',
|
|
114
|
+
message: 'Could not reach Jaitus. Check your internet connection.',
|
|
115
|
+
});
|
|
116
|
+
error.title = 'Cannot reach Jaitus';
|
|
117
|
+
error.hint = 'Check your connection, then run `jaitus doctor`.';
|
|
118
|
+
error.cause = cause;
|
|
119
|
+
return error;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function isJaitusError(e) {
|
|
123
|
+
return e instanceof JaitusError || e?.name === 'JaitusError';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const ERROR_CODES = Object.freeze(Object.keys(CATALOG));
|