@kvman/kvcoder 0.1.11 → 0.1.12
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/dist/api.d.ts +45 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/calls/call-name.d.ts.map +1 -1
- package/dist/calls/call-name.js +10 -1
- package/dist/calls/call-name.js.map +1 -1
- package/dist/calls/run-tool.d.ts.map +1 -1
- package/dist/calls/run-tool.js +2 -0
- package/dist/calls/run-tool.js.map +1 -1
- package/dist/connector-call.d.ts +2 -2
- package/dist/connector-call.d.ts.map +1 -1
- package/dist/connector-call.js +5 -3
- package/dist/connector-call.js.map +1 -1
- package/dist/connectors/artifact.d.ts +1 -0
- package/dist/connectors/artifact.d.ts.map +1 -1
- package/dist/connectors/background.d.ts.map +1 -1
- package/dist/connectors/background.js +8 -4
- package/dist/connectors/background.js.map +1 -1
- package/dist/connectors/builtin-connectors.d.ts +38 -0
- package/dist/connectors/builtin-connectors.d.ts.map +1 -1
- package/dist/connectors/builtin-connectors.js +4 -1
- package/dist/connectors/builtin-connectors.js.map +1 -1
- package/dist/connectors/delegate.d.ts.map +1 -1
- package/dist/connectors/delegate.js +3 -0
- package/dist/connectors/delegate.js.map +1 -1
- package/dist/connectors/execution-map.d.ts +1 -1
- package/dist/connectors/execution-map.d.ts.map +1 -1
- package/dist/connectors/execution-map.js +1 -1
- package/dist/connectors/execution-map.js.map +1 -1
- package/dist/connectors/fs.d.ts +29 -1
- package/dist/connectors/fs.d.ts.map +1 -1
- package/dist/connectors/fs.js +46 -9
- package/dist/connectors/fs.js.map +1 -1
- package/dist/connectors/payload-fields.d.ts +3 -0
- package/dist/connectors/payload-fields.d.ts.map +1 -1
- package/dist/connectors/payload-fields.js +8 -2
- package/dist/connectors/payload-fields.js.map +1 -1
- package/dist/connectors/web.d.ts +16 -0
- package/dist/connectors/web.d.ts.map +1 -0
- package/dist/connectors/web.js +22 -0
- package/dist/connectors/web.js.map +1 -0
- package/dist/delegate/permission.d.ts +6 -0
- package/dist/delegate/permission.d.ts.map +1 -1
- package/dist/files/change-diff.d.ts +17 -0
- package/dist/files/change-diff.d.ts.map +1 -0
- package/dist/files/change-diff.js +59 -0
- package/dist/files/change-diff.js.map +1 -0
- package/dist/files/edit-places.d.ts +11 -0
- package/dist/files/edit-places.d.ts.map +1 -0
- package/dist/files/edit-places.js +105 -0
- package/dist/files/edit-places.js.map +1 -0
- package/dist/files/edit-text.d.ts +1 -0
- package/dist/files/edit-text.d.ts.map +1 -1
- package/dist/files/edit-text.js +22 -10
- package/dist/files/edit-text.js.map +1 -1
- package/dist/files/file-change.d.ts.map +1 -1
- package/dist/files/file-change.js +12 -0
- package/dist/files/file-change.js.map +1 -1
- package/dist/files/find-paths.d.ts +9 -0
- package/dist/files/find-paths.d.ts.map +1 -0
- package/dist/files/find-paths.js +38 -0
- package/dist/files/find-paths.js.map +1 -0
- package/dist/files/read-file.d.ts +3 -1
- package/dist/files/read-file.d.ts.map +1 -1
- package/dist/files/read-file.js +7 -6
- package/dist/files/read-file.js.map +1 -1
- package/dist/files/read-files.d.ts +11 -0
- package/dist/files/read-files.d.ts.map +1 -0
- package/dist/files/read-files.js +35 -0
- package/dist/files/read-files.js.map +1 -0
- package/dist/files/read-text.d.ts +63 -0
- package/dist/files/read-text.d.ts.map +1 -0
- package/dist/files/read-text.js +67 -0
- package/dist/files/read-text.js.map +1 -0
- package/dist/files/register-changes.d.ts +3 -0
- package/dist/files/register-changes.d.ts.map +1 -0
- package/dist/files/register-changes.js +78 -0
- package/dist/files/register-changes.js.map +1 -0
- package/dist/files/search-text.d.ts +10 -1
- package/dist/files/search-text.d.ts.map +1 -1
- package/dist/files/search-text.js +32 -57
- package/dist/files/search-text.js.map +1 -1
- package/dist/files/workspace-files.d.ts +5 -0
- package/dist/files/workspace-files.d.ts.map +1 -0
- package/dist/files/workspace-files.js +66 -0
- package/dist/files/workspace-files.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/prompt/build-prompt.d.ts +4 -0
- package/dist/prompt/build-prompt.d.ts.map +1 -1
- package/dist/prompt/build-prompt.js +6 -2
- package/dist/prompt/build-prompt.js.map +1 -1
- package/dist/prompt/person-preferences.d.ts +5 -0
- package/dist/prompt/person-preferences.d.ts.map +1 -0
- package/dist/prompt/person-preferences.js +14 -0
- package/dist/prompt/person-preferences.js.map +1 -0
- package/dist/prompt/session-grants.d.ts +4 -0
- package/dist/prompt/session-grants.d.ts.map +1 -1
- package/dist/prompt/session-grants.js +3 -2
- package/dist/prompt/session-grants.js.map +1 -1
- package/dist/prompt/session-prompt.d.ts.map +1 -1
- package/dist/prompt/session-prompt.js +15 -6
- package/dist/prompt/session-prompt.js.map +1 -1
- package/dist/prompt/working-method.d.ts +2 -2
- package/dist/prompt/working-method.d.ts.map +1 -1
- package/dist/prompt/working-method.js +49 -43
- package/dist/prompt/working-method.js.map +1 -1
- package/dist/register-settings.d.ts +23 -0
- package/dist/register-settings.d.ts.map +1 -1
- package/dist/register-settings.js +13 -0
- package/dist/register-settings.js.map +1 -1
- package/dist/schemas/approval-rule.d.ts +9 -0
- package/dist/schemas/approval-rule.d.ts.map +1 -0
- package/dist/schemas/approval-rule.js +7 -0
- package/dist/schemas/approval-rule.js.map +1 -0
- package/dist/schemas/check.d.ts +7 -0
- package/dist/schemas/check.d.ts.map +1 -0
- package/dist/schemas/check.js +9 -0
- package/dist/schemas/check.js.map +1 -0
- package/dist/schemas/records.d.ts +10 -0
- package/dist/schemas/records.d.ts.map +1 -1
- package/dist/schemas/records.js +8 -0
- package/dist/schemas/records.js.map +1 -1
- package/dist/sessions/new-session.d.ts.map +1 -1
- package/dist/sessions/new-session.js +4 -1
- package/dist/sessions/new-session.js.map +1 -1
- package/dist/sessions/register-fork-export.d.ts.map +1 -1
- package/dist/sessions/register-fork-export.js +3 -2
- package/dist/sessions/register-fork-export.js.map +1 -1
- package/dist/sessions/register-sessions.d.ts.map +1 -1
- package/dist/sessions/register-sessions.js +17 -9
- package/dist/sessions/register-sessions.js.map +1 -1
- package/dist/sessions/session-view.d.ts +8 -1
- package/dist/sessions/session-view.d.ts.map +1 -1
- package/dist/sessions/session-view.js +6 -1
- package/dist/sessions/session-view.js.map +1 -1
- package/dist/sessions/waiting-on.d.ts +7 -0
- package/dist/sessions/waiting-on.d.ts.map +1 -0
- package/dist/sessions/waiting-on.js +20 -0
- package/dist/sessions/waiting-on.js.map +1 -0
- package/dist/store/collections.d.ts +18 -0
- package/dist/store/collections.d.ts.map +1 -1
- package/dist/store/collections.js +3 -1
- package/dist/store/collections.js.map +1 -1
- package/dist/turns/answer-extras.d.ts +21 -0
- package/dist/turns/answer-extras.d.ts.map +1 -0
- package/dist/turns/answer-extras.js +43 -0
- package/dist/turns/answer-extras.js.map +1 -0
- package/dist/turns/answer-fingerprint.d.ts +6 -2
- package/dist/turns/answer-fingerprint.d.ts.map +1 -1
- package/dist/turns/answer-fingerprint.js +9 -3
- package/dist/turns/answer-fingerprint.js.map +1 -1
- package/dist/turns/apply-answer.d.ts +2 -1
- package/dist/turns/apply-answer.d.ts.map +1 -1
- package/dist/turns/apply-answer.js +10 -4
- package/dist/turns/apply-answer.js.map +1 -1
- package/dist/turns/approval-rules.d.ts +13 -0
- package/dist/turns/approval-rules.d.ts.map +1 -0
- package/dist/turns/approval-rules.js +65 -0
- package/dist/turns/approval-rules.js.map +1 -0
- package/dist/turns/check-after-edits.d.ts +8 -0
- package/dist/turns/check-after-edits.d.ts.map +1 -0
- package/dist/turns/check-after-edits.js +23 -0
- package/dist/turns/check-after-edits.js.map +1 -0
- package/dist/turns/clear-results.d.ts +15 -0
- package/dist/turns/clear-results.d.ts.map +1 -0
- package/dist/turns/clear-results.js +58 -0
- package/dist/turns/clear-results.js.map +1 -0
- package/dist/turns/cleared-results.d.ts +17 -0
- package/dist/turns/cleared-results.d.ts.map +1 -0
- package/dist/turns/cleared-results.js +46 -0
- package/dist/turns/cleared-results.js.map +1 -0
- package/dist/turns/compaction.js +6 -6
- package/dist/turns/compaction.js.map +1 -1
- package/dist/turns/file-results.d.ts +15 -0
- package/dist/turns/file-results.d.ts.map +1 -0
- package/dist/turns/file-results.js +39 -0
- package/dist/turns/file-results.js.map +1 -0
- package/dist/turns/lost-reply.js +2 -2
- package/dist/turns/lost-reply.js.map +1 -1
- package/dist/turns/model-context.d.ts +2 -0
- package/dist/turns/model-context.d.ts.map +1 -1
- package/dist/turns/model-context.js +28 -5
- package/dist/turns/model-context.js.map +1 -1
- package/dist/turns/read-again.d.ts +11 -5
- package/dist/turns/read-again.d.ts.map +1 -1
- package/dist/turns/read-again.js +39 -10
- package/dist/turns/read-again.js.map +1 -1
- package/dist/turns/register-turns.d.ts.map +1 -1
- package/dist/turns/register-turns.js +12 -4
- package/dist/turns/register-turns.js.map +1 -1
- package/dist/turns/run-calls.d.ts +4 -0
- package/dist/turns/run-calls.d.ts.map +1 -1
- package/dist/turns/run-calls.js +35 -5
- package/dist/turns/run-calls.js.map +1 -1
- package/dist/turns/run-command.d.ts.map +1 -1
- package/dist/turns/run-command.js +4 -4
- package/dist/turns/run-command.js.map +1 -1
- package/dist/turns/step.d.ts.map +1 -1
- package/dist/turns/step.js +43 -8
- package/dist/turns/step.js.map +1 -1
- package/dist/ui/register-ui.js +2 -2
- package/dist/ui/register-ui.js.map +1 -1
- package/dist/web/components/approval.css +1 -1
- package/dist/web/components/approval.js +122 -89
- package/dist/web/components/call.css +1 -1
- package/dist/web/components/call.js +400 -302
- package/dist/web/components/connectors.css +1 -1
- package/dist/web/components/connectors.js +440 -427
- package/dist/web/components/conversation.css +1 -1
- package/dist/web/components/conversation.js +2509 -1500
- package/dist/web/components/mcp-sign-in.css +1 -1
- package/dist/web/components/model.css +1 -1
- package/dist/web/components/model.js +138 -126
- package/dist/web/components/preferences.css +2 -0
- package/dist/web/components/preferences.js +151 -0
- package/dist/web/components/question.css +1 -1
- package/dist/web/components/sessions.css +1 -1
- package/dist/web/components/sessions.js +44 -21
- package/dist/web-fetch/fetch-page.d.ts +28 -0
- package/dist/web-fetch/fetch-page.d.ts.map +1 -0
- package/dist/web-fetch/fetch-page.js +108 -0
- package/dist/web-fetch/fetch-page.js.map +1 -0
- package/dist/web-fetch/private-address.d.ts +3 -0
- package/dist/web-fetch/private-address.d.ts.map +1 -0
- package/dist/web-fetch/private-address.js +69 -0
- package/dist/web-fetch/private-address.js.map +1 -0
- package/dist/web-fetch/web-hosts.d.ts +7 -0
- package/dist/web-fetch/web-hosts.d.ts.map +1 -0
- package/dist/web-fetch/web-hosts.js +19 -0
- package/dist/web-fetch/web-hosts.js.map +1 -0
- package/docs/connectors.md +2 -2
- package/locales/ar.json +66 -1
- package/locales/en.json +66 -1
- package/package.json +17 -3
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { lookup } from 'node:dns/promises';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import https from 'node:https';
|
|
4
|
+
import { isIP } from 'node:net';
|
|
5
|
+
import { ProblemError } from '@kvman/sdk';
|
|
6
|
+
import { invalid } from "../problems.js";
|
|
7
|
+
import { truncate } from "../result-text.js";
|
|
8
|
+
import { isPrivateAddress } from "./private-address.js";
|
|
9
|
+
// `web fetch` (plan 08 §8.5, ADR 0095): a page by its address, as Markdown or text. Every host is resolved and checked
|
|
10
|
+
// before each request and each redirect, and the connection goes to the address that was checked.
|
|
11
|
+
export const bodyLimit = 5 * 1024 * 1024;
|
|
12
|
+
const redirectLimit = 5;
|
|
13
|
+
const pageTimeoutMs = 30_000;
|
|
14
|
+
const textTypes = new Set(['application/json', 'application/xml', 'application/javascript']);
|
|
15
|
+
export const webFailed = (url, fields) => new ProblemError({ code: 'kvcoder/WEB_FAILED', message: `${url} couldn't be read: ${fields.status === undefined ? fields.reason ?? 'it failed' : `status ${String(fields.status)}`}.`, params: { url, ...fields } });
|
|
16
|
+
// Reads at most the body limit; the rest of a larger body is left unread.
|
|
17
|
+
function readBody(response) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const chunks = [];
|
|
20
|
+
let size = 0;
|
|
21
|
+
response.on('data', (chunk) => {
|
|
22
|
+
chunks.push(chunk);
|
|
23
|
+
size += chunk.length;
|
|
24
|
+
if (size >= bodyLimit)
|
|
25
|
+
response.destroy();
|
|
26
|
+
});
|
|
27
|
+
response.on('close', () => resolve(Buffer.concat(chunks).subarray(0, bodyLimit)));
|
|
28
|
+
response.on('error', reject);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** The network: Node's resolver, and a request pinned to the checked address. */
|
|
32
|
+
export const networkTransport = {
|
|
33
|
+
resolve: async (host) => (isIP(host) !== 0 ? [host] : (await lookup(host, { all: true, verbatim: true })).map((found) => found.address)),
|
|
34
|
+
request: (url, address, signal) => new Promise((resolve, reject) => {
|
|
35
|
+
const client = url.protocol === 'https:' ? https : http;
|
|
36
|
+
// Every lookup of this request answers the checked address, so a second resolution can't move it.
|
|
37
|
+
const pinned = (_host, options, done) => {
|
|
38
|
+
if (options.all === true)
|
|
39
|
+
done(null, [{ address, family: isIP(address) }]);
|
|
40
|
+
else
|
|
41
|
+
done(null, address, isIP(address));
|
|
42
|
+
};
|
|
43
|
+
const request = client.request(url, { method: 'GET', signal, lookup: pinned, headers: { accept: 'text/html, text/markdown, text/plain, application/json;q=0.9, */*;q=0.1', 'user-agent': 'kvman' } }, (response) => {
|
|
44
|
+
readBody(response).then((body) => resolve({ status: response.statusCode ?? 0, type: String(response.headers['content-type'] ?? ''), location: response.headers.location, body }), reject);
|
|
45
|
+
});
|
|
46
|
+
request.on('error', reject);
|
|
47
|
+
request.end();
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
// turndown brings a whole DOM, about 14 MB, so a worker loads it with its first page, not at start (plan 12 §12.3).
|
|
51
|
+
async function markdownOf(html) {
|
|
52
|
+
const { default: TurndownService } = await import('turndown');
|
|
53
|
+
const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });
|
|
54
|
+
turndown.remove(['script', 'style', 'noscript']);
|
|
55
|
+
return turndown.turndown(html);
|
|
56
|
+
}
|
|
57
|
+
// A checked address of the host, or a refusal naming it.
|
|
58
|
+
async function checkedAddress(transport, url) {
|
|
59
|
+
const host = url.hostname.replace(/^\[|\]$/g, '');
|
|
60
|
+
const addresses = await transport.resolve(host);
|
|
61
|
+
const [first] = addresses;
|
|
62
|
+
if (first === undefined || addresses.some(isPrivateAddress))
|
|
63
|
+
throw invalid(`${url.hostname} is a private or local address, which web fetch doesn't reach.`, { url: url.href });
|
|
64
|
+
return first;
|
|
65
|
+
}
|
|
66
|
+
function parsed(given) {
|
|
67
|
+
const url = URL.canParse(given) ? new URL(given) : undefined;
|
|
68
|
+
if (url === undefined || (url.protocol !== 'http:' && url.protocol !== 'https:'))
|
|
69
|
+
throw invalid('The address must start with http:// or https://.', { url: given });
|
|
70
|
+
if (url.username !== '' || url.password !== '')
|
|
71
|
+
throw invalid("The address can't hold a name or a password.", { url: given });
|
|
72
|
+
return url;
|
|
73
|
+
}
|
|
74
|
+
async function contentOf(type, body, url) {
|
|
75
|
+
const text = body.toString('utf8');
|
|
76
|
+
if (type === 'text/html' || type === 'application/xhtml+xml')
|
|
77
|
+
return markdownOf(text);
|
|
78
|
+
if (type.startsWith('text/') || textTypes.has(type) || type.endsWith('+json'))
|
|
79
|
+
return text;
|
|
80
|
+
throw invalid(`${url} is ${type === '' ? 'of no stated type' : type}, which web fetch doesn't read; only pages and text.`, { url, type });
|
|
81
|
+
}
|
|
82
|
+
/** Fetches a page, following redirects, each checked again. */
|
|
83
|
+
export async function fetchPage(given, transport, signal) {
|
|
84
|
+
let url = parsed(given);
|
|
85
|
+
const timeout = AbortSignal.any([signal, AbortSignal.timeout(pageTimeoutMs)]);
|
|
86
|
+
for (let redirects = 0;; redirects += 1) {
|
|
87
|
+
const address = await checkedAddress(transport, url);
|
|
88
|
+
let response;
|
|
89
|
+
try {
|
|
90
|
+
response = await transport.request(url, address, timeout);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
signal.throwIfAborted();
|
|
94
|
+
throw webFailed(url.href, { reason: timeout.aborted ? 'it took longer than 30 s' : error instanceof Error ? error.message : 'the connection failed' });
|
|
95
|
+
}
|
|
96
|
+
if (response.status >= 300 && response.status < 400 && response.location !== undefined) {
|
|
97
|
+
if (redirects === redirectLimit)
|
|
98
|
+
throw webFailed(url.href, { reason: `more than ${String(redirectLimit)} redirects` });
|
|
99
|
+
url = parsed(new URL(response.location, url).href);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (response.status >= 400)
|
|
103
|
+
throw webFailed(url.href, { status: response.status });
|
|
104
|
+
const type = (response.type.split(';')[0] ?? '').trim().toLowerCase();
|
|
105
|
+
return { url: url.href, status: response.status, type, content: truncate(await contentOf(type, response.body, url.href)) };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=fetch-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-page.js","sourceRoot":"","sources":["../../src/web-fetch/fetch-page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-address.d.ts","sourceRoot":"","sources":["../../src/web-fetch/private-address.ts"],"names":[],"mappings":"AA2DA,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKzD"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { isIP } from 'node:net';
|
|
2
|
+
// The addresses `web fetch` never reaches (plan 08 §8.5, ADR 0095, 3): loopback, private, link-local, unique-local,
|
|
3
|
+
// unspecified, and multicast, in IPv4 and IPv6, and IPv4 carried inside IPv6. Addresses are compared as numbers, so
|
|
4
|
+
// every spelling of one address (`::ffff:127.0.0.1`, `::ffff:7f00:1`) is judged the same.
|
|
5
|
+
const v4Blocks = [
|
|
6
|
+
[0x00000000, 8], // 0.0.0.0/8, unspecified
|
|
7
|
+
[0x0a000000, 8], // 10/8
|
|
8
|
+
[0x64400000, 10], // 100.64/10, shared
|
|
9
|
+
[0x7f000000, 8], // 127/8, loopback
|
|
10
|
+
[0xa9fe0000, 16], // 169.254/16, link-local
|
|
11
|
+
[0xac100000, 12], // 172.16/12
|
|
12
|
+
[0xc0a80000, 16], // 192.168/16
|
|
13
|
+
[0xe0000000, 4], // 224/4, multicast
|
|
14
|
+
[0xf0000000, 4], // 240/4, reserved
|
|
15
|
+
];
|
|
16
|
+
function privateV4(value) {
|
|
17
|
+
return v4Blocks.some(([base, bits]) => Math.floor(value / 2 ** (32 - bits)) === Math.floor(base / 2 ** (32 - bits)));
|
|
18
|
+
}
|
|
19
|
+
function v4Number(address) {
|
|
20
|
+
return address.split('.').reduce((total, part) => total * 256 + Number(part), 0);
|
|
21
|
+
}
|
|
22
|
+
/** The eight 16-bit groups of an IPv6 address, or nothing when it doesn't expand to exactly eight. */
|
|
23
|
+
function hextets(address) {
|
|
24
|
+
const dotted = /^(.*:)(\d+\.\d+\.\d+\.\d+)$/.exec(address);
|
|
25
|
+
const v4 = dotted?.[2] === undefined ? undefined : v4Number(dotted[2]);
|
|
26
|
+
const text = dotted?.[1] === undefined || v4 === undefined ? address : `${dotted[1]}${(v4 >>> 16).toString(16)}:${(v4 & 0xffff).toString(16)}`;
|
|
27
|
+
const halves = text.split('::');
|
|
28
|
+
if (halves.length > 2)
|
|
29
|
+
return undefined;
|
|
30
|
+
const groups = (half) => (half === undefined || half === '' ? [] : half.split(':').map((group) => (/^[\da-f]{1,4}$/i.test(group) ? Number.parseInt(group, 16) : Number.NaN)));
|
|
31
|
+
const head = groups(halves[0]), tail = groups(halves[1]);
|
|
32
|
+
const missing = 8 - head.length - tail.length;
|
|
33
|
+
if (halves.length === 1 ? missing !== 0 : missing < 1)
|
|
34
|
+
return undefined;
|
|
35
|
+
const all = [...head, ...Array(halves.length === 1 ? 0 : missing).fill(0), ...tail];
|
|
36
|
+
return all.some(Number.isNaN) ? undefined : all;
|
|
37
|
+
}
|
|
38
|
+
const v4Of = (high, low) => high * 0x10000 + low;
|
|
39
|
+
const zeros = (groups) => groups.every((group) => group === 0);
|
|
40
|
+
function privateV6(address) {
|
|
41
|
+
const groups = hextets(address);
|
|
42
|
+
if (groups === undefined)
|
|
43
|
+
return true;
|
|
44
|
+
const [first = 0, second = 0, third = 0, , , sixth = 0, seventh = 0, eighth = 0] = groups;
|
|
45
|
+
// ::/96 holds :: and ::1 and the old IPv4-compatible form; ::ffff:0:0/96 is IPv4 mapped into IPv6.
|
|
46
|
+
if (zeros(groups.slice(0, 6)))
|
|
47
|
+
return true;
|
|
48
|
+
if (zeros(groups.slice(0, 5)) && sixth === 0xffff)
|
|
49
|
+
return privateV4(v4Of(seventh, eighth));
|
|
50
|
+
// 64:ff9b::/96 is NAT64 and 2002::/16 is 6to4: each carries an IPv4 address, judged as one.
|
|
51
|
+
if (first === 0x64 && second === 0xff9b && zeros(groups.slice(2, 6)))
|
|
52
|
+
return privateV4(v4Of(seventh, eighth));
|
|
53
|
+
if (first === 0x64 && second === 0xff9b && third === 1)
|
|
54
|
+
return true; // 64:ff9b:1::/48, NAT64 for local use
|
|
55
|
+
if (first === 0x2002)
|
|
56
|
+
return privateV4(v4Of(second, third));
|
|
57
|
+
// fc00::/7 unique-local, fe80::/10 link-local, fec0::/10 site-local, ff00::/8 multicast.
|
|
58
|
+
return (first & 0xfe00) === 0xfc00 || (first & 0xffc0) === 0xfe80 || (first & 0xffc0) === 0xfec0 || (first & 0xff00) === 0xff00;
|
|
59
|
+
}
|
|
60
|
+
/** Whether an address is one `web fetch` must not reach; something that isn't an address counts as one. */
|
|
61
|
+
export function isPrivateAddress(address) {
|
|
62
|
+
const kind = isIP(address);
|
|
63
|
+
if (kind === 4)
|
|
64
|
+
return privateV4(v4Number(address));
|
|
65
|
+
if (kind === 6)
|
|
66
|
+
return privateV6(address.split('%')[0] ?? address);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=private-address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-address.js","sourceRoot":"","sources":["../../src/web-fetch/private-address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,oHAAoH;AACpH,oHAAoH;AACpH,0FAA0F;AAE1F,MAAM,QAAQ,GAAgC;IAC5C,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,yBAAyB;IAC1C,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,OAAO;IACxB,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,oBAAoB;IACtC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,kBAAkB;IACnC,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,yBAAyB;IAC3C,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,YAAY;IAC9B,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,aAAa;IAC/B,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,mBAAmB;IACpC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,kBAAkB;CACpC,CAAC;AAEF,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AACvH,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,sGAAsG;AACtG,SAAS,OAAO,CAAC,OAAe;IAC9B,MAAM,MAAM,GAAG,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IAC/I,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAwB,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAClM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACxE,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,CAAS,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IAC5F,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;AAClD,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,GAAW,EAAE,EAAE,CAAC,IAAI,GAAG,OAAO,GAAG,GAAG,CAAC;AACjE,MAAM,KAAK,GAAG,CAAC,MAAyB,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;AAElF,SAAS,SAAS,CAAC,OAAe;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,AAAD,EAAG,AAAD,EAAG,KAAK,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IAC1F,mGAAmG;IACnG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3F,4FAA4F;IAC5F,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9G,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,sCAAsC;IAC3G,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5D,yFAAyF;IACzF,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,MAAM,CAAC;AAClI,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACpD,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RunCall } from '../calls/run-tool.ts';
|
|
2
|
+
import type { TxRecords } from '../store/collections.ts';
|
|
3
|
+
/** The host a `web fetch` call names, lowercase, or nothing for another call or an address that doesn't parse. */
|
|
4
|
+
export declare function hostOf(call: RunCall): string | undefined;
|
|
5
|
+
/** Adds the host of an allowed `web fetch` to the chat at the root, in the transaction that applies the answer. */
|
|
6
|
+
export declare function allowHostInTx(store: TxRecords, sessionId: string, call: RunCall): void;
|
|
7
|
+
//# sourceMappingURL=web-hosts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-hosts.d.ts","sourceRoot":"","sources":["../../src/web-fetch/web-hosts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAKzD,kHAAkH;AAClH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIxD;AAED,mHAAmH;AACnH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAKtF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { executionRootInTx } from "../sessions/execution-root.js";
|
|
2
|
+
// The hosts a chat let `web fetch` reach (plan 08 §8.5, ADR 0095, 4): the first fetch from a host asks, and an allowed
|
|
3
|
+
// one is kept on the chat at the root, so its helpers share it.
|
|
4
|
+
/** The host a `web fetch` call names, lowercase, or nothing for another call or an address that doesn't parse. */
|
|
5
|
+
export function hostOf(call) {
|
|
6
|
+
if (call.connector !== 'web' || call.command !== 'fetch')
|
|
7
|
+
return undefined;
|
|
8
|
+
const given = call.payload['url'];
|
|
9
|
+
return typeof given === 'string' && URL.canParse(given) ? new URL(given).hostname.toLowerCase() : undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Adds the host of an allowed `web fetch` to the chat at the root, in the transaction that applies the answer. */
|
|
12
|
+
export function allowHostInTx(store, sessionId, call) {
|
|
13
|
+
const host = hostOf(call);
|
|
14
|
+
const root = executionRootInTx(store, sessionId);
|
|
15
|
+
if (host === undefined || root === undefined || root.webHosts.includes(host))
|
|
16
|
+
return;
|
|
17
|
+
store.sessions.update(root.id, { webHosts: [...root.webHosts, host] });
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=web-hosts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-hosts.js","sourceRoot":"","sources":["../../src/web-fetch/web-hosts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,uHAAuH;AACvH,gEAAgE;AAEhE,kHAAkH;AAClH,MAAM,UAAU,MAAM,CAAC,IAAa;IAClC,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9G,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,aAAa,CAAC,KAAgB,EAAE,SAAiB,EAAE,IAAa;IAC9E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACjD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO;IACrF,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC"}
|
package/docs/connectors.md
CHANGED
|
@@ -36,7 +36,7 @@ ctx.registerHandler('kernel.started', {
|
|
|
36
36
|
- `commands`: each command's `name`, the public `command` it runs, and optional `examples` (`{ description, input }`). `help` shows the registered descriptions, JSON Schemas, and examples, so give every input field a `.describe()`.
|
|
37
37
|
- `asks: true` on a command makes the person approve every call of it first (see **A command that asks** below). The field takes only `true`; leave it out for a command that runs at once.
|
|
38
38
|
- Each `command` must be a public command or query of the registering extension, or registration fails `VALIDATION_FAILED`. The command runs through `ctx.exec` with the payload as its input, so validation, cancel, and timeouts are the kernel's, and it runs to its end inside the agent's step.
|
|
39
|
-
- The result the agent reads is the output as JSON on one line, or `error <code>: <message>`. A payload that doesn't fit returns each problem and then the payload's signature, such as `{ text, done? }`, so the agent can correct it in one try; a payload that isn't a plain object returns its JSON Schema on one line instead.
|
|
39
|
+
- The result the agent reads is the output as JSON on one line, or `error <code>: <message>`. A payload that doesn't fit returns each problem and then the payload's signature, such as `{ text (≤200), done? }`, where `(≤N)` is a string's `max` length from your zod schema, so the agent can correct it in one try; a payload that isn't a plain object returns its JSON Schema on one line instead.
|
|
40
40
|
- `binary`: a program on the system, with `{ check, install?, help? }`. `check` is a line whose exit code 0 means the program is usable; the connector is listed, and can be called, only while its check passes.
|
|
41
41
|
|
|
42
42
|
## A command that asks
|
|
@@ -101,7 +101,7 @@ Register a connector with `optIn: true`, the only value the field takes, when it
|
|
|
101
101
|
|
|
102
102
|
## Built-in connectors
|
|
103
103
|
|
|
104
|
-
kvcoder's own connectors are `shell` (one line in the real shell), `fs` (read, list, search, write, and edit files in the workspace folder), `artifact` (a document shown beside the chat), `background` (follow up on what was started with `background: true`), `ask` (a question that suspends the turn), `delegate` (`delegate run { worker, title, task, background? }` hands a task to a worker, which runs it in a helper session, and `delegate continue { id, message, background? }` sends a follow-up to a helper that has ended, which goes on with its own history; the workers are the setting `kvcoder.delegate.workers`, and it is a connector of a session only while a worker is turned on), and `mcp` (the tools of the MCP servers the person added; it is a connector of a session only while the workspace has a server). Their names are taken: registering one fails `kvcoder/NAME_TAKEN`.
|
|
104
|
+
kvcoder's own connectors are `shell` (one line in the real shell), `fs` (read, list, find, search, write, and edit files in the workspace folder; `read-files` reads several files in one call, and the model reads a file as numbered lines), `artifact` (a document shown beside the chat), `background` (follow up on what was started with `background: true`), `ask` (a question that suspends the turn), `delegate` (`delegate run { worker, title, task, background? }` hands a task to a worker, which runs it in a helper session, and `delegate continue { id, message, background? }` sends a follow-up to a helper that has ended, which goes on with its own history; the workers are the setting `kvcoder.delegate.workers`, and it is a connector of a session only while a worker is turned on), and `mcp` (the tools of the MCP servers the person added; it is a connector of a session only while the workspace has a server). Their names are taken: registering one fails `kvcoder/NAME_TAKEN`.
|
|
105
105
|
|
|
106
106
|
`shell exec`, a binary's `exec`, `fs write`, `fs edit`, and `mcp call` ask the person first when the payload says `risky: true`, or always when `kvcoder.approval` is `ask`, and never when it is `never`. A registered command asks only when its entry has `asks: true`, and then always, except on `never`. `risky` is required: a call that leaves it out fails `VALIDATION_FAILED` and asks nobody. Only `shell exec`, a binary's `exec`, `delegate run`, and `delegate continue` take `background: true`; every other command runs to its end. A background helper's approvals show in the chat, and while it waits on the person its status is `waiting`.
|
|
107
107
|
|
package/locales/ar.json
CHANGED
|
@@ -15,20 +15,38 @@
|
|
|
15
15
|
"kvcoder.errors.JOB_NOT_FOUND": "لا توجد في هذه المحادثة مهمة خلفية بهذا المعرّف.",
|
|
16
16
|
"kvcoder.errors.MCP_SERVER_NOT_FOUND": "لا يوجد خادم MCP باسم {server}.",
|
|
17
17
|
"kvcoder.errors.WORKER_NOT_FOUND": "لا يوجد مساعد باسم {worker}.",
|
|
18
|
+
"kvcoder.errors.WEB_FAILED": "تعذّرت قراءة {url}.",
|
|
18
19
|
"kvcoder.errors.MCP_CONNECT_FAILED": "فشل خادم MCP {server}: {reason}",
|
|
19
20
|
"kvcoder.errors.MCP_SIGN_IN_NEEDED": "خادم MCP {server} يحتاج إلى تسجيل دخولك.",
|
|
20
21
|
"kvcoder.errors.MCP_SIGN_IN_FAILED": "لم ينجح تسجيل الدخول: {reason}",
|
|
21
22
|
"kvcoder.notices.CANCELLED": "أوقفتَ هذه الجولة.",
|
|
22
23
|
"kvcoder.notices.INTERRUPTED": "انقطعت هذه الجولة. قد تكون آثارها غير معروفة؛ لن تُعاد الخطوة القديمة تلقائيًا. أرسل رسالة جديدة للمتابعة.",
|
|
23
24
|
"kvcoder.notices.STEP_FAILED": "توقفت الجولة: {error}",
|
|
25
|
+
"kvcoder.notices.MODEL_SWITCHED": "بلغ {from} حده، فانتقلت هذه المحادثة إلى النموذج البديل {to}.",
|
|
24
26
|
"kvcoder.notices.MAX_STEPS": "توقفت الجولة بعد بلوغ الحد الأقصى للخطوات ({steps}).",
|
|
25
27
|
"kvcoder.notices.SUMMARY_FAILED": "تعذّر تلخيص الرسائل السابقة: {error}",
|
|
26
28
|
"kvcoder.notices.REPLY_LOST": "لم يصل رد النموذج كاملًا بعد عدة محاولات (ضاع نحو {tokens} توكن). اكتب «تابع» للمحاولة من جديد، أو اختر نموذجًا آخر.",
|
|
27
29
|
"kvcoder.notices.REPLY_INCOMPLETE": "جاء رد النموذج فارغًا أو مقطوعًا عند حد الطول مرتين متتاليتين. أعد المحاولة، أو اختر نموذجًا آخر.",
|
|
28
30
|
"kvcoder.ui.newChat": "محادثة جديدة",
|
|
31
|
+
"kvcoder.ui.changes.title": "التغييرات",
|
|
32
|
+
"kvcoder.ui.changes.toggle": "التغييرات ({count})",
|
|
33
|
+
"kvcoder.ui.changes.loading": "جارٍ قراءة التغييرات…",
|
|
34
|
+
"kvcoder.ui.changes.note": "الملفات التي غيّرتها هذه المحادثة، مقارنةً بآخر حفظ أو بالنسخة التي احتفظت بها. تغييرات أسطر الطرفية لا تظهر هنا.",
|
|
35
|
+
"kvcoder.ui.changes.noGit": "تعذّر تشغيل Git، فتظهر التغييرات بلا فروقها. تغييرات أسطر الطرفية لا تظهر هنا.",
|
|
36
|
+
"kvcoder.ui.changes.commit": "احفظ في Git",
|
|
37
|
+
"kvcoder.ui.changes.commitMessage": "احفظ هذه التغييرات في Git.",
|
|
38
|
+
"kvcoder.ui.changes.undo": "تراجع",
|
|
39
|
+
"kvcoder.ui.changes.none": "لم يبقَ أي تغيير.",
|
|
40
|
+
"kvcoder.ui.changes.state.changed": "مُعدَّل",
|
|
41
|
+
"kvcoder.ui.changes.state.created": "جديد",
|
|
42
|
+
"kvcoder.ui.changes.state.deleted": "محذوف",
|
|
29
43
|
"kvcoder.ui.chats": "المحادثات",
|
|
30
44
|
"kvcoder.ui.today": "اليوم",
|
|
31
45
|
"kvcoder.ui.earlier": "الأقدم",
|
|
46
|
+
"kvcoder.ui.notify.title": "محادثة تحتاجك",
|
|
47
|
+
"kvcoder.ui.notify.ask": "احصل على تنبيه عندما تحتاجك محادثة وkvman في الخلفية.",
|
|
48
|
+
"kvcoder.ui.notify.on": "تفعيل",
|
|
49
|
+
"kvcoder.ui.notify.later": "ليس الآن",
|
|
32
50
|
"kvcoder.ui.needsYou": "بانتظار ردّك",
|
|
33
51
|
"kvcoder.ui.status.idle": "جاهزة",
|
|
34
52
|
"kvcoder.ui.status.running": "قيد العمل…",
|
|
@@ -73,6 +91,11 @@
|
|
|
73
91
|
"kvcoder.ui.no": "لا",
|
|
74
92
|
"kvcoder.ui.allowCommands": "هل تسمح بتنفيذ هذه الأوامر؟ ({count})",
|
|
75
93
|
"kvcoder.ui.allow": "سماح",
|
|
94
|
+
"kvcoder.ui.approval.denyWhy": "ارفض واذكر السبب…",
|
|
95
|
+
"kvcoder.ui.approval.reason": "ماذا يفعل الوكيل بدلًا من ذلك؟",
|
|
96
|
+
"kvcoder.ui.approval.alwaysLine": "اسمح دائمًا بالأسطر التي تبدأ بـ",
|
|
97
|
+
"kvcoder.ui.approval.always": "اسمح دائمًا",
|
|
98
|
+
"kvcoder.ui.approval.alwaysFiles": "اسمح دائمًا بتغيير الملفات هنا",
|
|
76
99
|
"kvcoder.ui.deny": "رفض",
|
|
77
100
|
"kvcoder.ui.allowAll": "سماح للكل",
|
|
78
101
|
"kvcoder.ui.denyAll": "رفض الكل",
|
|
@@ -141,6 +164,8 @@
|
|
|
141
164
|
"kvcoder.ui.reach.session": "هذه المحادثة",
|
|
142
165
|
"kvcoder.ui.leftOut": "مستبعد: يتجاوز 64 كيلوبايت",
|
|
143
166
|
"kvcoder.ui.model": "النموذج",
|
|
167
|
+
"kvcoder.ui.decideForMe": "قرّر عني",
|
|
168
|
+
"kvcoder.ui.decideForMeHint": "يتخذ الوكيل كل قرار بنفسه، بالخيار الذي يوصي به، ولا يسألك أسئلة في هذه المحادثة. طلبات الموافقة تبقى كما هي.",
|
|
144
169
|
"kvcoder.ui.thinking": "التفكير",
|
|
145
170
|
"kvcoder.ui.thinkingLevels.off": "بدون",
|
|
146
171
|
"kvcoder.ui.thinkingLevels.minimal": "أدنى",
|
|
@@ -182,7 +207,11 @@
|
|
|
182
207
|
"kvcoder.shell.run.description": "ينفّذ سطرًا واحدًا في الطرفية الفعلية، داخل مجلد مساحة العمل.",
|
|
183
208
|
"kvcoder.binary.run.description": "يشغّل البرنامج بالوسائط المعطاة في الطرفية الفعلية، داخل مجلد مساحة العمل.",
|
|
184
209
|
"kvcoder.fs.file.get.description": "يقرأ أسطرًا من ملف نصي.",
|
|
210
|
+
"kvcoder.fs.files.get.description": "يقرأ عدة ملفات نصية في استدعاء واحد، بالترتيب، كلًّا كما يقرؤه read.",
|
|
211
|
+
"kvcoder.change.list.description": "يسرد الملفات التي غيّرتها محادثة عبر fs، الأحدث أولًا، مع فرق كل منها.",
|
|
212
|
+
"kvcoder.change.undo.description": "يتراجع عن آخر تغيير أجرته المحادثة على ملف، كما يفعل fs undo؛ للشخص.",
|
|
185
213
|
"kvcoder.fs.entry.list.description": "يسرد ملفات ومجلدات مجلد واحد.",
|
|
214
|
+
"kvcoder.fs.path.list.description": "يجد الملفات التي يطابق مسارها نمطًا، داخل مجلد، الأحدث أولًا.",
|
|
186
215
|
"kvcoder.fs.text.search.description": "يجد الأسطر التي تطابق تعبيرًا نمطيًا، في ملف أو داخل مجلد.",
|
|
187
216
|
"kvcoder.fs.write.description": "ينشئ ملفًا مع مجلداته الأصلية، أو يستبدل محتوى الملف.",
|
|
188
217
|
"kvcoder.fs.edit.description": "يستبدل مقاطع نصية محددة في ملف موجود؛ وإذا فشل أحد الاستبدالات لا يُكتب شيء.",
|
|
@@ -202,6 +231,7 @@
|
|
|
202
231
|
"kvcoder.background.wait.description": "ينتظر حتى تنتهي عملية في الخلفية أو ينقضي الوقت، ثم يعطي حالتها ومخرجاتها كما يفعل output.",
|
|
203
232
|
"kvcoder.background.stop.description": "يوقف عملية في الخلفية أو تشغيل برنامج مساعد، أو يلغي وكيلًا فرعيًا في الخلفية.",
|
|
204
233
|
"kvcoder.mcp.tool.describe.description": "يسرد أدوات خادم MCP، أو يعطي وصف أداة واحدة ومُدخلاتها.",
|
|
234
|
+
"kvcoder.web.page.get.description": "يقرأ صفحة على الويب بصيغة Markdown أو نصًا.",
|
|
205
235
|
"kvcoder.mcp.tool.call.description": "يستدعي أداة من خادم MCP ويعيد نصّها.",
|
|
206
236
|
"kvcoder.mcp.steps.run.description": "يستدعي عدة أدوات من خادم MCP على اتصال واحد بالترتيب، فيحتفظ الخادم بحالته بينها، ويتوقف عند أول أداة تُبلغ عن خطأ.",
|
|
207
237
|
"kvcoder.mcp.server.check.description": "يتصل بخادم MCP ويخبر هل هو جاهز، أم يحتاج إلى تسجيل دخول، أم فشل.",
|
|
@@ -241,8 +271,26 @@
|
|
|
241
271
|
"kvcoder.thinking.description": "مقدار تفكير النموذج في المحادثة الجديدة.",
|
|
242
272
|
"kvcoder.maxSteps.title": "الخطوات في كل جولة",
|
|
243
273
|
"kvcoder.maxSteps.description": "أقصى عدد من الخطوات تنفّذه الجولة قبل أن تتوقف. اتركه فارغًا لتبقى الجولة بلا حدّ.",
|
|
274
|
+
"kvcoder.preferences.title": "تفضيلاتك",
|
|
275
|
+
"kvcoder.preferences.description": "ما يجب أن تعرفه كل محادثة عن طريقتك في العمل، مثل لغة تطبيقاتك أو ألا يسألك الوكيل. يقرؤها الوكيل في كل محادثة.",
|
|
276
|
+
"kvcoder.config.preferences.placeholder": "ابنِ التطبيقات بالعربية أولًا.\nلا تطلب مني الاختيار: اختر ما توصي به.",
|
|
277
|
+
"kvcoder.config.preferences.save": "حفظ",
|
|
278
|
+
"kvcoder.ui.remember.this": "تذكّر هذا",
|
|
279
|
+
"kvcoder.ui.remember.question": "أتضيف هذا إلى تفضيلاتك؟ كل محادثة تقرؤها.",
|
|
280
|
+
"kvcoder.ui.remember.add": "أضف",
|
|
281
|
+
"kvcoder.ui.remember.added": "أُضيف إلى تفضيلاتك.",
|
|
282
|
+
"kvcoder.check.title": "فحص بعد التغييرات",
|
|
283
|
+
"kvcoder.check.description": "سطر يشغّله kvman بعد أن يغيّر الوكيل ملفات، مثل فحص الأنواع في المشروع؛ تُضاف نتيجته ومخرجاته إلى التغيير ليرى الوكيل الخطأ فورًا. فارغ لعدم التشغيل.",
|
|
284
|
+
"kvcoder.fallbackModel.title": "نموذج بديل",
|
|
285
|
+
"kvcoder.fallbackModel.description": "النموذج الذي تنتقل إليه المحادثة عندما يبلغ نموذجها حد الاستخدام، أو حد الطلبات بعد كل المحاولات. فارغ لعدم الانتقال.",
|
|
244
286
|
"kvcoder.approval.title": "الموافقة",
|
|
245
287
|
"kvcoder.approval.description": "متى يطلب الوكيل موافقتك قبل تنفيذ أمر أو تعديل ملف أو أي شيء آخر يحتاج إلى إذنك.",
|
|
288
|
+
"kvcoder.approval.allowed.title": "مسموح دائمًا",
|
|
289
|
+
"kvcoder.approval.allowed.description": "أوامر وتغييرات تعمل دون سؤالك: سطر يبدأ كل أمر فيه بأحد هذه البدايات، أو تغيير ملف في هذا المجلد.",
|
|
290
|
+
"kvcoder.config.approval.rules.line": "مسموح دائمًا: {prefix} …",
|
|
291
|
+
"kvcoder.config.approval.rules.files": "مسموح دائمًا: تغيير الملفات",
|
|
292
|
+
"kvcoder.config.approval.rules.none": "لا توجد أوامر مسموحة دائمًا.",
|
|
293
|
+
"kvcoder.config.approval.rules.remove": "إزالة",
|
|
246
294
|
"kvcoder.config.approval.never.title": "عدم السؤال قبل أي عملية؟",
|
|
247
295
|
"kvcoder.config.approval.never.text": "سينفّذ الوكيل الأوامر ويعدّل الملفات ويغيّر kvman نفسه ويشغّل برامج المساعدين دون أن يسألك. وما يقرؤه قد يوجّهه.",
|
|
248
296
|
"kvcoder.config.approval.never.confirm": "أوقف السؤال",
|
|
@@ -308,6 +356,8 @@
|
|
|
308
356
|
"kvcoder.ui.map.note": "ملاحظة",
|
|
309
357
|
"kvcoder.ui.map.noted": "مؤجَّل لوقت لاحق ({count})",
|
|
310
358
|
"kvcoder.ui.map.remaining": "{count} من خطوات خريطة التنفيذ لم تُنجز.",
|
|
359
|
+
"kvcoder.ui.map.continue": "تابع",
|
|
360
|
+
"kvcoder.ui.map.continueMessage": "تابع.",
|
|
311
361
|
"kvcoder.ui.map.show": "عرض الخريطة",
|
|
312
362
|
"kvcoder.ui.map.close": "إغلاق",
|
|
313
363
|
"kvcoder.ui.artifacts.frameLabel": "معاينة {title}",
|
|
@@ -346,6 +396,7 @@
|
|
|
346
396
|
"kvcoder.config.connector.background": "يسرد ما يعمل في الخلفية ويقرأ ناتجه ويوقفه.",
|
|
347
397
|
"kvcoder.config.connector.ask": "يطرح عليك سؤالًا وينتظر إجابتك.",
|
|
348
398
|
"kvcoder.config.connector.delegate": "يسند جزءًا من المهمة إلى مساعد: وكيل آخر له تعليماته.",
|
|
399
|
+
"kvcoder.config.connector.web": "يقرأ صفحات على الويب، مثل التوثيق الحالي، ويسألك قبل أول صفحة من كل موقع.",
|
|
349
400
|
"kvcoder.config.connector.mcp": "يستخدم أدوات خوادم MCP التي تضيفها.",
|
|
350
401
|
"kvcoder.config.connectors.use": "استخدام {name}",
|
|
351
402
|
"kvcoder.config.connectors.configure": "إعداد {name}",
|
|
@@ -498,6 +549,7 @@
|
|
|
498
549
|
"kvcoder.config.model.reset.workspace": "استخدام قيمة كل مساحات العمل",
|
|
499
550
|
"kvcoder.config.model.ownValue": "لمساحة العمل {name} قيمة خاصة بها. انتقل إلى {name} لتغييرها.",
|
|
500
551
|
"kvcoder.ui.milliseconds": "{count} مللي ث",
|
|
552
|
+
"kvcoder.ui.hoursMinutes": "{hours} س {minutes} د",
|
|
501
553
|
"kvcoder.ui.minutesSeconds": "{minutes} د {seconds} ث",
|
|
502
554
|
"kvcoder.ui.callFailed": "فشل",
|
|
503
555
|
"kvcoder.ui.callParts": "كُتب في {written} · نُفّذ في {ran}",
|
|
@@ -506,6 +558,18 @@
|
|
|
506
558
|
"kvcoder.ui.call.write": "كتابة",
|
|
507
559
|
"kvcoder.ui.call.read": "قراءة",
|
|
508
560
|
"kvcoder.ui.call.list": "عرض",
|
|
561
|
+
"kvcoder.ui.fold.read": "قراءة {count}",
|
|
562
|
+
"kvcoder.ui.fold.searched": "بحث {count}",
|
|
563
|
+
"kvcoder.ui.fold.changed": "تغيير {count}",
|
|
564
|
+
"kvcoder.ui.fold.ran": "تشغيل {count}",
|
|
565
|
+
"kvcoder.ui.fold.other": "أخرى {count}",
|
|
566
|
+
"kvcoder.ui.fold.failed": "فشل {count}",
|
|
567
|
+
"kvcoder.ui.call.fetch": "جلب",
|
|
568
|
+
"kvcoder.ui.call.find": "إيجاد",
|
|
569
|
+
"kvcoder.ui.call.files": "{count} ملف",
|
|
570
|
+
"kvcoder.ui.call.fileNotRead": "لم يُقرأ: استهلكت الملفات التي قبله حدّ هذا الاستدعاء (30 KB).",
|
|
571
|
+
"kvcoder.ui.call.fileUnchanged": "لم يتغيّر منذ قراءة سابقة في هذه المحادثة.",
|
|
572
|
+
"kvcoder.ui.call.filesFirst": "أول {count} ملف",
|
|
509
573
|
"kvcoder.ui.call.search": "بحث",
|
|
510
574
|
"kvcoder.ui.call.tools": "الأدوات",
|
|
511
575
|
"kvcoder.ui.call.delegate": "تفويض",
|
|
@@ -527,6 +591,7 @@
|
|
|
527
591
|
"kvcoder.ui.call.lines": "الأسطر {from}–{to} من {total}",
|
|
528
592
|
"kvcoder.ui.call.entries": "{count} عنصر",
|
|
529
593
|
"kvcoder.ui.call.entriesFirst": "أول {count} عنصر",
|
|
594
|
+
"kvcoder.ui.call.matchCount": "النتائج: {count}",
|
|
530
595
|
"kvcoder.ui.call.matches": "{matches} نتيجة في {files} ملف",
|
|
531
596
|
"kvcoder.ui.call.matchesFirst": "أول {matches} نتيجة في {files} ملف",
|
|
532
597
|
"kvcoder.ui.call.toolCount": "{count} أداة",
|
|
@@ -535,7 +600,7 @@
|
|
|
535
600
|
"kvcoder.ui.call.kilobytes": "{count} ك.ب",
|
|
536
601
|
"kvcoder.ui.call.megabytes": "{count} م.ب",
|
|
537
602
|
"kvcoder.ui.call.risky": "خطِر",
|
|
538
|
-
"kvcoder.ui.call.replacements": "{count}
|
|
603
|
+
"kvcoder.ui.call.replacements": "الاستبدالات: {count} · من السطر {line}",
|
|
539
604
|
"kvcoder.ui.call.showAll": "عرض كل الأسطر ({count})",
|
|
540
605
|
"kvcoder.ui.call.showFewer": "عرض أقل",
|
|
541
606
|
"kvcoder.ui.call.error": "الخطأ",
|
package/locales/en.json
CHANGED
|
@@ -15,20 +15,38 @@
|
|
|
15
15
|
"kvcoder.errors.JOB_NOT_FOUND": "This chat started no such background job.",
|
|
16
16
|
"kvcoder.errors.MCP_SERVER_NOT_FOUND": "There is no MCP server named {server}.",
|
|
17
17
|
"kvcoder.errors.WORKER_NOT_FOUND": "There is no worker named {worker}.",
|
|
18
|
+
"kvcoder.errors.WEB_FAILED": "{url} couldn't be read.",
|
|
18
19
|
"kvcoder.errors.MCP_CONNECT_FAILED": "The MCP server {server} failed: {reason}",
|
|
19
20
|
"kvcoder.errors.MCP_SIGN_IN_NEEDED": "The MCP server {server} needs you to sign in.",
|
|
20
21
|
"kvcoder.errors.MCP_SIGN_IN_FAILED": "The sign-in didn't work: {reason}",
|
|
21
22
|
"kvcoder.notices.CANCELLED": "You stopped this turn.",
|
|
22
23
|
"kvcoder.notices.INTERRUPTED": "This turn was interrupted. Its effects may be unknown; the old step will not be replayed automatically. Send a new message to continue.",
|
|
23
24
|
"kvcoder.notices.STEP_FAILED": "The turn stopped: {error}",
|
|
25
|
+
"kvcoder.notices.MODEL_SWITCHED": "{from} reached its limit, so this chat moved to the fallback model {to}.",
|
|
24
26
|
"kvcoder.notices.MAX_STEPS": "The turn stopped after {steps} steps.",
|
|
25
27
|
"kvcoder.notices.SUMMARY_FAILED": "The earlier messages couldn't be summarized: {error}",
|
|
26
28
|
"kvcoder.notices.REPLY_LOST": "The model's reply was lost on the way, again and again (about {tokens} tokens never arrived). Say continue to try again, or choose another model.",
|
|
27
29
|
"kvcoder.notices.REPLY_INCOMPLETE": "The model's reply was empty or cut off at its length limit, twice in a row. Retry, or choose another model.",
|
|
28
30
|
"kvcoder.ui.newChat": "New chat",
|
|
31
|
+
"kvcoder.ui.changes.title": "Changes",
|
|
32
|
+
"kvcoder.ui.changes.toggle": "Changes ({count})",
|
|
33
|
+
"kvcoder.ui.changes.loading": "Reading the changes…",
|
|
34
|
+
"kvcoder.ui.changes.note": "The files this chat changed, against the last commit or the copy it kept. Changes made by shell lines aren't listed.",
|
|
35
|
+
"kvcoder.ui.changes.noGit": "Git couldn't be run, so the changes are listed without their diffs. Changes made by shell lines aren't listed.",
|
|
36
|
+
"kvcoder.ui.changes.commit": "Commit",
|
|
37
|
+
"kvcoder.ui.changes.commitMessage": "Commit these changes.",
|
|
38
|
+
"kvcoder.ui.changes.undo": "Undo",
|
|
39
|
+
"kvcoder.ui.changes.none": "No changes are left.",
|
|
40
|
+
"kvcoder.ui.changes.state.changed": "Changed",
|
|
41
|
+
"kvcoder.ui.changes.state.created": "New",
|
|
42
|
+
"kvcoder.ui.changes.state.deleted": "Deleted",
|
|
29
43
|
"kvcoder.ui.chats": "Chats",
|
|
30
44
|
"kvcoder.ui.today": "Today",
|
|
31
45
|
"kvcoder.ui.earlier": "Earlier",
|
|
46
|
+
"kvcoder.ui.notify.title": "A chat needs you",
|
|
47
|
+
"kvcoder.ui.notify.ask": "Get a notice when a chat needs you while kvman is in the background.",
|
|
48
|
+
"kvcoder.ui.notify.on": "Turn on",
|
|
49
|
+
"kvcoder.ui.notify.later": "Not now",
|
|
32
50
|
"kvcoder.ui.needsYou": "Needs you",
|
|
33
51
|
"kvcoder.ui.status.idle": "Idle",
|
|
34
52
|
"kvcoder.ui.status.running": "Working…",
|
|
@@ -73,6 +91,11 @@
|
|
|
73
91
|
"kvcoder.ui.no": "No",
|
|
74
92
|
"kvcoder.ui.allowCommands": "Allow these commands? ({count})",
|
|
75
93
|
"kvcoder.ui.allow": "Allow",
|
|
94
|
+
"kvcoder.ui.approval.denyWhy": "Deny and say why…",
|
|
95
|
+
"kvcoder.ui.approval.reason": "What should the agent do instead?",
|
|
96
|
+
"kvcoder.ui.approval.alwaysLine": "Always allow lines that start with",
|
|
97
|
+
"kvcoder.ui.approval.always": "Always allow",
|
|
98
|
+
"kvcoder.ui.approval.alwaysFiles": "Always allow file changes here",
|
|
76
99
|
"kvcoder.ui.deny": "Deny",
|
|
77
100
|
"kvcoder.ui.allowAll": "Allow all",
|
|
78
101
|
"kvcoder.ui.denyAll": "Deny all",
|
|
@@ -141,6 +164,8 @@
|
|
|
141
164
|
"kvcoder.ui.reach.session": "this chat",
|
|
142
165
|
"kvcoder.ui.leftOut": "Left out: over 64 KB",
|
|
143
166
|
"kvcoder.ui.model": "Model",
|
|
167
|
+
"kvcoder.ui.decideForMe": "Decide for me",
|
|
168
|
+
"kvcoder.ui.decideForMeHint": "The agent makes each choice itself, the one it recommends, and asks you no questions in this chat. Approvals still ask.",
|
|
144
169
|
"kvcoder.ui.thinking": "Thinking",
|
|
145
170
|
"kvcoder.ui.thinkingLevels.off": "Off",
|
|
146
171
|
"kvcoder.ui.thinkingLevels.minimal": "Minimal",
|
|
@@ -182,7 +207,11 @@
|
|
|
182
207
|
"kvcoder.shell.run.description": "Runs one line in the real shell, in the workspace folder.",
|
|
183
208
|
"kvcoder.binary.run.description": "Runs the program with the given arguments in the real shell, in the workspace folder.",
|
|
184
209
|
"kvcoder.fs.file.get.description": "Reads lines of a text file.",
|
|
210
|
+
"kvcoder.fs.files.get.description": "Reads several text files in one call, in order, each as read reads it.",
|
|
211
|
+
"kvcoder.change.list.description": "Lists the files a chat changed with fs, newest first, each with its diff.",
|
|
212
|
+
"kvcoder.change.undo.description": "Takes back the chat's latest change to a file, as fs undo does; for the person.",
|
|
185
213
|
"kvcoder.fs.entry.list.description": "Lists the files and folders of one folder.",
|
|
214
|
+
"kvcoder.fs.path.list.description": "Finds the files whose path matches a glob, under a folder, newest first.",
|
|
186
215
|
"kvcoder.fs.text.search.description": "Finds the lines that match a regular expression, in a file or under a folder.",
|
|
187
216
|
"kvcoder.fs.write.description": "Creates a file and its parent folders, or replaces the file.",
|
|
188
217
|
"kvcoder.fs.edit.description": "Replaces exact pieces of text in an existing file; if one replacement fails, nothing is written.",
|
|
@@ -202,6 +231,7 @@
|
|
|
202
231
|
"kvcoder.background.wait.description": "Waits until a background run ends or the time passes, then gives its status and output as output does.",
|
|
203
232
|
"kvcoder.background.stop.description": "Stops a background process or a program worker's run, or cancels a background subagent.",
|
|
204
233
|
"kvcoder.mcp.tool.describe.description": "Lists an MCP server's tools, or gives one tool's description and arguments.",
|
|
234
|
+
"kvcoder.web.page.get.description": "Reads a page on the web as Markdown or text.",
|
|
205
235
|
"kvcoder.mcp.tool.call.description": "Calls one tool of an MCP server and returns the tool's text.",
|
|
206
236
|
"kvcoder.mcp.steps.run.description": "Calls several tools of an MCP server on one connection, in order, so the server keeps its state between them; stops at the first tool that reports an error.",
|
|
207
237
|
"kvcoder.mcp.server.check.description": "Connects to one MCP server and says whether it is ready, needs a sign-in, or failed.",
|
|
@@ -241,8 +271,26 @@
|
|
|
241
271
|
"kvcoder.thinking.description": "How hard the model thinks in a new chat.",
|
|
242
272
|
"kvcoder.maxSteps.title": "Steps per turn",
|
|
243
273
|
"kvcoder.maxSteps.description": "The most steps a turn takes before it stops. Leave it empty for no limit.",
|
|
274
|
+
"kvcoder.preferences.title": "Your preferences",
|
|
275
|
+
"kvcoder.preferences.description": "What every chat should know about how you like to work, such as the language of your apps or that the agent should not ask. The agent reads it in every chat.",
|
|
276
|
+
"kvcoder.config.preferences.placeholder": "Build apps in Arabic first.\nDon't ask me to choose: pick what you recommend.",
|
|
277
|
+
"kvcoder.config.preferences.save": "Save",
|
|
278
|
+
"kvcoder.ui.remember.this": "Remember this",
|
|
279
|
+
"kvcoder.ui.remember.question": "Add this to your preferences? Every chat reads them.",
|
|
280
|
+
"kvcoder.ui.remember.add": "Add",
|
|
281
|
+
"kvcoder.ui.remember.added": "Added to your preferences.",
|
|
282
|
+
"kvcoder.check.title": "Check after changes",
|
|
283
|
+
"kvcoder.check.description": "A line kvman runs after the agent changes files, such as the project's type check; its exit code and output are added to the change, so the agent sees an error at once. Empty for none.",
|
|
284
|
+
"kvcoder.fallbackModel.title": "Fallback model",
|
|
285
|
+
"kvcoder.fallbackModel.description": "The model a chat moves to when its model reaches a usage limit, or a rate limit after all tries. Empty for none.",
|
|
244
286
|
"kvcoder.approval.title": "Approval",
|
|
245
287
|
"kvcoder.approval.description": "When the agent asks you before it runs a command, changes a file, or does anything else that needs your go-ahead.",
|
|
288
|
+
"kvcoder.approval.allowed.title": "Always allowed",
|
|
289
|
+
"kvcoder.approval.allowed.description": "Commands and changes that run without asking: a line whose every command starts with one of these, or a file change in this folder.",
|
|
290
|
+
"kvcoder.config.approval.rules.line": "Always allowed: {prefix} …",
|
|
291
|
+
"kvcoder.config.approval.rules.files": "Always allowed: file changes",
|
|
292
|
+
"kvcoder.config.approval.rules.none": "No commands are always allowed.",
|
|
293
|
+
"kvcoder.config.approval.rules.remove": "Remove",
|
|
246
294
|
"kvcoder.config.approval.never.title": "Never ask before a call?",
|
|
247
295
|
"kvcoder.config.approval.never.text": "The agent will run commands, change files, change kvman itself, and start worker programs without asking you. What it reads can steer it.",
|
|
248
296
|
"kvcoder.config.approval.never.confirm": "Turn off asking",
|
|
@@ -308,6 +356,8 @@
|
|
|
308
356
|
"kvcoder.ui.map.note": "Note",
|
|
309
357
|
"kvcoder.ui.map.noted": "Noted for later ({count})",
|
|
310
358
|
"kvcoder.ui.map.remaining": "{count} steps of the execution map are not done.",
|
|
359
|
+
"kvcoder.ui.map.continue": "Continue",
|
|
360
|
+
"kvcoder.ui.map.continueMessage": "Continue.",
|
|
311
361
|
"kvcoder.ui.map.show": "Show the map",
|
|
312
362
|
"kvcoder.ui.map.close": "Close",
|
|
313
363
|
"kvcoder.ui.artifacts.frameLabel": "Preview of {title}",
|
|
@@ -346,6 +396,7 @@
|
|
|
346
396
|
"kvcoder.config.connector.background": "Lists, reads, and stops what runs in the background.",
|
|
347
397
|
"kvcoder.config.connector.ask": "Asks you a question and waits for your answer.",
|
|
348
398
|
"kvcoder.config.connector.delegate": "Hands part of a task to a worker: another agent with its own instructions.",
|
|
399
|
+
"kvcoder.config.connector.web": "Reads pages on the web, such as current documentation, and asks you before the first page from each site.",
|
|
349
400
|
"kvcoder.config.connector.mcp": "Uses the tools of the MCP servers you add.",
|
|
350
401
|
"kvcoder.config.connectors.use": "Use {name}",
|
|
351
402
|
"kvcoder.config.connectors.configure": "Configure {name}",
|
|
@@ -498,6 +549,7 @@
|
|
|
498
549
|
"kvcoder.config.model.reset.workspace": "Use the value for all workspaces",
|
|
499
550
|
"kvcoder.config.model.ownValue": "{name} has its own value. Switch to {name} to change it.",
|
|
500
551
|
"kvcoder.ui.milliseconds": "{count} ms",
|
|
552
|
+
"kvcoder.ui.hoursMinutes": "{hours} h {minutes} min",
|
|
501
553
|
"kvcoder.ui.minutesSeconds": "{minutes} min {seconds} s",
|
|
502
554
|
"kvcoder.ui.callFailed": "Failed",
|
|
503
555
|
"kvcoder.ui.callParts": "Written in {written} · ran in {ran}",
|
|
@@ -506,6 +558,18 @@
|
|
|
506
558
|
"kvcoder.ui.call.write": "Write",
|
|
507
559
|
"kvcoder.ui.call.read": "Read",
|
|
508
560
|
"kvcoder.ui.call.list": "List",
|
|
561
|
+
"kvcoder.ui.fold.read": "Read {count}",
|
|
562
|
+
"kvcoder.ui.fold.searched": "Searched {count}",
|
|
563
|
+
"kvcoder.ui.fold.changed": "Changed {count}",
|
|
564
|
+
"kvcoder.ui.fold.ran": "Ran {count}",
|
|
565
|
+
"kvcoder.ui.fold.other": "Other {count}",
|
|
566
|
+
"kvcoder.ui.fold.failed": "Failed {count}",
|
|
567
|
+
"kvcoder.ui.call.fetch": "Fetch",
|
|
568
|
+
"kvcoder.ui.call.find": "Find",
|
|
569
|
+
"kvcoder.ui.call.files": "{count} files",
|
|
570
|
+
"kvcoder.ui.call.fileNotRead": "Not read: the files before it used this call's 30 KB.",
|
|
571
|
+
"kvcoder.ui.call.fileUnchanged": "Unchanged since an earlier read in this chat.",
|
|
572
|
+
"kvcoder.ui.call.filesFirst": "The first {count} files",
|
|
509
573
|
"kvcoder.ui.call.search": "Search",
|
|
510
574
|
"kvcoder.ui.call.tools": "Tools",
|
|
511
575
|
"kvcoder.ui.call.delegate": "Delegate",
|
|
@@ -527,6 +591,7 @@
|
|
|
527
591
|
"kvcoder.ui.call.lines": "Lines {from}–{to} of {total}",
|
|
528
592
|
"kvcoder.ui.call.entries": "{count} entries",
|
|
529
593
|
"kvcoder.ui.call.entriesFirst": "The first {count} entries",
|
|
594
|
+
"kvcoder.ui.call.matchCount": "Matches: {count}",
|
|
530
595
|
"kvcoder.ui.call.matches": "{matches} matches in {files} files",
|
|
531
596
|
"kvcoder.ui.call.matchesFirst": "The first {matches} matches in {files} files",
|
|
532
597
|
"kvcoder.ui.call.toolCount": "{count} tools",
|
|
@@ -535,7 +600,7 @@
|
|
|
535
600
|
"kvcoder.ui.call.kilobytes": "{count} KB",
|
|
536
601
|
"kvcoder.ui.call.megabytes": "{count} MB",
|
|
537
602
|
"kvcoder.ui.call.risky": "Risky",
|
|
538
|
-
"kvcoder.ui.call.replacements": "{count}
|
|
603
|
+
"kvcoder.ui.call.replacements": "Replaced: {count} · from line {line}",
|
|
539
604
|
"kvcoder.ui.call.showAll": "Show all {count} lines",
|
|
540
605
|
"kvcoder.ui.call.showFewer": "Show fewer",
|
|
541
606
|
"kvcoder.ui.call.error": "Error",
|