@kvman/kvcoder 0.1.10 → 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.
Files changed (328) hide show
  1. package/dist/api.d.ts +48 -2
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/calls/call-name.d.ts +8 -0
  4. package/dist/calls/call-name.d.ts.map +1 -0
  5. package/dist/calls/call-name.js +47 -0
  6. package/dist/calls/call-name.js.map +1 -0
  7. package/dist/calls/line-run.d.ts +1 -4
  8. package/dist/calls/line-run.d.ts.map +1 -1
  9. package/dist/calls/line-run.js +2 -2
  10. package/dist/calls/line-run.js.map +1 -1
  11. package/dist/calls/run-tool.d.ts +1 -6
  12. package/dist/calls/run-tool.d.ts.map +1 -1
  13. package/dist/calls/run-tool.js +5 -6
  14. package/dist/calls/run-tool.js.map +1 -1
  15. package/dist/connector-call.d.ts +3 -3
  16. package/dist/connector-call.d.ts.map +1 -1
  17. package/dist/connector-call.js +5 -3
  18. package/dist/connector-call.js.map +1 -1
  19. package/dist/connectors/artifact.d.ts +2 -1
  20. package/dist/connectors/artifact.d.ts.map +1 -1
  21. package/dist/connectors/artifact.js +1 -1
  22. package/dist/connectors/artifact.js.map +1 -1
  23. package/dist/connectors/background.d.ts.map +1 -1
  24. package/dist/connectors/background.js +17 -7
  25. package/dist/connectors/background.js.map +1 -1
  26. package/dist/connectors/binary.js +2 -2
  27. package/dist/connectors/binary.js.map +1 -1
  28. package/dist/connectors/builtin-connectors.d.ts +62 -2
  29. package/dist/connectors/builtin-connectors.d.ts.map +1 -1
  30. package/dist/connectors/builtin-connectors.js +4 -1
  31. package/dist/connectors/builtin-connectors.js.map +1 -1
  32. package/dist/connectors/connector-command.d.ts +0 -1
  33. package/dist/connectors/connector-command.d.ts.map +1 -1
  34. package/dist/connectors/connector-command.js +1 -1
  35. package/dist/connectors/connector-command.js.map +1 -1
  36. package/dist/connectors/delegate.d.ts +17 -0
  37. package/dist/connectors/delegate.d.ts.map +1 -1
  38. package/dist/connectors/delegate.js +31 -6
  39. package/dist/connectors/delegate.js.map +1 -1
  40. package/dist/connectors/execution-map.d.ts +14 -3
  41. package/dist/connectors/execution-map.d.ts.map +1 -1
  42. package/dist/connectors/execution-map.js +43 -12
  43. package/dist/connectors/execution-map.js.map +1 -1
  44. package/dist/connectors/fs.d.ts +29 -1
  45. package/dist/connectors/fs.d.ts.map +1 -1
  46. package/dist/connectors/fs.js +46 -9
  47. package/dist/connectors/fs.js.map +1 -1
  48. package/dist/connectors/payload-fields.d.ts +3 -0
  49. package/dist/connectors/payload-fields.d.ts.map +1 -1
  50. package/dist/connectors/payload-fields.js +8 -2
  51. package/dist/connectors/payload-fields.js.map +1 -1
  52. package/dist/connectors/shell.js +1 -1
  53. package/dist/connectors/shell.js.map +1 -1
  54. package/dist/connectors/web.d.ts +16 -0
  55. package/dist/connectors/web.d.ts.map +1 -0
  56. package/dist/connectors/web.js +22 -0
  57. package/dist/connectors/web.js.map +1 -0
  58. package/dist/delegate/approved-run.js +2 -2
  59. package/dist/delegate/approved-run.js.map +1 -1
  60. package/dist/delegate/continue-helper.d.ts +18 -0
  61. package/dist/delegate/continue-helper.d.ts.map +1 -0
  62. package/dist/delegate/continue-helper.js +64 -0
  63. package/dist/delegate/continue-helper.js.map +1 -0
  64. package/dist/delegate/permission.d.ts +11 -5
  65. package/dist/delegate/permission.d.ts.map +1 -1
  66. package/dist/delegate/runs.d.ts +9 -11
  67. package/dist/delegate/runs.d.ts.map +1 -1
  68. package/dist/delegate/runs.js +13 -9
  69. package/dist/delegate/runs.js.map +1 -1
  70. package/dist/delegate/workers.d.ts +6 -0
  71. package/dist/delegate/workers.d.ts.map +1 -1
  72. package/dist/files/change-diff.d.ts +17 -0
  73. package/dist/files/change-diff.d.ts.map +1 -0
  74. package/dist/files/change-diff.js +59 -0
  75. package/dist/files/change-diff.js.map +1 -0
  76. package/dist/files/edit-places.d.ts +11 -0
  77. package/dist/files/edit-places.d.ts.map +1 -0
  78. package/dist/files/edit-places.js +105 -0
  79. package/dist/files/edit-places.js.map +1 -0
  80. package/dist/files/edit-text.d.ts +1 -0
  81. package/dist/files/edit-text.d.ts.map +1 -1
  82. package/dist/files/edit-text.js +22 -10
  83. package/dist/files/edit-text.js.map +1 -1
  84. package/dist/files/file-change.d.ts.map +1 -1
  85. package/dist/files/file-change.js +12 -0
  86. package/dist/files/file-change.js.map +1 -1
  87. package/dist/files/find-paths.d.ts +9 -0
  88. package/dist/files/find-paths.d.ts.map +1 -0
  89. package/dist/files/find-paths.js +38 -0
  90. package/dist/files/find-paths.js.map +1 -0
  91. package/dist/files/read-file.d.ts +3 -1
  92. package/dist/files/read-file.d.ts.map +1 -1
  93. package/dist/files/read-file.js +7 -6
  94. package/dist/files/read-file.js.map +1 -1
  95. package/dist/files/read-files.d.ts +11 -0
  96. package/dist/files/read-files.d.ts.map +1 -0
  97. package/dist/files/read-files.js +35 -0
  98. package/dist/files/read-files.js.map +1 -0
  99. package/dist/files/read-text.d.ts +63 -0
  100. package/dist/files/read-text.d.ts.map +1 -0
  101. package/dist/files/read-text.js +67 -0
  102. package/dist/files/read-text.js.map +1 -0
  103. package/dist/files/register-changes.d.ts +3 -0
  104. package/dist/files/register-changes.d.ts.map +1 -0
  105. package/dist/files/register-changes.js +78 -0
  106. package/dist/files/register-changes.js.map +1 -0
  107. package/dist/files/search-text.d.ts +10 -1
  108. package/dist/files/search-text.d.ts.map +1 -1
  109. package/dist/files/search-text.js +32 -57
  110. package/dist/files/search-text.js.map +1 -1
  111. package/dist/files/workspace-files.d.ts +5 -0
  112. package/dist/files/workspace-files.d.ts.map +1 -0
  113. package/dist/files/workspace-files.js +66 -0
  114. package/dist/files/workspace-files.js.map +1 -0
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +6 -0
  117. package/dist/index.js.map +1 -1
  118. package/dist/jobs/helper-progress.d.ts +11 -0
  119. package/dist/jobs/helper-progress.d.ts.map +1 -0
  120. package/dist/jobs/helper-progress.js +38 -0
  121. package/dist/jobs/helper-progress.js.map +1 -0
  122. package/dist/jobs/job-rows.d.ts +3 -1
  123. package/dist/jobs/job-rows.d.ts.map +1 -1
  124. package/dist/jobs/job-rows.js +46 -22
  125. package/dist/jobs/job-rows.js.map +1 -1
  126. package/dist/jobs/process-report.d.ts +1 -1
  127. package/dist/jobs/process-report.d.ts.map +1 -1
  128. package/dist/jobs/process-report.js +11 -6
  129. package/dist/jobs/process-report.js.map +1 -1
  130. package/dist/jobs/process-run.d.ts +2 -5
  131. package/dist/jobs/process-run.d.ts.map +1 -1
  132. package/dist/jobs/process-run.js +6 -5
  133. package/dist/jobs/process-run.js.map +1 -1
  134. package/dist/jobs/register-jobs.js +3 -3
  135. package/dist/jobs/register-jobs.js.map +1 -1
  136. package/dist/maps/map-rules.d.ts +4 -2
  137. package/dist/maps/map-rules.d.ts.map +1 -1
  138. package/dist/maps/map-rules.js +7 -4
  139. package/dist/maps/map-rules.js.map +1 -1
  140. package/dist/maps/map-schema.d.ts +4 -4
  141. package/dist/maps/map-schema.d.ts.map +1 -1
  142. package/dist/maps/map-schema.js +10 -3
  143. package/dist/maps/map-schema.js.map +1 -1
  144. package/dist/prompt/build-prompt.d.ts +4 -0
  145. package/dist/prompt/build-prompt.d.ts.map +1 -1
  146. package/dist/prompt/build-prompt.js +8 -4
  147. package/dist/prompt/build-prompt.js.map +1 -1
  148. package/dist/prompt/person-preferences.d.ts +5 -0
  149. package/dist/prompt/person-preferences.d.ts.map +1 -0
  150. package/dist/prompt/person-preferences.js +14 -0
  151. package/dist/prompt/person-preferences.js.map +1 -0
  152. package/dist/prompt/session-grants.d.ts +7 -3
  153. package/dist/prompt/session-grants.d.ts.map +1 -1
  154. package/dist/prompt/session-grants.js +3 -2
  155. package/dist/prompt/session-grants.js.map +1 -1
  156. package/dist/prompt/session-prompt.d.ts.map +1 -1
  157. package/dist/prompt/session-prompt.js +15 -6
  158. package/dist/prompt/session-prompt.js.map +1 -1
  159. package/dist/prompt/working-method.d.ts +2 -2
  160. package/dist/prompt/working-method.d.ts.map +1 -1
  161. package/dist/prompt/working-method.js +51 -45
  162. package/dist/prompt/working-method.js.map +1 -1
  163. package/dist/register-settings.d.ts +27 -0
  164. package/dist/register-settings.d.ts.map +1 -1
  165. package/dist/register-settings.js +13 -0
  166. package/dist/register-settings.js.map +1 -1
  167. package/dist/schemas/approval-rule.d.ts +9 -0
  168. package/dist/schemas/approval-rule.d.ts.map +1 -0
  169. package/dist/schemas/approval-rule.js +7 -0
  170. package/dist/schemas/approval-rule.js.map +1 -0
  171. package/dist/schemas/check.d.ts +7 -0
  172. package/dist/schemas/check.d.ts.map +1 -0
  173. package/dist/schemas/check.js +9 -0
  174. package/dist/schemas/check.js.map +1 -0
  175. package/dist/schemas/records.d.ts +20 -6
  176. package/dist/schemas/records.d.ts.map +1 -1
  177. package/dist/schemas/records.js +15 -4
  178. package/dist/schemas/records.js.map +1 -1
  179. package/dist/sessions/new-session.d.ts.map +1 -1
  180. package/dist/sessions/new-session.js +8 -3
  181. package/dist/sessions/new-session.js.map +1 -1
  182. package/dist/sessions/register-fork-export.d.ts.map +1 -1
  183. package/dist/sessions/register-fork-export.js +3 -2
  184. package/dist/sessions/register-fork-export.js.map +1 -1
  185. package/dist/sessions/register-sessions.d.ts.map +1 -1
  186. package/dist/sessions/register-sessions.js +21 -10
  187. package/dist/sessions/register-sessions.js.map +1 -1
  188. package/dist/sessions/session-view.d.ts +10 -1
  189. package/dist/sessions/session-view.d.ts.map +1 -1
  190. package/dist/sessions/session-view.js +6 -1
  191. package/dist/sessions/session-view.js.map +1 -1
  192. package/dist/sessions/waiting-on.d.ts +7 -0
  193. package/dist/sessions/waiting-on.d.ts.map +1 -0
  194. package/dist/sessions/waiting-on.js +20 -0
  195. package/dist/sessions/waiting-on.js.map +1 -0
  196. package/dist/store/collections.d.ts +26 -8
  197. package/dist/store/collections.d.ts.map +1 -1
  198. package/dist/store/collections.js +3 -1
  199. package/dist/store/collections.js.map +1 -1
  200. package/dist/thinking-levels.d.ts +6 -0
  201. package/dist/thinking-levels.d.ts.map +1 -0
  202. package/dist/thinking-levels.js +13 -0
  203. package/dist/thinking-levels.js.map +1 -0
  204. package/dist/turns/answer-extras.d.ts +21 -0
  205. package/dist/turns/answer-extras.d.ts.map +1 -0
  206. package/dist/turns/answer-extras.js +43 -0
  207. package/dist/turns/answer-extras.js.map +1 -0
  208. package/dist/turns/answer-fingerprint.d.ts +6 -2
  209. package/dist/turns/answer-fingerprint.d.ts.map +1 -1
  210. package/dist/turns/answer-fingerprint.js +9 -3
  211. package/dist/turns/answer-fingerprint.js.map +1 -1
  212. package/dist/turns/apply-answer.d.ts +2 -1
  213. package/dist/turns/apply-answer.d.ts.map +1 -1
  214. package/dist/turns/apply-answer.js +10 -4
  215. package/dist/turns/apply-answer.js.map +1 -1
  216. package/dist/turns/approval-rules.d.ts +13 -0
  217. package/dist/turns/approval-rules.d.ts.map +1 -0
  218. package/dist/turns/approval-rules.js +65 -0
  219. package/dist/turns/approval-rules.js.map +1 -0
  220. package/dist/turns/cache-retention.d.ts +6 -0
  221. package/dist/turns/cache-retention.d.ts.map +1 -0
  222. package/dist/turns/cache-retention.js +7 -0
  223. package/dist/turns/cache-retention.js.map +1 -0
  224. package/dist/turns/call-results.d.ts +6 -0
  225. package/dist/turns/call-results.d.ts.map +1 -0
  226. package/dist/turns/call-results.js +21 -0
  227. package/dist/turns/call-results.js.map +1 -0
  228. package/dist/turns/check-after-edits.d.ts +8 -0
  229. package/dist/turns/check-after-edits.d.ts.map +1 -0
  230. package/dist/turns/check-after-edits.js +23 -0
  231. package/dist/turns/check-after-edits.js.map +1 -0
  232. package/dist/turns/child-result.d.ts.map +1 -1
  233. package/dist/turns/child-result.js +4 -2
  234. package/dist/turns/child-result.js.map +1 -1
  235. package/dist/turns/clear-results.d.ts +15 -0
  236. package/dist/turns/clear-results.d.ts.map +1 -0
  237. package/dist/turns/clear-results.js +58 -0
  238. package/dist/turns/clear-results.js.map +1 -0
  239. package/dist/turns/cleared-results.d.ts +17 -0
  240. package/dist/turns/cleared-results.d.ts.map +1 -0
  241. package/dist/turns/cleared-results.js +46 -0
  242. package/dist/turns/cleared-results.js.map +1 -0
  243. package/dist/turns/compaction.d.ts.map +1 -1
  244. package/dist/turns/compaction.js +8 -7
  245. package/dist/turns/compaction.js.map +1 -1
  246. package/dist/turns/end-turn-state.d.ts.map +1 -1
  247. package/dist/turns/end-turn-state.js +2 -0
  248. package/dist/turns/end-turn-state.js.map +1 -1
  249. package/dist/turns/ended-calls.d.ts +6 -0
  250. package/dist/turns/ended-calls.d.ts.map +1 -0
  251. package/dist/turns/ended-calls.js +43 -0
  252. package/dist/turns/ended-calls.js.map +1 -0
  253. package/dist/turns/file-results.d.ts +15 -0
  254. package/dist/turns/file-results.d.ts.map +1 -0
  255. package/dist/turns/file-results.js +39 -0
  256. package/dist/turns/file-results.js.map +1 -0
  257. package/dist/turns/lost-reply.js +2 -2
  258. package/dist/turns/lost-reply.js.map +1 -1
  259. package/dist/turns/model-context.d.ts +2 -0
  260. package/dist/turns/model-context.d.ts.map +1 -1
  261. package/dist/turns/model-context.js +41 -3
  262. package/dist/turns/model-context.js.map +1 -1
  263. package/dist/turns/model-info.d.ts +4 -0
  264. package/dist/turns/model-info.d.ts.map +1 -1
  265. package/dist/turns/model-info.js +7 -1
  266. package/dist/turns/model-info.js.map +1 -1
  267. package/dist/turns/model-retry.d.ts.map +1 -1
  268. package/dist/turns/model-retry.js +5 -4
  269. package/dist/turns/model-retry.js.map +1 -1
  270. package/dist/turns/read-again.d.ts +11 -5
  271. package/dist/turns/read-again.d.ts.map +1 -1
  272. package/dist/turns/read-again.js +39 -10
  273. package/dist/turns/read-again.js.map +1 -1
  274. package/dist/turns/register-turns.d.ts.map +1 -1
  275. package/dist/turns/register-turns.js +12 -4
  276. package/dist/turns/register-turns.js.map +1 -1
  277. package/dist/turns/run-calls.d.ts +4 -0
  278. package/dist/turns/run-calls.d.ts.map +1 -1
  279. package/dist/turns/run-calls.js +56 -10
  280. package/dist/turns/run-calls.js.map +1 -1
  281. package/dist/turns/run-command.d.ts.map +1 -1
  282. package/dist/turns/run-command.js +8 -10
  283. package/dist/turns/run-command.js.map +1 -1
  284. package/dist/turns/sent-size.d.ts +6 -2
  285. package/dist/turns/sent-size.d.ts.map +1 -1
  286. package/dist/turns/sent-size.js +8 -4
  287. package/dist/turns/sent-size.js.map +1 -1
  288. package/dist/turns/settle-calls.d.ts +1 -7
  289. package/dist/turns/settle-calls.d.ts.map +1 -1
  290. package/dist/turns/settle-calls.js +2 -19
  291. package/dist/turns/settle-calls.js.map +1 -1
  292. package/dist/turns/step.d.ts.map +1 -1
  293. package/dist/turns/step.js +68 -10
  294. package/dist/turns/step.js.map +1 -1
  295. package/dist/ui/register-ui.js +2 -2
  296. package/dist/ui/register-ui.js.map +1 -1
  297. package/dist/web/components/approval.css +1 -1
  298. package/dist/web/components/approval.js +122 -89
  299. package/dist/web/components/call.css +1 -1
  300. package/dist/web/components/call.js +431 -306
  301. package/dist/web/components/connectors.css +1 -1
  302. package/dist/web/components/connectors.js +553 -521
  303. package/dist/web/components/conversation.css +1 -1
  304. package/dist/web/components/conversation.js +2636 -1520
  305. package/dist/web/components/mcp-sign-in.css +1 -1
  306. package/dist/web/components/model.css +1 -1
  307. package/dist/web/components/model.js +140 -127
  308. package/dist/web/components/preferences.css +2 -0
  309. package/dist/web/components/preferences.js +151 -0
  310. package/dist/web/components/question.css +1 -1
  311. package/dist/web/components/sessions.css +1 -1
  312. package/dist/web/components/sessions.js +44 -21
  313. package/dist/web-fetch/fetch-page.d.ts +28 -0
  314. package/dist/web-fetch/fetch-page.d.ts.map +1 -0
  315. package/dist/web-fetch/fetch-page.js +108 -0
  316. package/dist/web-fetch/fetch-page.js.map +1 -0
  317. package/dist/web-fetch/private-address.d.ts +3 -0
  318. package/dist/web-fetch/private-address.d.ts.map +1 -0
  319. package/dist/web-fetch/private-address.js +69 -0
  320. package/dist/web-fetch/private-address.js.map +1 -0
  321. package/dist/web-fetch/web-hosts.d.ts +7 -0
  322. package/dist/web-fetch/web-hosts.d.ts.map +1 -0
  323. package/dist/web-fetch/web-hosts.js +19 -0
  324. package/dist/web-fetch/web-hosts.js.map +1 -0
  325. package/docs/connectors.md +5 -6
  326. package/locales/ar.json +81 -5
  327. package/locales/en.json +81 -5
  328. package/package.json +152 -6
