presubmit 0.1.0

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 (220) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +51 -0
  3. package/THIRD_PARTY_NOTICES.md +24 -0
  4. package/apps/web/dist/assets/FileCode-CZZH52o7.js +5 -0
  5. package/apps/web/dist/assets/FileCode-DovDO7Jh.css +1 -0
  6. package/apps/web/dist/assets/SettingsPage-CRvOwdjt.js +4 -0
  7. package/apps/web/dist/assets/SettingsPage-UbYSCwJj.css +1 -0
  8. package/apps/web/dist/assets/TerminalPanel-0sw-J6YS.css +1 -0
  9. package/apps/web/dist/assets/TerminalPanel-BqUjPWav.js +16 -0
  10. package/apps/web/dist/assets/index-BhqNNFja.js +54 -0
  11. package/apps/web/dist/assets/index-DD8VXy8H.css +1 -0
  12. package/apps/web/dist/assets/presubmit-mark-BBQ19Fmr.svg +7 -0
  13. package/apps/web/dist/assets/presubmit-mark-busy-CwBC-7on.svg +8 -0
  14. package/apps/web/dist/assets/react-vendor-wiHys0m2.js +9 -0
  15. package/apps/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
  16. package/apps/web/dist/index.html +6 -0
  17. package/apps/web/dist/service-worker.js +11 -0
  18. package/dist/apps/server/src/agent-builder.js +204 -0
  19. package/dist/apps/server/src/attach.js +163 -0
  20. package/dist/apps/server/src/attachments.js +86 -0
  21. package/dist/apps/server/src/browser-access.js +131 -0
  22. package/dist/apps/server/src/check-provenance.js +95 -0
  23. package/dist/apps/server/src/check-supervisor.js +112 -0
  24. package/dist/apps/server/src/checks.js +402 -0
  25. package/dist/apps/server/src/child-collaboration-guidance.js +2 -0
  26. package/dist/apps/server/src/child-sessions.js +191 -0
  27. package/dist/apps/server/src/cli.js +162 -0
  28. package/dist/apps/server/src/conversation-search.js +12 -0
  29. package/dist/apps/server/src/coordinator-messages.js +72 -0
  30. package/dist/apps/server/src/dev-auth.js +54 -0
  31. package/dist/apps/server/src/dev-server.js +201 -0
  32. package/dist/apps/server/src/dev-worker.js +48 -0
  33. package/dist/apps/server/src/diagnostics.js +105 -0
  34. package/dist/apps/server/src/fast-mode.js +8 -0
  35. package/dist/apps/server/src/folder-picker.js +54 -0
  36. package/dist/apps/server/src/git-blobs.js +62 -0
  37. package/dist/apps/server/src/git-handoff.js +127 -0
  38. package/dist/apps/server/src/history-sources.js +59 -0
  39. package/dist/apps/server/src/hub.js +159 -0
  40. package/dist/apps/server/src/internal-transport.js +38 -0
  41. package/dist/apps/server/src/local-embeddings.js +70 -0
  42. package/dist/apps/server/src/ollama-setup.js +56 -0
  43. package/dist/apps/server/src/planning.js +30 -0
  44. package/dist/apps/server/src/project-agents.js +276 -0
  45. package/dist/apps/server/src/project-memory.js +94 -0
  46. package/dist/apps/server/src/projects.js +106 -0
  47. package/dist/apps/server/src/queued-launch.js +13 -0
  48. package/dist/apps/server/src/reply-search.js +172 -0
  49. package/dist/apps/server/src/review-context.js +60 -0
  50. package/dist/apps/server/src/review-refresh.js +14 -0
  51. package/dist/apps/server/src/reviewers.js +75 -0
  52. package/dist/apps/server/src/search-settings.js +22 -0
  53. package/dist/apps/server/src/semantic-history.js +186 -0
  54. package/dist/apps/server/src/server.js +4338 -0
  55. package/dist/apps/server/src/session-changes.js +181 -0
  56. package/dist/apps/server/src/session-router-settings.js +198 -0
  57. package/dist/apps/server/src/session-workspaces.js +135 -0
  58. package/dist/apps/server/src/sessions.js +579 -0
  59. package/dist/apps/server/src/shared-auth.js +70 -0
  60. package/dist/apps/server/src/shell-evaluator-settings.js +53 -0
  61. package/dist/apps/server/src/store.js +203 -0
  62. package/dist/apps/server/src/tailscale-process.js +115 -0
  63. package/dist/apps/server/src/tailscale-serve-worker.js +33 -0
  64. package/dist/apps/server/src/tailscale-serve.js +276 -0
  65. package/dist/apps/server/src/task-capacity.js +92 -0
  66. package/dist/apps/server/src/task-graph.js +190 -0
  67. package/dist/apps/server/src/task-logs.js +74 -0
  68. package/dist/apps/server/src/task-numbers.js +25 -0
  69. package/dist/apps/server/src/task-orchestrator.js +1088 -0
  70. package/dist/apps/server/src/terminal.js +182 -0
  71. package/dist/apps/server/src/terminals.js +80 -0
  72. package/dist/apps/server/src/tool-safety.js +2 -0
  73. package/dist/apps/server/src/workspace-lock.js +140 -0
  74. package/dist/apps/server/src/workspace-watcher.js +65 -0
  75. package/dist/apps/server/src/workspace.js +517 -0
  76. package/dist/packages/agent-pi/src/agent-builder-tool.js +32 -0
  77. package/dist/packages/agent-pi/src/agent-capabilities.js +44 -0
  78. package/dist/packages/agent-pi/src/ask-user.js +86 -0
  79. package/dist/packages/agent-pi/src/auth.js +510 -0
  80. package/dist/packages/agent-pi/src/check-tools.js +72 -0
  81. package/dist/packages/agent-pi/src/command-policy.js +246 -0
  82. package/dist/packages/agent-pi/src/coordinator-tools.js +122 -0
  83. package/dist/packages/agent-pi/src/fast-mode.js +67 -0
  84. package/dist/packages/agent-pi/src/file-tools.js +163 -0
  85. package/dist/packages/agent-pi/src/history-tool.js +40 -0
  86. package/dist/packages/agent-pi/src/history.js +34 -0
  87. package/dist/packages/agent-pi/src/index.js +177 -0
  88. package/dist/packages/agent-pi/src/ipc.js +314 -0
  89. package/dist/packages/agent-pi/src/jev-session-router.js +408 -0
  90. package/dist/packages/agent-pi/src/jev-tools.js +71 -0
  91. package/dist/packages/agent-pi/src/local-model.js +277 -0
  92. package/dist/packages/agent-pi/src/memory-tools.js +119 -0
  93. package/dist/packages/agent-pi/src/model.js +25 -0
  94. package/dist/packages/agent-pi/src/planning.js +206 -0
  95. package/dist/packages/agent-pi/src/resource-loader.js +23 -0
  96. package/dist/packages/agent-pi/src/review-tools.js +158 -0
  97. package/dist/packages/agent-pi/src/review-transition.js +73 -0
  98. package/dist/packages/agent-pi/src/review.js +40 -0
  99. package/dist/packages/agent-pi/src/routing.js +27 -0
  100. package/dist/packages/agent-pi/src/session-setup.js +118 -0
  101. package/dist/packages/agent-pi/src/shell-context.js +51 -0
  102. package/dist/packages/agent-pi/src/shell-policy.js +281 -0
  103. package/dist/packages/agent-pi/src/shell-safety.js +205 -0
  104. package/dist/packages/agent-pi/src/shell.js +121 -0
  105. package/dist/packages/agent-pi/src/snapshot-permissions.js +12 -0
  106. package/dist/packages/agent-pi/src/spike.js +41 -0
  107. package/dist/packages/agent-pi/src/task-tools.js +53 -0
  108. package/dist/packages/agent-pi/src/types.js +1 -0
  109. package/dist/packages/agent-pi/src/usage.js +30 -0
  110. package/dist/packages/agent-pi/src/worker.js +602 -0
  111. package/dist/packages/protocol/src/activity-summary.js +77 -0
  112. package/dist/packages/protocol/src/agents.js +301 -0
  113. package/dist/packages/protocol/src/browser-access.js +1 -0
  114. package/dist/packages/protocol/src/checks.js +40 -0
  115. package/dist/packages/protocol/src/child-sessions.js +28 -0
  116. package/dist/packages/protocol/src/command-policy.js +3 -0
  117. package/dist/packages/protocol/src/coordinator.js +135 -0
  118. package/dist/packages/protocol/src/delegation.js +40 -0
  119. package/dist/packages/protocol/src/git-diff.js +71 -0
  120. package/dist/packages/protocol/src/git-handoff.js +1 -0
  121. package/dist/packages/protocol/src/index.js +1 -0
  122. package/dist/packages/protocol/src/memory.js +46 -0
  123. package/dist/packages/protocol/src/metrics.js +70 -0
  124. package/dist/packages/protocol/src/planning.js +138 -0
  125. package/dist/packages/protocol/src/retrieval.js +36 -0
  126. package/dist/packages/protocol/src/reviewers.js +17 -0
  127. package/dist/packages/protocol/src/search.js +16 -0
  128. package/dist/packages/protocol/src/session-changes.js +29 -0
  129. package/dist/packages/protocol/src/session-router.js +123 -0
  130. package/dist/packages/protocol/src/shell-evaluator.js +43 -0
  131. package/dist/packages/protocol/src/task-graph.js +1 -0
  132. package/dist/packages/protocol/src/token-usage.js +17 -0
  133. package/dist/packages/protocol/src/user-questions.js +106 -0
  134. package/package.json +71 -0
  135. package/vendor/lancedb/NODEJS_THIRD_PARTY_LICENSES.md +668 -0
  136. package/vendor/lancedb/RUST_THIRD_PARTY_LICENSES.html +14607 -0
  137. package/vendor/lancedb/dist/arrow.d.ts +296 -0
  138. package/vendor/lancedb/dist/arrow.js +1145 -0
  139. package/vendor/lancedb/dist/arrow_type.d.ts +9 -0
  140. package/vendor/lancedb/dist/arrow_type.js +29 -0
  141. package/vendor/lancedb/dist/connection.d.ts +508 -0
  142. package/vendor/lancedb/dist/connection.js +298 -0
  143. package/vendor/lancedb/dist/embedding/embedding_function.d.ts +103 -0
  144. package/vendor/lancedb/dist/embedding/embedding_function.js +192 -0
  145. package/vendor/lancedb/dist/embedding/index.d.ts +37 -0
  146. package/vendor/lancedb/dist/embedding/index.js +108 -0
  147. package/vendor/lancedb/dist/embedding/openai.d.ts +16 -0
  148. package/vendor/lancedb/dist/embedding/openai.js +81 -0
  149. package/vendor/lancedb/dist/embedding/registry.d.ts +94 -0
  150. package/vendor/lancedb/dist/embedding/registry.js +221 -0
  151. package/vendor/lancedb/dist/embedding/transformers.d.ts +36 -0
  152. package/vendor/lancedb/dist/embedding/transformers.js +110 -0
  153. package/vendor/lancedb/dist/header.d.ts +162 -0
  154. package/vendor/lancedb/dist/header.js +217 -0
  155. package/vendor/lancedb/dist/index.d.ts +246 -0
  156. package/vendor/lancedb/dist/index.js +176 -0
  157. package/vendor/lancedb/dist/indices.d.ts +721 -0
  158. package/vendor/lancedb/dist/indices.js +166 -0
  159. package/vendor/lancedb/dist/materialized_view.d.ts +69 -0
  160. package/vendor/lancedb/dist/materialized_view.js +112 -0
  161. package/vendor/lancedb/dist/merge.d.ts +104 -0
  162. package/vendor/lancedb/dist/merge.js +120 -0
  163. package/vendor/lancedb/dist/native.d.ts +1193 -0
  164. package/vendor/lancedb/dist/native.js +688 -0
  165. package/vendor/lancedb/dist/oauth.d.ts +66 -0
  166. package/vendor/lancedb/dist/oauth.js +15 -0
  167. package/vendor/lancedb/dist/otel.d.ts +26 -0
  168. package/vendor/lancedb/dist/otel.js +114 -0
  169. package/vendor/lancedb/dist/permutation.d.ts +143 -0
  170. package/vendor/lancedb/dist/permutation.js +184 -0
  171. package/vendor/lancedb/dist/query.d.ts +663 -0
  172. package/vendor/lancedb/dist/query.js +966 -0
  173. package/vendor/lancedb/dist/rerankers/index.d.ts +5 -0
  174. package/vendor/lancedb/dist/rerankers/index.js +19 -0
  175. package/vendor/lancedb/dist/rerankers/rrf.d.ts +14 -0
  176. package/vendor/lancedb/dist/rerankers/rrf.js +28 -0
  177. package/vendor/lancedb/dist/sanitize.d.ts +32 -0
  178. package/vendor/lancedb/dist/sanitize.js +544 -0
  179. package/vendor/lancedb/dist/scannable.d.ts +92 -0
  180. package/vendor/lancedb/dist/scannable.js +200 -0
  181. package/vendor/lancedb/dist/schema.d.ts +16 -0
  182. package/vendor/lancedb/dist/schema.js +387 -0
  183. package/vendor/lancedb/dist/table.d.ts +1069 -0
  184. package/vendor/lancedb/dist/table.js +498 -0
  185. package/vendor/lancedb/dist/util.d.ts +14 -0
  186. package/vendor/lancedb/dist/util.js +77 -0
  187. package/vendor/lancedb/license_header.txt +2 -0
  188. package/vendor/lancedb/package.json +56 -0
  189. package/vendor/transformers/LICENSE +202 -0
  190. package/vendor/transformers/dist/transformers.cjs +30844 -0
  191. package/vendor/transformers/dist/transformers.mjs +31404 -0
  192. package/vendor/transformers/package.json +55 -0
  193. package/vendor/transformers/types/backends/onnx.d.ts +30 -0
  194. package/vendor/transformers/types/configs.d.ts +85 -0
  195. package/vendor/transformers/types/env.d.ts +110 -0
  196. package/vendor/transformers/types/generation/configuration_utils.d.ts +320 -0
  197. package/vendor/transformers/types/generation/logits_process.d.ts +354 -0
  198. package/vendor/transformers/types/generation/logits_sampler.d.ts +51 -0
  199. package/vendor/transformers/types/generation/parameters.d.ts +47 -0
  200. package/vendor/transformers/types/generation/stopping_criteria.d.ts +81 -0
  201. package/vendor/transformers/types/generation/streamers.d.ts +81 -0
  202. package/vendor/transformers/types/models/whisper/common_whisper.d.ts +8 -0
  203. package/vendor/transformers/types/models/whisper/generation_whisper.d.ts +76 -0
  204. package/vendor/transformers/types/models.d.ts +3684 -0
  205. package/vendor/transformers/types/ops/registry.d.ts +11 -0
  206. package/vendor/transformers/types/pipelines.d.ts +2402 -0
  207. package/vendor/transformers/types/processors.d.ts +924 -0
  208. package/vendor/transformers/types/tokenizers.d.ts +990 -0
  209. package/vendor/transformers/types/transformers.d.ts +13 -0
  210. package/vendor/transformers/types/utils/audio.d.ts +130 -0
  211. package/vendor/transformers/types/utils/constants.d.ts +2 -0
  212. package/vendor/transformers/types/utils/core.d.ts +98 -0
  213. package/vendor/transformers/types/utils/data-structures.d.ts +236 -0
  214. package/vendor/transformers/types/utils/devices.d.ts +18 -0
  215. package/vendor/transformers/types/utils/dtypes.d.ts +19 -0
  216. package/vendor/transformers/types/utils/generic.d.ts +11 -0
  217. package/vendor/transformers/types/utils/hub.d.ts +152 -0
  218. package/vendor/transformers/types/utils/image.d.ts +119 -0
  219. package/vendor/transformers/types/utils/maths.d.ts +280 -0
  220. package/vendor/transformers/types/utils/tensor.d.ts +418 -0
