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,92 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { dirname } from 'node:path';
4
+ import { defaultDelegatedExecutionLimit, maxDelegatedExecutionLimit, minDelegatedExecutionLimit, } from '../../../packages/protocol/src/delegation.js';
5
+ function readSettings(path) {
6
+ const defaults = { version: '0', limit: defaultDelegatedExecutionLimit, parallelFileReads: true };
7
+ if (!path)
8
+ return defaults;
9
+ try {
10
+ const value = JSON.parse(readFileSync(path, 'utf8'));
11
+ if (typeof value.version !== 'string' ||
12
+ !Number.isInteger(value.limit) ||
13
+ value.limit < minDelegatedExecutionLimit ||
14
+ value.limit > maxDelegatedExecutionLimit ||
15
+ (value.parallelFileReads !== undefined && typeof value.parallelFileReads !== 'boolean'))
16
+ throw new Error('Invalid delegated execution settings.');
17
+ return { ...defaults, ...value };
18
+ }
19
+ catch (error) {
20
+ if (error.code === 'ENOENT')
21
+ return defaults;
22
+ throw error;
23
+ }
24
+ }
25
+ /** Shared by all projects in one host. Each parent session has its own delegated execution allowance. */
26
+ export class TaskCapacity {
27
+ settingsPath;
28
+ leases = new Map();
29
+ settings;
30
+ constructor(settingsPath) {
31
+ this.settingsPath = settingsPath;
32
+ this.settings = readSettings(settingsPath);
33
+ }
34
+ get limit() {
35
+ return this.settings.limit;
36
+ }
37
+ state() {
38
+ return { ...this.settings };
39
+ }
40
+ save(input) {
41
+ const value = input;
42
+ if (!value ||
43
+ typeof value !== 'object' ||
44
+ typeof value.version !== 'string' ||
45
+ value.version !== this.settings.version)
46
+ throw new Error('Execution settings changed. Reload before saving.');
47
+ const limit = value.limit;
48
+ if (!Number.isInteger(limit) ||
49
+ limit < minDelegatedExecutionLimit ||
50
+ limit > maxDelegatedExecutionLimit)
51
+ throw new Error(`Maximum child sessions must be between ${minDelegatedExecutionLimit} and ${maxDelegatedExecutionLimit}.`);
52
+ if (value.parallelFileReads !== undefined && typeof value.parallelFileReads !== 'boolean')
53
+ throw new Error('Invalid parallel file reads setting.');
54
+ const next = {
55
+ version: randomUUID(),
56
+ limit: limit,
57
+ parallelFileReads: value.parallelFileReads ?? this.settings.parallelFileReads,
58
+ };
59
+ if (this.settingsPath) {
60
+ mkdirSync(dirname(this.settingsPath), { recursive: true, mode: 0o700 });
61
+ const temporary = `${this.settingsPath}.${randomUUID()}`;
62
+ try {
63
+ writeFileSync(temporary, JSON.stringify(next), { mode: 0o600 });
64
+ renameSync(temporary, this.settingsPath);
65
+ }
66
+ finally {
67
+ rmSync(temporary, { force: true });
68
+ }
69
+ }
70
+ this.settings = next;
71
+ return this.state();
72
+ }
73
+ acquire(owner, coordinator, userRequested = false) {
74
+ if (this.leases.has(owner))
75
+ return true;
76
+ if (!userRequested && this.blockedReason(owner, coordinator))
77
+ return false;
78
+ this.leases.set(owner, coordinator);
79
+ return true;
80
+ }
81
+ blockedReason(owner, coordinator) {
82
+ if (this.leases.has(owner))
83
+ return undefined;
84
+ const active = [...this.leases.values()].filter((value) => value === coordinator).length;
85
+ if (active >= this.limit)
86
+ return `Waiting for execution capacity: ${active}/${this.limit} session slots in use.`;
87
+ return undefined;
88
+ }
89
+ release(owner) {
90
+ this.leases.delete(owner);
91
+ }
92
+ }
@@ -0,0 +1,190 @@
1
+ import { activeCheck } from '../../../packages/protocol/src/checks.js';
2
+ import { taskDisplayId } from '../../../packages/protocol/src/planning.js';
3
+ const sessionKey = (id) => `session:${id}`;
4
+ const taskKey = (sessionId, id) => `task:${sessionId}:${id}`;
5
+ const done = (attempt) => !!attempt && ['done', 'needs_review'].includes(attempt.status);
6
+ export function projectTaskGraph(sessions, stateFor) {
7
+ const nodes = [];
8
+ const edges = [];
9
+ const aliases = new Map();
10
+ const directory = new Map(sessions.map((session) => [session.id, session]));
11
+ for (const session of sessions.filter((item) => !item.archived && !item.assignment)) {
12
+ const state = stateFor(session.id);
13
+ const board = state?.planning;
14
+ const delegation = state?.delegation;
15
+ const latest = new Map(delegation?.attempts.map((attempt) => [attempt.taskId, attempt]));
16
+ const tasks = new Map(board?.tasks.map((task) => [task.id, task]));
17
+ for (const attempt of latest.values())
18
+ if (!tasks.has(attempt.taskId))
19
+ tasks.set(attempt.taskId, attempt.task);
20
+ const references = [...tasks.values()];
21
+ for (const task of tasks.values()) {
22
+ const attempt = latest.get(task.id);
23
+ const child = attempt && directory.get(attempt.sessionId);
24
+ const node = {
25
+ id: taskKey(session.id, task.id),
26
+ kind: 'task',
27
+ title: task.title,
28
+ tag: taskDisplayId(task.id, references),
29
+ coordinatorId: session.id,
30
+ taskId: task.id,
31
+ sessionId: child?.id,
32
+ branch: child?.branch,
33
+ description: task.scope,
34
+ criteria: task.criteria,
35
+ status: 'idle',
36
+ statusLabel: 'Draft',
37
+ };
38
+ const unmet = (task.dependencies ?? []).filter((id) => !done(latest.get(id)));
39
+ const question = board?.questions.find((q) => q.blocking && !q.answer.trim() && (!q.taskIds?.length || q.taskIds.includes(task.id)));
40
+ if (attempt) {
41
+ const active = ['starting', 'running', 'waiting'].includes(attempt.status);
42
+ if (child?.status === 'unavailable') {
43
+ node.status = 'failed';
44
+ node.statusLabel = 'Unavailable';
45
+ node.reason = child.error;
46
+ node.unavailable = true;
47
+ }
48
+ else if (active && (attempt.pendingApprovals || child?.pendingApprovals)) {
49
+ node.status = 'attention';
50
+ node.statusLabel = 'Needs permission';
51
+ node.reason = 'Open the conversation to review the pending command.';
52
+ }
53
+ else if (active && (attempt.question || child?.pendingQuestions)) {
54
+ node.status = 'attention';
55
+ node.statusLabel = 'Question';
56
+ node.reason = attempt.question || 'The agent needs your answer to continue.';
57
+ }
58
+ else if (done(attempt)) {
59
+ node.status = 'done';
60
+ node.statusLabel = 'Done';
61
+ node.reason = attempt.result?.summary;
62
+ }
63
+ else if (attempt.status === 'failed' || attempt.status === 'interrupted') {
64
+ node.status = attempt.status === 'failed' ? 'failed' : 'attention';
65
+ node.statusLabel = attempt.status === 'failed' ? 'Failed' : 'Interrupted';
66
+ node.reason = attempt.error || 'Open task controls to review and retry this attempt.';
67
+ }
68
+ else if (attempt.status === 'queued') {
69
+ const paused = delegation?.paused && !attempt.resumeRequested;
70
+ node.status = unmet.length || attempt.blockedReason ? 'blocked' : 'idle';
71
+ node.statusLabel = paused ? 'Paused' : node.status === 'blocked' ? 'Blocked' : 'Queued';
72
+ node.reason = attempt.blockedReason || (paused ? 'Task execution is paused.' : undefined);
73
+ }
74
+ else if (attempt.status === 'cancelled') {
75
+ node.statusLabel = 'Cancelled';
76
+ }
77
+ else {
78
+ node.status = attempt.status === 'waiting' ? 'attention' : 'running';
79
+ node.statusLabel = attempt.status === 'waiting' ? 'Waiting' : 'Running';
80
+ }
81
+ }
82
+ else if (question || task.status === 'needs_clarification') {
83
+ node.status = 'attention';
84
+ node.statusLabel = 'Needs clarification';
85
+ node.reason = question?.text || 'Clarify the scope with the coordinator.';
86
+ }
87
+ else if (task.status === 'ready' && task.criteria.trim()) {
88
+ node.status = unmet.length ? 'blocked' : 'ready';
89
+ node.statusLabel = unmet.length ? 'Blocked' : 'Ready';
90
+ }
91
+ else if (task.status === 'deferred')
92
+ node.statusLabel = 'Deferred';
93
+ if (node.status === 'blocked' && !node.reason)
94
+ node.reason = `Waiting for ${unmet.map((id) => taskDisplayId(id, references) ?? id).join(', ')} to finish.`;
95
+ nodes.push(node);
96
+ edges.push({ from: sessionKey(session.id), to: node.id, kind: 'child' });
97
+ for (const id of task.dependencies ?? [])
98
+ if (tasks.has(id))
99
+ edges.push({ from: taskKey(session.id, id), to: node.id, kind: 'dependency' });
100
+ }
101
+ for (const attempt of delegation?.attempts ?? [])
102
+ aliases.set(attempt.sessionId, taskKey(session.id, attempt.taskId));
103
+ }
104
+ for (const session of sessions) {
105
+ if ((session.archived && !session.activeChecks) || aliases.has(session.id))
106
+ continue;
107
+ // An unused main workspace adds no context to a project's graph.
108
+ if (session.id === 'main' &&
109
+ !session.runs &&
110
+ !stateFor(session.id)?.checks?.length &&
111
+ !edges.some((edge) => edge.from === sessionKey('main')) &&
112
+ !sessions.some((child) => !child.archived && child.parentSessionId === 'main'))
113
+ continue;
114
+ const node = {
115
+ id: sessionKey(session.id),
116
+ kind: 'session',
117
+ title: session.id === 'main' ? 'Main workspace' : session.title,
118
+ sessionId: session.id,
119
+ branch: session.branch,
120
+ description: session.latestActivity?.slice(0, 600),
121
+ status: 'idle',
122
+ statusLabel: 'Idle',
123
+ unavailable: session.status === 'unavailable',
124
+ };
125
+ if (session.pendingApprovals || session.pendingQuestions || session.status === 'waiting') {
126
+ node.status = 'attention';
127
+ node.statusLabel = session.pendingApprovals
128
+ ? 'Needs permission'
129
+ : session.pendingQuestions
130
+ ? 'Question'
131
+ : 'Waiting';
132
+ }
133
+ else if (session.status === 'running') {
134
+ node.status = 'running';
135
+ node.statusLabel = 'Running';
136
+ }
137
+ else if (session.status === 'completed') {
138
+ node.status = 'done';
139
+ node.statusLabel = 'Done';
140
+ }
141
+ else if (session.status === 'failed' || session.status === 'unavailable') {
142
+ node.status = 'failed';
143
+ node.statusLabel = session.status === 'failed' ? 'Failed' : 'Unavailable';
144
+ node.reason = session.error;
145
+ }
146
+ else if (session.status === 'interrupted') {
147
+ node.status = 'attention';
148
+ node.statusLabel = 'Interrupted';
149
+ }
150
+ nodes.push(node);
151
+ const parent = session.parentSessionId ?? session.assignment?.coordinatorId;
152
+ if (parent)
153
+ edges.push({ from: aliases.get(parent) ?? sessionKey(parent), to: node.id, kind: 'child' });
154
+ }
155
+ for (const session of sessions) {
156
+ for (const check of stateFor(session.id)?.checks ?? []) {
157
+ if (session.archived && !activeCheck(check))
158
+ continue;
159
+ const id = `check:${session.id}:${check.id}`;
160
+ nodes.push({
161
+ id,
162
+ kind: 'check',
163
+ title: check.purpose,
164
+ tag: 'Check',
165
+ sessionId: session.id,
166
+ checkId: check.id,
167
+ checkActive: activeCheck(check),
168
+ status: check.state === 'succeeded'
169
+ ? 'done'
170
+ : check.state === 'awaiting_approval'
171
+ ? 'attention'
172
+ : activeCheck(check)
173
+ ? 'running'
174
+ : 'failed',
175
+ statusLabel: check.state.replaceAll('_', ' '),
176
+ description: check.command,
177
+ reason: `${check.startedAt ? 'Ran in mutable workspace.' : 'Mutable workspace; startup not yet confirmed.'} ${check.reason ?? 'No revision verification or task completion implied.'}`,
178
+ });
179
+ const origin = check.taskId &&
180
+ nodes.find((n) => n.kind === 'task' && n.coordinatorId === session.id && n.taskId === check.taskId)?.id;
181
+ edges.push({
182
+ from: origin || aliases.get(session.id) || sessionKey(session.id),
183
+ to: id,
184
+ kind: 'child',
185
+ });
186
+ }
187
+ }
188
+ const ids = new Set(nodes.map((node) => node.id));
189
+ return { nodes, edges: edges.filter((edge) => ids.has(edge.from) && ids.has(edge.to)) };
190
+ }
@@ -0,0 +1,74 @@
1
+ /** Retain recent output and tool metadata without copying arbitrary event payloads. */
2
+ export function taskLogs(events) {
3
+ let textBudget = 16000;
4
+ let argsBudget = 16000;
5
+ let traceBudget = 64000;
6
+ return events
7
+ .filter((event) => (event.text || event.toolName || event.type.startsWith('tool_')) &&
8
+ !['command', 'task_progress'].includes(event.type))
9
+ .slice(-40)
10
+ .reverse()
11
+ .flatMap((event) => {
12
+ // Exhausting output must not discard earlier tool identities/history.
13
+ const text = textBudget ? event.text?.slice(-Math.min(2000, textBudget)) : '';
14
+ textBudget -= text?.length ?? 0;
15
+ const source = event.data;
16
+ const data = {};
17
+ if (event.text && text !== event.text)
18
+ data.textTruncated = true;
19
+ if ([
20
+ 'shell_evaluation_request',
21
+ 'session_routing_request',
22
+ 'jev_task_routing_request',
23
+ 'jev_shell_safety_request',
24
+ 'jev_agent_consult_request',
25
+ ].includes(event.type) &&
26
+ source?.request) {
27
+ const serialized = JSON.stringify(source.request);
28
+ if (serialized.length <= traceBudget) {
29
+ data.request = JSON.parse(serialized);
30
+ traceBudget -= serialized.length;
31
+ }
32
+ }
33
+ if (typeof source?.toolCallId === 'string' && source.toolCallId.length <= 200)
34
+ data.toolCallId = source.toolCallId;
35
+ if (typeof source?.isError === 'boolean')
36
+ data.isError = source.isError;
37
+ if (source?.args != null) {
38
+ const serialized = JSON.stringify(source.args);
39
+ if (serialized.length <= Math.min(4000, argsBudget)) {
40
+ data.args = JSON.parse(serialized);
41
+ data.argsTruncated = false;
42
+ argsBudget -= serialized.length;
43
+ }
44
+ else {
45
+ data.argsTruncated = true;
46
+ const args = source.args;
47
+ const summary = {};
48
+ for (const key of ['path', 'file', 'command', 'query', 'pattern', 'side', 'title']) {
49
+ const value = args[key];
50
+ if (typeof value === 'string' &&
51
+ value.length <= 500 &&
52
+ value.length + 32 <= argsBudget) {
53
+ summary[key] = value;
54
+ argsBudget -= value.length + 32;
55
+ }
56
+ }
57
+ if (Object.keys(summary).length)
58
+ data.args = summary;
59
+ }
60
+ }
61
+ return [
62
+ {
63
+ seq: event.seq,
64
+ runId: event.runId,
65
+ type: event.type,
66
+ toolName: event.toolName,
67
+ createdAt: event.createdAt,
68
+ text,
69
+ ...(Object.keys(data).length ? { data } : {}),
70
+ },
71
+ ];
72
+ })
73
+ .reverse();
74
+ }
@@ -0,0 +1,25 @@
1
+ /** Stable labels shared by proposals and directly started work within one coordinator session. */
2
+ export function createTaskNumbers(store) {
3
+ const numbers = store.get('taskDisplayNumbers') ?? {};
4
+ const nextByCoordinator = new Map();
5
+ for (const [storedKey, number] of Object.entries(numbers)) {
6
+ try {
7
+ const parsed = JSON.parse(storedKey);
8
+ if (Array.isArray(parsed) && parsed.length === 2 && typeof parsed[0] === 'string')
9
+ nextByCoordinator.set(parsed[0], Math.max(nextByCoordinator.get(parsed[0]) ?? 0, number));
10
+ }
11
+ catch {
12
+ // Legacy project-wide keys are retained, but do not advance new session-local counters.
13
+ }
14
+ }
15
+ return (coordinatorId, itemId, preferred) => {
16
+ const key = JSON.stringify([coordinatorId, itemId]);
17
+ if (Object.hasOwn(numbers, key))
18
+ return numbers[key];
19
+ const next = Math.max(nextByCoordinator.get(coordinatorId) ?? 0, preferred ?? 0);
20
+ numbers[key] = preferred ?? next + 1;
21
+ nextByCoordinator.set(coordinatorId, Math.max(next, numbers[key]));
22
+ store.put('taskDisplayNumbers', numbers);
23
+ return numbers[key];
24
+ };
25
+ }