@@ -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,3 @@
1
+ /** Whether an address is one `web fetch` must not reach; something that isn't an address counts as one. */
2
+ export declare function isPrivateAddress(address: string): boolean;
3
+ //# sourceMappingURL=private-address.d.ts.map
@@ -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":"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"}
@@ -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"}
@@ -3,10 +3,9 @@
3
3
  A **connector** is a named set of commands the agent runs with its one tool, `run`:
4
4
 
5
5
  ```json
6
- { "description": "Adding milk to the notes", "connector": "notes", "command": "add", "payload": { "text": "Buy milk" } }
6
+ { "connector": "notes", "command": "add", "payload": { "text": "Buy milk" } }
7
7
  ```
8
8
 
9
- - `description` is one sentence for the person, shown on the call's card.
10
9
  - `connector` and `command` name what runs; `payload` is the command's input, and may be left out when it takes none.
11
10
  - Every connector has the command `help`: with no payload it describes the connector and its commands, and with `{ "command": "add" }` it gives that command's payload and result as JSON Schema, with its examples.
12
11
 
@@ -37,14 +36,14 @@ ctx.registerHandler('kernel.started', {
37
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()`.
38
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.
39
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.
40
- - 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.
41
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.
42
41
 
43
42
  ## A command that asks
44
43
 
45
44
  Mark a command with `asks: true` when it changes something the person didn't make in this chat: their settings, their data, what is installed.
46
45
 
47
- - Every call of it becomes an approval card in the chat, showing the call's `description`, the connector and command, and the payload. The turn waits for the answer.
46
+ - Every call of it becomes an approval card in the chat, showing the connector and command, and the payload. The turn waits for the answer.
48
47
  - It asks with `kvcoder.approval` on `auto` and on `ask`, and runs at once on `never`, where nothing asks. Otherwise that setting covers kvcoder's own `shell`, `fs`, and `mcp` calls, which carry `risky`; a registered command has no `risky`, so the flag on its entry decides.
49
48
  - **Allow** runs the command at the start of the next step, and its result goes to the agent as usual. **Deny** returns `denied by the user`, and the command never runs.
50
49
  - The payload isn't checked before the person is asked; the kernel validates it when the command runs.
@@ -102,9 +101,9 @@ Register a connector with `optIn: true`, the only value the field takes, when it
102
101
 
103
102
  ## Built-in connectors
104
103
 
105
- 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, task, background? }` hands a task to a worker, which runs it in a helper session; 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`.
106
105
 
107
- `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`, and `delegate run` take `background: true`; every other command runs to its end.
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`.
108
107
 
109
108
  ## Ownership
110
109
 
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,12 +164,16 @@
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": "أدنى",
147
172
  "kvcoder.ui.thinkingLevels.low": "منخفض",
148
173
  "kvcoder.ui.thinkingLevels.medium": "متوسط",
149
174
  "kvcoder.ui.thinkingLevels.high": "مرتفع",
175
+ "kvcoder.ui.thinkingLevels.xhigh": "مرتفع جدًا",
176
+ "kvcoder.ui.thinkingLevels.max": "أقصى",
150
177
  "kvcoder.ui.menu": "المزيد",
151
178
  "kvcoder.ui.rename": "إعادة التسمية",
152
179
  "kvcoder.ui.fork": "نسخ إلى محادثة جديدة",
@@ -180,7 +207,11 @@
180
207
  "kvcoder.shell.run.description": "ينفّذ سطرًا واحدًا في الطرفية الفعلية، داخل مجلد مساحة العمل.",
181
208
  "kvcoder.binary.run.description": "يشغّل البرنامج بالوسائط المعطاة في الطرفية الفعلية، داخل مجلد مساحة العمل.",
182
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؛ للشخص.",
183
213
  "kvcoder.fs.entry.list.description": "يسرد ملفات ومجلدات مجلد واحد.",
214
+ "kvcoder.fs.path.list.description": "يجد الملفات التي يطابق مسارها نمطًا، داخل مجلد، الأحدث أولًا.",
184
215
  "kvcoder.fs.text.search.description": "يجد الأسطر التي تطابق تعبيرًا نمطيًا، في ملف أو داخل مجلد.",
185
216
  "kvcoder.fs.write.description": "ينشئ ملفًا مع مجلداته الأصلية، أو يستبدل محتوى الملف.",
186
217
  "kvcoder.fs.edit.description": "يستبدل مقاطع نصية محددة في ملف موجود؛ وإذا فشل أحد الاستبدالات لا يُكتب شيء.",
@@ -190,15 +221,17 @@
190
221
  "kvcoder.artifact.write.description": "ينشئ مخرجًا، أو يستبدل عنوانه وصيغته ومحتواه.",
191
222
  "kvcoder.artifact.edit.description": "يستبدل مقاطع نصية محددة في مخرج موجود؛ وإذا فشل أحد الاستبدالات لا يتغير شيء.",
192
223
  "kvcoder.artifact.content.get.description": "يقرأ مخرجًا مع محتواه.",
193
- "kvcoder.map.set.description": "ينشئ خريطة التنفيذ أو يستبدلها، والخطوة التي يبقى معرّفها تحتفظ بما وصلت إليه.",
224
+ "kvcoder.map.set.description": "ينشئ هيكل خريطة التنفيذ أو يستبدله، والخطوة التي يبقى معرّفها تحتفظ بتفاصيلها وبما وصلت إليه.",
225
+ "kvcoder.map.step.details.set.description": "يكتب تفاصيل خطوة واحدة من الخريطة.",
194
226
  "kvcoder.map.step.update.description": "يغيّر حالة خطوة أو أكثر من خطوات الخريطة.",
195
227
  "kvcoder.map.note.add.description": "يضيف ملاحظة إلى قائمة «مؤجَّل لوقت لاحق» في الخريطة.",
196
- "kvcoder.map.state.get.description": "يقرأ خريطة التنفيذ كاملة.",
228
+ "kvcoder.map.state.get.description": "يقرأ خريطة التنفيذ دون تفاصيل خطواتها، أو خطوة واحدة كاملة.",
197
229
  "kvcoder.background.list.description": "يسرد أحدث 50 عملية في خلفية هذه المحادثة، الأحدث أولًا، كلٌّ بمعرّفها ونوعها وعنوانها وحالتها.",
198
230
  "kvcoder.background.output.get.description": "يعطي حالة عملية واحدة في الخلفية ومخرجاتها (آخر أسطر العملية، أو إجابة الوكيل المساعد، أو ما أعاده تشغيل عامل برنامج).",
199
231
  "kvcoder.background.wait.description": "ينتظر حتى تنتهي عملية في الخلفية أو ينقضي الوقت، ثم يعطي حالتها ومخرجاتها كما يفعل output.",
200
232
  "kvcoder.background.stop.description": "يوقف عملية في الخلفية أو تشغيل برنامج مساعد، أو يلغي وكيلًا فرعيًا في الخلفية.",
201
233
  "kvcoder.mcp.tool.describe.description": "يسرد أدوات خادم MCP، أو يعطي وصف أداة واحدة ومُدخلاتها.",
234
+ "kvcoder.web.page.get.description": "يقرأ صفحة على الويب بصيغة Markdown أو نصًا.",
202
235
  "kvcoder.mcp.tool.call.description": "يستدعي أداة من خادم MCP ويعيد نصّها.",
203
236
  "kvcoder.mcp.steps.run.description": "يستدعي عدة أدوات من خادم MCP على اتصال واحد بالترتيب، فيحتفظ الخادم بحالته بينها، ويتوقف عند أول أداة تُبلغ عن خطأ.",
204
237
  "kvcoder.mcp.server.check.description": "يتصل بخادم MCP ويخبر هل هو جاهز، أم يحتاج إلى تسجيل دخول، أم فشل.",
@@ -208,6 +241,7 @@
208
241
  "kvcoder.ask.choice.check.description": "يطلب من المستخدم الاختيار من بين خيارات وينتظر الإجابة.",
209
242
  "kvcoder.ask.confirm.check.description": "يسأل المستخدم سؤال نعم أو لا وينتظر الإجابة.",
210
243
  "kvcoder.delegate.check.description": "يشغّل مساعدًا على مهمة؛ وعدة تشغيلات في رد واحد تعمل بالتوازي.",
244
+ "kvcoder.delegate.continue.check.description": "يرسل متابعة إلى مساعد في هذه المحادثة أنهى عمله، مثل مساعد عاد متوقفًا أو بأسئلة: فيكمل بسجله نفسه.",
211
245
  "kvcoder.delegate.worker.check.description": "يتحقق من أن برنامج المساعد مثبت؛ والوكيل المساعد جاهز دائمًا.",
212
246
  "kvcoder.delegate.worker.run.description": "يشغّل برنامج المساعد على مهمته، ويعطي المحادثة إجابته.",
213
247
  "kvcoder.connector.help.get.description": "يعيد مساعدة موصّل: أوامره، أو حمولة أمر واحد ونتيجته وأمثلته.",
@@ -237,8 +271,26 @@
237
271
  "kvcoder.thinking.description": "مقدار تفكير النموذج في المحادثة الجديدة.",
238
272
  "kvcoder.maxSteps.title": "الخطوات في كل جولة",
239
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": "النموذج الذي تنتقل إليه المحادثة عندما يبلغ نموذجها حد الاستخدام، أو حد الطلبات بعد كل المحاولات. فارغ لعدم الانتقال.",
240
286
  "kvcoder.approval.title": "الموافقة",
241
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": "إزالة",
242
294
  "kvcoder.config.approval.never.title": "عدم السؤال قبل أي عملية؟",
243
295
  "kvcoder.config.approval.never.text": "سينفّذ الوكيل الأوامر ويعدّل الملفات ويغيّر kvman نفسه ويشغّل برامج المساعدين دون أن يسألك. وما يقرؤه قد يوجّهه.",
244
296
  "kvcoder.config.approval.never.confirm": "أوقف السؤال",
@@ -261,6 +313,7 @@
261
313
  "kvcoder.artifact.list.description": "يسرد مخرجات المحادثة، الأحدث تعديلًا أولًا.",
262
314
  "kvcoder.artifact.get.description": "يعيد مخرجًا واحدًا من المحادثة مع محتواه.",
263
315
  "kvcoder.map.get.description": "يعطي خريطة التنفيذ لمحادثة، أو null إن لم تكن لها خريطة.",
316
+ "kvcoder.ui.backgroundDecision": "مساعد يعمل في الخلفية ينتظر قرارك.",
264
317
  "kvcoder.ui.jobs.title": "المهام الخلفية",
265
318
  "kvcoder.ui.jobs.running": "{count} قيد التشغيل",
266
319
  "kvcoder.ui.jobs.minutes": "{minutes} د {seconds} ث",
@@ -268,6 +321,7 @@
268
321
  "kvcoder.ui.jobs.stop": "إيقاف",
269
322
  "kvcoder.ui.jobs.noOutput": "لا يوجد ناتج بعد.",
270
323
  "kvcoder.ui.jobs.status.running": "قيد التشغيل",
324
+ "kvcoder.ui.jobs.status.waiting": "بانتظار ردّك",
271
325
  "kvcoder.ui.jobs.status.succeeded": "اكتملت",
272
326
  "kvcoder.ui.jobs.status.failed": "فشلت",
273
327
  "kvcoder.ui.jobs.status.cancelled": "أُوقفت",
@@ -275,7 +329,8 @@
275
329
  "kvcoder.ui.jobs.inBackground": "يعمل في الخلفية",
276
330
  "kvcoder.ui.jobs.background": "في الخلفية",
277
331
  "kvcoder.notices.STEP_FAILED_REASON": "توقفت الجولة: {error} {reason}",
278
- "kvcoder.ui.activity.retrying": "جارٍ إعادة المحاولة… ({attempt} من {of})",
332
+ "kvcoder.ui.activity.retryingRateLimited": "إعادة المحاولة بعد {seconds} ث: المزوّد يحدّ من الطلبات ({attempt} من {of})",
333
+ "kvcoder.ui.activity.retryingUnavailable": "إعادة المحاولة بعد {seconds} ث: المزوّد لم يُجب ({attempt} من {of})",
279
334
  "kvcoder.ui.artifacts.title": "المخرجات",
280
335
  "kvcoder.ui.artifacts.open": "فتح",
281
336
  "kvcoder.ui.artifacts.close": "إغلاق",
@@ -293,7 +348,7 @@
293
348
  "kvcoder.ui.map.status.failed": "فشلت",
294
349
  "kvcoder.ui.map.status.skipped": "تم تخطيها",
295
350
  "kvcoder.ui.map.step": "الخطوة",
296
- "kvcoder.ui.map.description": "الوصف",
351
+ "kvcoder.ui.map.details": "التفاصيل",
297
352
  "kvcoder.ui.map.after": "بعد",
298
353
  "kvcoder.ui.map.uses": "تستخدم",
299
354
  "kvcoder.ui.map.check": "التحقق",
@@ -301,6 +356,8 @@
301
356
  "kvcoder.ui.map.note": "ملاحظة",
302
357
  "kvcoder.ui.map.noted": "مؤجَّل لوقت لاحق ({count})",
303
358
  "kvcoder.ui.map.remaining": "{count} من خطوات خريطة التنفيذ لم تُنجز.",
359
+ "kvcoder.ui.map.continue": "تابع",
360
+ "kvcoder.ui.map.continueMessage": "تابع.",
304
361
  "kvcoder.ui.map.show": "عرض الخريطة",
305
362
  "kvcoder.ui.map.close": "إغلاق",
306
363
  "kvcoder.ui.artifacts.frameLabel": "معاينة {title}",
@@ -339,6 +396,7 @@
339
396
  "kvcoder.config.connector.background": "يسرد ما يعمل في الخلفية ويقرأ ناتجه ويوقفه.",
340
397
  "kvcoder.config.connector.ask": "يطرح عليك سؤالًا وينتظر إجابتك.",
341
398
  "kvcoder.config.connector.delegate": "يسند جزءًا من المهمة إلى مساعد: وكيل آخر له تعليماته.",
399
+ "kvcoder.config.connector.web": "يقرأ صفحات على الويب، مثل التوثيق الحالي، ويسألك قبل أول صفحة من كل موقع.",
342
400
  "kvcoder.config.connector.mcp": "يستخدم أدوات خوادم MCP التي تضيفها.",
343
401
  "kvcoder.config.connectors.use": "استخدام {name}",
344
402
  "kvcoder.config.connectors.configure": "إعداد {name}",
@@ -491,6 +549,7 @@
491
549
  "kvcoder.config.model.reset.workspace": "استخدام قيمة كل مساحات العمل",
492
550
  "kvcoder.config.model.ownValue": "لمساحة العمل {name} قيمة خاصة بها. انتقل إلى {name} لتغييرها.",
493
551
  "kvcoder.ui.milliseconds": "{count} مللي ث",
552
+ "kvcoder.ui.hoursMinutes": "{hours} س {minutes} د",
494
553
  "kvcoder.ui.minutesSeconds": "{minutes} د {seconds} ث",
495
554
  "kvcoder.ui.callFailed": "فشل",
496
555
  "kvcoder.ui.callParts": "كُتب في {written} · نُفّذ في {ran}",
@@ -499,6 +558,18 @@
499
558
  "kvcoder.ui.call.write": "كتابة",
500
559
  "kvcoder.ui.call.read": "قراءة",
501
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} ملف",
502
573
  "kvcoder.ui.call.search": "بحث",
503
574
  "kvcoder.ui.call.tools": "الأدوات",
504
575
  "kvcoder.ui.call.delegate": "تفويض",
@@ -506,16 +577,21 @@
506
577
  "kvcoder.ui.call.output": "ناتج",
507
578
  "kvcoder.ui.call.wait": "انتظار",
508
579
  "kvcoder.ui.call.mapSet": "خريطة",
580
+ "kvcoder.ui.call.mapDetail": "تفاصيل خطوة",
509
581
  "kvcoder.ui.call.mapUpdate": "خطوة في الخريطة",
510
582
  "kvcoder.ui.call.mapNote": "مؤجَّل لوقت لاحق",
511
583
  "kvcoder.ui.call.mapGet": "قراءة الخريطة",
512
584
  "kvcoder.ui.call.stop": "إيقاف",
513
585
  "kvcoder.ui.call.readArtifact": "قراءة المُخرَج",
586
+ "kvcoder.ui.call.writeArtifact": "كتابة المُخرَج",
587
+ "kvcoder.ui.call.editArtifact": "تعديل المُخرَج",
588
+ "kvcoder.ui.call.help": "مساعدة",
514
589
  "kvcoder.ui.call.created": "أُنشئ · {size}",
515
590
  "kvcoder.ui.call.replaced": "استُبدل · {size}",
516
591
  "kvcoder.ui.call.lines": "الأسطر {from}–{to} من {total}",
517
592
  "kvcoder.ui.call.entries": "{count} عنصر",
518
593
  "kvcoder.ui.call.entriesFirst": "أول {count} عنصر",
594
+ "kvcoder.ui.call.matchCount": "النتائج: {count}",
519
595
  "kvcoder.ui.call.matches": "{matches} نتيجة في {files} ملف",
520
596
  "kvcoder.ui.call.matchesFirst": "أول {matches} نتيجة في {files} ملف",
521
597
  "kvcoder.ui.call.toolCount": "{count} أداة",
@@ -524,7 +600,7 @@
524
600
  "kvcoder.ui.call.kilobytes": "{count} ك.ب",
525
601
  "kvcoder.ui.call.megabytes": "{count} م.ب",
526
602
  "kvcoder.ui.call.risky": "خطِر",
527
- "kvcoder.ui.call.replacements": "{count} استبدال · من السطر {line}",
603
+ "kvcoder.ui.call.replacements": "الاستبدالات: {count} · من السطر {line}",
528
604
  "kvcoder.ui.call.showAll": "عرض كل الأسطر ({count})",
529
605
  "kvcoder.ui.call.showFewer": "عرض أقل",
530
606
  "kvcoder.ui.call.error": "الخطأ",