@@ -0,0 +1,46 @@
1
+ function text(value, max, empty = false) {
2
+ if (typeof value !== 'string' || value.length > max || (!empty && !value.trim()))
3
+ throw new Error('Invalid memory text.');
4
+ return value.trim();
5
+ }
6
+ export function parseMemoryRequest(value) {
7
+ if (!value || typeof value !== 'object')
8
+ throw new Error('Invalid memory request.');
9
+ const v = value;
10
+ if (v.action === 'search') {
11
+ const limit = v.limit ?? 10;
12
+ if (!Number.isInteger(limit) ||
13
+ Number(limit) < 1 ||
14
+ Number(limit) > 50 ||
15
+ (v.includeRetired !== undefined && typeof v.includeRetired !== 'boolean'))
16
+ throw new Error('Invalid memory search.');
17
+ return {
18
+ action: 'search',
19
+ query: text(v.query, 200, true),
20
+ limit: Number(limit),
21
+ includeRetired: v.includeRetired === true,
22
+ };
23
+ }
24
+ const id = () => text(v.id, 128);
25
+ if (v.action === 'read')
26
+ return { action: 'read', id: id() };
27
+ if (!['save', 'update', 'retire'].includes(String(v.action)))
28
+ throw new Error('Invalid memory action.');
29
+ const requestId = text(v.requestId, 128);
30
+ if (v.action !== 'save' && (!Number.isSafeInteger(v.revision) || Number(v.revision) < 1))
31
+ throw new Error('Invalid memory revision.');
32
+ if (v.action === 'retire')
33
+ return { action: 'retire', requestId, id: id(), revision: Number(v.revision) };
34
+ if (!v.text || typeof v.text !== 'object')
35
+ throw new Error('Invalid lesson.');
36
+ const t = v.text;
37
+ const fields = {
38
+ title: text(t.title, 120),
39
+ lesson: text(t.lesson, 1600),
40
+ context: text(t.context, 800),
41
+ evidence: text(t.evidence, 1200),
42
+ };
43
+ return v.action === 'save'
44
+ ? { action: 'save', requestId, text: fields }
45
+ : { action: 'update', requestId, id: id(), revision: Number(v.revision), text: fields };
46
+ }
@@ -0,0 +1,70 @@
1
+ // Fixed buckets and bounded labels keep diagnostics from growing with session history.
2
+ const bounds = [
3
+ 0.1,
4
+ 0.25,
5
+ 0.5,
6
+ 1,
7
+ 2,
8
+ 4,
9
+ 8,
10
+ 16,
11
+ 32,
12
+ 64,
13
+ 128,
14
+ 256,
15
+ 512,
16
+ 1000,
17
+ 2000,
18
+ 4000,
19
+ 8000,
20
+ 16000,
21
+ 30000,
22
+ Infinity,
23
+ ];
24
+ const round = (value) => Math.round(value * 100) / 100;
25
+ export class PerformanceMetrics {
26
+ timings = new Map();
27
+ counters = new Map();
28
+ observe(name, milliseconds) {
29
+ if (!Number.isFinite(milliseconds) || milliseconds < 0)
30
+ return;
31
+ let value = this.timings.get(name);
32
+ if (!value) {
33
+ if (this.timings.size >= 32)
34
+ return;
35
+ value = { count: 0, total: 0, max: 0, buckets: bounds.map(() => 0) };
36
+ this.timings.set(name, value);
37
+ }
38
+ value.count++;
39
+ value.total += milliseconds;
40
+ value.max = Math.max(value.max, milliseconds);
41
+ value.buckets[bounds.findIndex((bound) => milliseconds <= bound)]++;
42
+ }
43
+ count(name, amount = 1) {
44
+ if (!Number.isFinite(amount) || amount < 0)
45
+ return;
46
+ if (!this.counters.has(name) && this.counters.size >= 32)
47
+ return;
48
+ this.counters.set(name, (this.counters.get(name) ?? 0) + amount);
49
+ }
50
+ drain() {
51
+ const timings = Object.fromEntries([...this.timings].map(([name, value]) => {
52
+ let count = 0;
53
+ const index = value.buckets.findIndex((bucket) => (count += bucket) >= Math.ceil(value.count * 0.95));
54
+ return [
55
+ name,
56
+ {
57
+ count: value.count,
58
+ totalMs: round(value.total),
59
+ meanMs: round(value.total / value.count),
60
+ p95UpperMs: round(Math.min(bounds[index], value.max)),
61
+ maxMs: round(value.max),
62
+ },
63
+ ];
64
+ }));
65
+ const counters = Object.fromEntries(this.counters);
66
+ this.timings.clear();
67
+ this.counters.clear();
68
+ return { timings, counters };
69
+ }
70
+ }
@@ -0,0 +1,138 @@
1
+ export const emptyPlanningBoard = () => ({
2
+ revision: 0,
3
+ summary: '',
4
+ ideas: [],
5
+ tasks: [],
6
+ questions: [],
7
+ });
8
+ /** Compact conversation/UI label in the task list's persisted order; tool references still use IDs. */
9
+ export function taskDisplayId(taskId, tasks) {
10
+ const index = tasks.findIndex((task) => task.id === taskId);
11
+ return index < 0 ? undefined : `T${tasks[index].displayNumber ?? index + 1}`;
12
+ }
13
+ /** Shared structural limits for HTTP, IPC, and persisted planning proposals. */
14
+ export function parsePlanningBoard(value) {
15
+ const object = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
16
+ const text = (v, max, required = true) => typeof v === 'string' && v.length <= max && (!required || !!v.trim());
17
+ const id = (v) => text(v, 80) && /^[a-zA-Z0-9_-]+$/.test(v);
18
+ const refs = (v) => Array.isArray(v) &&
19
+ v.length > 0 &&
20
+ v.length <= 100 &&
21
+ v.every(id) &&
22
+ new Set(v).size === v.length;
23
+ const list = (v, max) => Array.isArray(v) &&
24
+ v.length <= max &&
25
+ v.every((x) => object(x) && id(x.id)) &&
26
+ new Set(v.map((x) => x.id)).size === v.length;
27
+ if (!object(value) ||
28
+ !Number.isSafeInteger(value.revision) ||
29
+ Number(value.revision) < 0 ||
30
+ Number(value.revision) >= Number.MAX_SAFE_INTEGER ||
31
+ !text(value.summary, 8000, false) ||
32
+ !list(value.ideas, 100) ||
33
+ !list(value.tasks, 50) ||
34
+ !list(value.questions, 50))
35
+ throw new Error('Invalid planning board or limits exceeded.');
36
+ const ideas = value.ideas.map((idea) => {
37
+ if (!text(idea.text, 4000) ||
38
+ !refs(idea.sourceRunIds) ||
39
+ !['active', 'deferred', 'rejected'].includes(String(idea.disposition)))
40
+ throw new Error('Invalid idea. Include its source message IDs.');
41
+ return {
42
+ id: String(idea.id),
43
+ text: idea.text,
44
+ sourceRunIds: idea.sourceRunIds,
45
+ disposition: idea.disposition,
46
+ };
47
+ });
48
+ const ideaIds = new Set(ideas.map((idea) => idea.id));
49
+ const tasks = value.tasks.map((task) => {
50
+ if (!text(task.title, 120) ||
51
+ !text(task.scope, 8000) ||
52
+ !text(task.criteria, 4000, false) ||
53
+ !Array.isArray(task.sourceIdeaIds) ||
54
+ (task.sourceIdeaIds.length > 0 && !refs(task.sourceIdeaIds)) ||
55
+ !task.sourceIdeaIds.every((ref) => ideaIds.has(ref)) ||
56
+ (task.sourceRunIds !== undefined && !refs(task.sourceRunIds)) ||
57
+ (!task.sourceIdeaIds.length && !refs(task.sourceRunIds)) ||
58
+ !['draft', 'needs_clarification', 'ready', 'deferred'].includes(String(task.status)))
59
+ throw new Error('Invalid task. Include source message IDs or existing idea references.');
60
+ if (task.status === 'ready' && !task.criteria.trim())
61
+ throw new Error('Ready tasks need acceptance criteria.');
62
+ if (task.dependencies !== undefined &&
63
+ (!Array.isArray(task.dependencies) ||
64
+ task.dependencies.length > 50 ||
65
+ !task.dependencies.every(id) ||
66
+ new Set(task.dependencies).size !== task.dependencies.length))
67
+ throw new Error('Invalid task dependencies.');
68
+ if (task.execution !== undefined && !['session', 'subagent'].includes(String(task.execution)))
69
+ throw new Error('Invalid execution kind.');
70
+ if (task.kind !== undefined && !['research', 'implementation'].includes(String(task.kind)))
71
+ throw new Error('Invalid task kind.');
72
+ if (task.affectedAreas !== undefined && !text(task.affectedAreas, 2000, false))
73
+ throw new Error('Invalid affected areas.');
74
+ return {
75
+ ...(task.sourceRunIds !== undefined ? { sourceRunIds: task.sourceRunIds } : {}),
76
+ ...(task.dependencies !== undefined ? { dependencies: task.dependencies } : {}),
77
+ ...(task.execution !== undefined
78
+ ? { execution: task.execution }
79
+ : {}),
80
+ ...(task.kind !== undefined ? { kind: task.kind } : {}),
81
+ ...(task.affectedAreas !== undefined ? { affectedAreas: task.affectedAreas } : {}),
82
+ id: String(task.id),
83
+ title: task.title,
84
+ scope: task.scope,
85
+ criteria: task.criteria,
86
+ sourceIdeaIds: task.sourceIdeaIds,
87
+ status: task.status,
88
+ };
89
+ });
90
+ const taskMap = new Map(tasks.map((task) => [task.id, task]));
91
+ const visiting = new Set(), visited = new Set();
92
+ const visit = (id) => {
93
+ if (visiting.has(id))
94
+ throw new Error('Task dependencies contain a cycle.');
95
+ if (visited.has(id))
96
+ return;
97
+ const task = taskMap.get(id);
98
+ if (!task)
99
+ throw new Error('Unknown dependency task.');
100
+ visiting.add(id);
101
+ for (const dependency of task.dependencies ?? [])
102
+ visit(dependency);
103
+ visiting.delete(id);
104
+ visited.add(id);
105
+ };
106
+ for (const task of tasks)
107
+ visit(task.id);
108
+ const questions = value.questions.map((question) => {
109
+ if (!text(question.text, 2000) ||
110
+ !text(question.answer, 4000, false) ||
111
+ typeof question.blocking !== 'boolean' ||
112
+ !refs(question.sourceRunIds))
113
+ throw new Error('Invalid clarification question.');
114
+ if (question.taskIds !== undefined &&
115
+ (!Array.isArray(question.taskIds) ||
116
+ question.taskIds.length > 50 ||
117
+ !question.taskIds.every((id) => typeof id === 'string' && taskMap.has(id))))
118
+ throw new Error('Invalid question task references.');
119
+ return {
120
+ ...(question.taskIds !== undefined ? { taskIds: question.taskIds } : {}),
121
+ id: String(question.id),
122
+ text: question.text,
123
+ answer: question.answer,
124
+ blocking: question.blocking,
125
+ sourceRunIds: question.sourceRunIds,
126
+ };
127
+ });
128
+ const board = {
129
+ revision: Number(value.revision),
130
+ summary: value.summary,
131
+ ideas,
132
+ tasks,
133
+ questions,
134
+ };
135
+ if (JSON.stringify(board).length > 100000)
136
+ throw new Error('Planning board exceeds 100,000 characters.');
137
+ return board;
138
+ }
@@ -0,0 +1,36 @@
1
+ /** Only turn features off; keep the embedding provider and any remaining access unchanged. */
2
+ export function isSearchSettingsReduction(previous, next) {
3
+ return (next.model === previous.model &&
4
+ next.endpoint === previous.endpoint &&
5
+ (!next.enabled || previous.enabled) &&
6
+ (!next.agentRetrieval || previous.agentRetrieval) &&
7
+ ((previous.enabled && !next.enabled) || (previous.agentRetrieval && !next.agentRetrieval)));
8
+ }
9
+ export function isAgentRetrievalChange(previous, next) {
10
+ return (previous.enabled &&
11
+ next.enabled &&
12
+ next.model === previous.model &&
13
+ next.endpoint === previous.endpoint &&
14
+ next.agentRetrieval !== previous.agentRetrieval);
15
+ }
16
+ export function parseHistoryHits(value) {
17
+ if (!Array.isArray(value) || value.length > 10)
18
+ throw new Error('Invalid history response');
19
+ for (const hit of value) {
20
+ if (!hit ||
21
+ typeof hit !== 'object' ||
22
+ !['sourceId', 'sessionId', 'sessionTitle', 'runId', 'createdAt', 'text'].every((key) => typeof hit[key] === 'string') ||
23
+ hit.sourceId.length > 128 ||
24
+ hit.sessionId.length > 128 ||
25
+ hit.runId.length > 128 ||
26
+ hit.sessionTitle.length > 500 ||
27
+ hit.createdAt.length > 100 ||
28
+ hit.text.length > 1600 ||
29
+ !['prompt', 'reply'].includes(hit.kind) ||
30
+ !Number.isFinite(hit.score) ||
31
+ hit.score < 0 ||
32
+ hit.score > 1)
33
+ throw new Error('Invalid history response');
34
+ }
35
+ return value;
36
+ }
@@ -0,0 +1,17 @@
1
+ export function parseReviewRequest(value) {
2
+ const v = value;
3
+ if (!v ||
4
+ !['working', 'branch'].includes(String(v.scope)) ||
5
+ typeof v.base !== 'string' ||
6
+ !v.base.trim() ||
7
+ v.base.length > 200 ||
8
+ (v.target !== undefined &&
9
+ (typeof v.target !== 'string' || !v.target.trim() || v.target.length > 200)) ||
10
+ (v.scope === 'working' && v.target !== undefined))
11
+ throw new Error('Supply working or branch scope and explicit local comparison refs.');
12
+ return {
13
+ scope: v.scope,
14
+ base: v.base.trim(),
15
+ ...(v.scope === 'branch' ? { target: v.target?.trim() ?? 'HEAD' } : {}),
16
+ };
17
+ }
@@ -0,0 +1,16 @@
1
+ /** Literal, case-insensitive matching, including punctuation and non-ASCII text. */
2
+ export function searchPattern(query) {
3
+ return new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'iu');
4
+ }
5
+ export function searchExcerpt(text, pattern) {
6
+ const match = pattern.exec(text);
7
+ if (!match)
8
+ return;
9
+ const start = Math.max(0, match.index - 80);
10
+ const end = Math.min(text.length, match.index + match[0].length + 160);
11
+ return {
12
+ before: (start ? '…' : '') + text.slice(start, match.index),
13
+ match: match[0],
14
+ after: text.slice(match.index + match[0].length, end) + (end < text.length ? '…' : ''),
15
+ };
16
+ }
@@ -0,0 +1,29 @@
1
+ export const MAX_RECORDED_FILE_BYTES = 1024 * 1024;
2
+ export function isRecordedFileChange(value) {
3
+ if (!value || typeof value !== 'object')
4
+ return false;
5
+ const item = value;
6
+ if (typeof item.toolCallId !== 'string' ||
7
+ !item.toolCallId ||
8
+ item.toolCallId.length > 200 ||
9
+ !Number.isSafeInteger(item.index) ||
10
+ Number(item.index) < 0 ||
11
+ typeof item.file !== 'string' ||
12
+ !item.file ||
13
+ item.file.length > 4096 ||
14
+ item.file.startsWith('/') ||
15
+ item.file.includes('\\') ||
16
+ item.file.includes('\0') ||
17
+ item.file
18
+ .split('/')
19
+ .some((part) => !part || part === '.' || part === '..' || part.toLowerCase() === '.git'))
20
+ return false;
21
+ if (item.omitted !== undefined)
22
+ return (['size', 'non-text'].includes(String(item.omitted)) &&
23
+ item.before === undefined &&
24
+ item.after === undefined);
25
+ return [item.before, item.after].every((text) => text === null ||
26
+ (typeof text === 'string' &&
27
+ !text.includes('\0') &&
28
+ new TextEncoder().encode(text).length <= MAX_RECORDED_FILE_BYTES));
29
+ }
@@ -0,0 +1,123 @@
1
+ export const defaultSessionRouterSettings = {
2
+ enabled: false,
3
+ model: 'jev-latest',
4
+ routeConfidence: { code: 0.8, plan: 0.7 },
5
+ taskRoutingEnabled: false,
6
+ taskMinConfidence: 0.7,
7
+ agentConsultEnabled: false,
8
+ agentConsultMinConfidence: 0.7,
9
+ shellSafetyShadowEnabled: false,
10
+ };
11
+ function boundedText(value, label, maxLength) {
12
+ if (typeof value !== 'string' ||
13
+ !value.trim() ||
14
+ value.length > maxLength ||
15
+ /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/.test(value))
16
+ throw new Error(`Enter valid ${label}.`);
17
+ return value.trim();
18
+ }
19
+ export function parseJevConsultRequest(value) {
20
+ if (!value || typeof value !== 'object' || Array.isArray(value))
21
+ throw new Error('Invalid Jev consultation.');
22
+ const input = value;
23
+ if (Object.keys(input).some((key) => !['question', 'choices', 'context', 'criterion'].includes(key)))
24
+ throw new Error('Unknown Jev consultation field.');
25
+ if (!Array.isArray(input.choices) || input.choices.length < 2 || input.choices.length > 5)
26
+ throw new Error('Provide between two and five Jev choices.');
27
+ const choices = input.choices.map((value) => {
28
+ if (!value || typeof value !== 'object' || Array.isArray(value))
29
+ throw new Error('Invalid Jev choice.');
30
+ const choice = value;
31
+ if (Object.keys(choice).some((key) => !['id', 'description'].includes(key)))
32
+ throw new Error('Unknown Jev choice field.');
33
+ const id = boundedText(choice.id, 'choice ID', 64);
34
+ if (!/^[a-zA-Z0-9_-]+$/.test(id))
35
+ throw new Error('Choice IDs may contain only letters, numbers, underscores, and hyphens.');
36
+ return { id, description: boundedText(choice.description, 'choice description', 1000) };
37
+ });
38
+ if (new Set(choices.map((choice) => choice.id)).size !== choices.length)
39
+ throw new Error('Jev choice IDs must be unique.');
40
+ return {
41
+ question: boundedText(input.question, 'consultation question', 1000),
42
+ choices,
43
+ context: boundedText(input.context, 'consultation context', 8000),
44
+ ...(input.criterion === undefined
45
+ ? {}
46
+ : { criterion: boundedText(input.criterion, 'decision criterion', 1000) }),
47
+ };
48
+ }
49
+ export function parseJevConsultDecision(value) {
50
+ if (!value || typeof value !== 'object' || Array.isArray(value))
51
+ throw new Error('Invalid Jev consultation result.');
52
+ const decision = value;
53
+ if (decision.provider !== 'typesafe' ||
54
+ typeof decision.requestedModel !== 'string' ||
55
+ typeof decision.accepted !== 'boolean' ||
56
+ (decision.choice !== undefined && typeof decision.choice !== 'string') ||
57
+ (decision.confidence !== undefined &&
58
+ (typeof decision.confidence !== 'number' ||
59
+ !Number.isFinite(decision.confidence) ||
60
+ decision.confidence < 0 ||
61
+ decision.confidence > 1)) ||
62
+ (decision.accepted && (!decision.choice || decision.confidence === undefined)) ||
63
+ (decision.fallback !== undefined &&
64
+ !['confidence', 'invalid_selection', 'timeout', 'provider_error'].includes(decision.fallback)))
65
+ throw new Error('Invalid Jev consultation result.');
66
+ return decision;
67
+ }
68
+ function confidence(value, label) {
69
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0.5 || value > 1)
70
+ throw new Error(`${label} must be between 0.5 and 1.`);
71
+ return value;
72
+ }
73
+ export function parseSessionRouterSettings(value) {
74
+ if (!value || typeof value !== 'object' || Array.isArray(value))
75
+ throw new Error('Invalid session routing settings.');
76
+ const input = value;
77
+ if (Object.keys(input).some((key) => ![
78
+ 'enabled',
79
+ 'model',
80
+ 'minConfidence',
81
+ 'routeConfidence',
82
+ 'taskRoutingEnabled',
83
+ 'taskMinConfidence',
84
+ 'agentConsultEnabled',
85
+ 'agentConsultMinConfidence',
86
+ 'shellSafetyShadowEnabled',
87
+ ].includes(key)))
88
+ throw new Error('Unknown session routing setting.');
89
+ if (typeof input.enabled !== 'boolean')
90
+ throw new Error('Choose whether Jev routing is enabled.');
91
+ if (typeof input.model !== 'string' ||
92
+ !input.model.trim() ||
93
+ input.model.length > 200 ||
94
+ /[\x00-\x1f\x7f]/.test(input.model))
95
+ throw new Error('Enter a valid Jev model ID.');
96
+ const legacy = input.minConfidence;
97
+ const route = input.routeConfidence;
98
+ if (route !== undefined &&
99
+ (!route ||
100
+ typeof route !== 'object' ||
101
+ Array.isArray(route) ||
102
+ Object.keys(route).some((key) => !['code', 'plan'].includes(key))))
103
+ throw new Error('Invalid route confidence settings.');
104
+ const code = confidence(route ? route.code : (legacy ?? 0.8), 'Code route confidence');
105
+ const plan = confidence(route ? route.plan : (legacy ?? 0.7), 'Plan route confidence');
106
+ if (input.taskRoutingEnabled !== undefined && typeof input.taskRoutingEnabled !== 'boolean')
107
+ throw new Error('Choose whether Jev routes subtask models.');
108
+ if (input.agentConsultEnabled !== undefined && typeof input.agentConsultEnabled !== 'boolean')
109
+ throw new Error('Choose whether agents can consult Jev.');
110
+ if (input.shellSafetyShadowEnabled !== undefined &&
111
+ typeof input.shellSafetyShadowEnabled !== 'boolean')
112
+ throw new Error('Choose whether Jev shadows shell safety.');
113
+ return {
114
+ enabled: input.enabled,
115
+ model: input.model.trim(),
116
+ routeConfidence: { code, plan },
117
+ taskRoutingEnabled: input.taskRoutingEnabled === true,
118
+ taskMinConfidence: confidence(input.taskMinConfidence ?? legacy ?? 0.7, 'Task confidence'),
119
+ agentConsultEnabled: input.agentConsultEnabled === true,
120
+ agentConsultMinConfidence: confidence(input.agentConsultMinConfidence ?? legacy ?? 0.7, 'Agent consultation confidence'),
121
+ shellSafetyShadowEnabled: input.shellSafetyShadowEnabled === true,
122
+ };
123
+ }
@@ -0,0 +1,43 @@
1
+ export const defaultSafetyMaxTokens = 4096;
2
+ export const minSafetyMaxTokens = 256;
3
+ export const maxSafetyMaxTokens = 32768;
4
+ export function validSafetyMaxTokens(value) {
5
+ return (typeof value === 'number' &&
6
+ Number.isInteger(value) &&
7
+ value >= minSafetyMaxTokens &&
8
+ value <= maxSafetyMaxTokens);
9
+ }
10
+ export function parseShellEvaluatorSettings(value, models) {
11
+ if (!value || typeof value !== 'object' || Array.isArray(value))
12
+ throw new Error('Invalid evaluator settings.');
13
+ const input = value;
14
+ if (Object.keys(input).some((key) => !['model', 'reasoning', 'maxTokens', 'prompt'].includes(key)))
15
+ throw new Error('Unknown evaluator setting.');
16
+ const result = {};
17
+ if (input.maxTokens !== undefined) {
18
+ if (!validSafetyMaxTokens(input.maxTokens))
19
+ throw new Error(`Maximum output tokens must be an integer from ${minSafetyMaxTokens} to ${maxSafetyMaxTokens}.`);
20
+ result.maxTokens = input.maxTokens;
21
+ }
22
+ if (input.model !== undefined) {
23
+ const model = models.find((model) => model.id === input.model);
24
+ if (!model)
25
+ throw new Error('Evaluator model is unavailable on the connected provider.');
26
+ result.model = model.id;
27
+ }
28
+ if (input.reasoning !== undefined) {
29
+ const model = models.find((model) => model.id === result.model);
30
+ if (!model || !(model.reasoningLevels ?? ['off']).includes(input.reasoning))
31
+ throw new Error('Select a model and a supported reasoning level.');
32
+ result.reasoning = input.reasoning;
33
+ }
34
+ if (input.prompt !== undefined) {
35
+ if (typeof input.prompt !== 'string' ||
36
+ !input.prompt.trim() ||
37
+ input.prompt.length > 16000 ||
38
+ input.prompt.includes('\0'))
39
+ throw new Error('Evaluator prompt must contain 1–16000 characters and no NUL.');
40
+ result.prompt = input.prompt;
41
+ }
42
+ return result;
43
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ /** Sum reported runs, preserving the distinction between missing usage and zero. */
2
+ export function sumTokenUsage(runs) {
3
+ let total;
4
+ for (const { usage } of runs) {
5
+ if (!usage)
6
+ continue;
7
+ total ??= { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
8
+ total.input += usage.input;
9
+ total.output += usage.output;
10
+ total.cacheRead += usage.cacheRead;
11
+ total.cacheWrite += usage.cacheWrite;
12
+ }
13
+ return total;
14
+ }
15
+ export function totalTokens(usage) {
16
+ return usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
17
+ }
@@ -0,0 +1,106 @@
1
+ export function userQuestionItems(request) {
2
+ return 'questions' in request ? request.questions : [request];
3
+ }
4
+ export function userAnswerItems(response) {
5
+ return 'answers' in response ? response.answers : [response];
6
+ }
7
+ function object(value) {
8
+ if (!value || typeof value !== 'object' || Array.isArray(value))
9
+ throw new Error('Invalid question or answer.');
10
+ return value;
11
+ }
12
+ function text(value, name, limit) {
13
+ if (typeof value !== 'string' || !value.trim() || value.length > limit)
14
+ throw new Error(`Invalid ${name}.`);
15
+ return value.trim();
16
+ }
17
+ export function parseUserQuestion(value) {
18
+ const input = object(value);
19
+ if (input.questions !== undefined)
20
+ throw new Error('Nested question batches are not supported.');
21
+ const question = text(input.question, 'question', 2000);
22
+ const context = input.context === undefined ? undefined : text(input.context, 'context', 2000);
23
+ if (input.allowMultiple !== undefined && typeof input.allowMultiple !== 'boolean')
24
+ throw new Error('Invalid multiple-selection setting.');
25
+ let options;
26
+ if (input.options !== undefined) {
27
+ if (!Array.isArray(input.options) || input.options.length < 2 || input.options.length > 4)
28
+ throw new Error('Provide two to four choices, or omit choices for a written answer.');
29
+ options = input.options.map((raw) => {
30
+ const option = object(raw);
31
+ return {
32
+ label: text(option.label, 'choice', 120),
33
+ ...(option.description === undefined
34
+ ? {}
35
+ : { description: text(option.description, 'choice description', 400) }),
36
+ };
37
+ });
38
+ if (new Set(options.map((option) => option.label.toLowerCase())).size !== options.length)
39
+ throw new Error('Choices must be distinct.');
40
+ }
41
+ if (input.allowMultiple && !options)
42
+ throw new Error('Multiple selection requires choices.');
43
+ return {
44
+ question,
45
+ ...(context ? { context } : {}),
46
+ ...(options ? { options } : {}),
47
+ ...(input.allowMultiple !== undefined ? { allowMultiple: input.allowMultiple } : {}),
48
+ };
49
+ }
50
+ export function parseUserAnswer(value, question) {
51
+ const input = object(value);
52
+ if (input.answers !== undefined)
53
+ throw new Error('This question needs one answer.');
54
+ if (input.skipped !== undefined) {
55
+ if (input.skipped !== true)
56
+ throw new Error('A skipped answer must explicitly set skipped to true.');
57
+ if (['option', 'options', 'text'].some((key) => input[key] !== undefined))
58
+ throw new Error('A skipped question cannot include an answer.');
59
+ return { skipped: true };
60
+ }
61
+ const option = input.option === undefined ? undefined : text(input.option, 'selected choice', 120);
62
+ const answerText = input.text === undefined ? undefined : text(input.text, 'answer', 4000);
63
+ if (input.option !== undefined && question.allowMultiple)
64
+ throw new Error('Return selected choices as an array for a multiple-selection question.');
65
+ let options;
66
+ if (input.options !== undefined) {
67
+ if (!question.allowMultiple || !Array.isArray(input.options) || input.options.length > 4)
68
+ throw new Error('Invalid selected choices.');
69
+ options = input.options.map((option) => text(option, 'selected choice', 120));
70
+ if (new Set(options).size !== options.length)
71
+ throw new Error('Selected choices must be distinct.');
72
+ if (options.some((option) => !question.options?.some((choice) => choice.label === option)))
73
+ throw new Error('A selected choice does not belong to this question.');
74
+ }
75
+ if (option && !question.options?.some((choice) => choice.label === option))
76
+ throw new Error('The selected choice does not belong to this question.');
77
+ if (!option && !options?.length && !answerText)
78
+ throw new Error('Choose an option or write an answer.');
79
+ return {
80
+ ...(option ? { option } : {}),
81
+ ...(options?.length ? { options } : {}),
82
+ ...(answerText ? { text: answerText } : {}),
83
+ };
84
+ }
85
+ export function parseUserQuestionRequest(value) {
86
+ const input = object(value);
87
+ if (input.questions === undefined)
88
+ return parseUserQuestion(input);
89
+ if (['question', 'context', 'options', 'allowMultiple'].some((key) => input[key] !== undefined))
90
+ throw new Error('Provide either a single question or a questions array.');
91
+ if (!Array.isArray(input.questions) || input.questions.length < 1 || input.questions.length > 5)
92
+ throw new Error('Provide one to five questions per batch.');
93
+ return { questions: input.questions.map(parseUserQuestion) };
94
+ }
95
+ export function parseUserResponse(value, request) {
96
+ if (!('questions' in request))
97
+ return parseUserAnswer(value, request);
98
+ const input = object(value);
99
+ if (['option', 'options', 'text', 'skipped'].some((key) => input[key] !== undefined) ||
100
+ !Array.isArray(input.answers) ||
101
+ input.answers.length !== request.questions.length)
102
+ throw new Error('Provide one answer for every question, in the original order.');
103
+ return {
104
+ answers: input.answers.map((answer, index) => parseUserAnswer(answer, request.questions[index])),
105
+ };
106
+ }