@cleocode/core 2026.3.43 → 2026.3.44

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 (161) hide show
  1. package/dist/admin/export-tasks.d.ts.map +1 -1
  2. package/dist/agents/agent-schema.d.ts +358 -0
  3. package/dist/agents/agent-schema.d.ts.map +1 -0
  4. package/dist/agents/capacity.d.ts +57 -0
  5. package/dist/agents/capacity.d.ts.map +1 -0
  6. package/dist/agents/index.d.ts +17 -0
  7. package/dist/agents/index.d.ts.map +1 -0
  8. package/dist/agents/registry.d.ts +115 -0
  9. package/dist/agents/registry.d.ts.map +1 -0
  10. package/dist/agents/retry.d.ts +83 -0
  11. package/dist/agents/retry.d.ts.map +1 -0
  12. package/dist/hooks/index.d.ts +4 -1
  13. package/dist/hooks/index.d.ts.map +1 -1
  14. package/dist/hooks/payload-schemas.d.ts +214 -0
  15. package/dist/hooks/payload-schemas.d.ts.map +1 -0
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +16443 -2160
  19. package/dist/index.js.map +4 -4
  20. package/dist/inject/index.d.ts.map +1 -1
  21. package/dist/intelligence/impact.d.ts +51 -0
  22. package/dist/intelligence/impact.d.ts.map +1 -0
  23. package/dist/intelligence/index.d.ts +15 -0
  24. package/dist/intelligence/index.d.ts.map +1 -0
  25. package/dist/intelligence/patterns.d.ts +66 -0
  26. package/dist/intelligence/patterns.d.ts.map +1 -0
  27. package/dist/intelligence/prediction.d.ts +51 -0
  28. package/dist/intelligence/prediction.d.ts.map +1 -0
  29. package/dist/intelligence/types.d.ts +221 -0
  30. package/dist/intelligence/types.d.ts.map +1 -0
  31. package/dist/internal.d.ts +9 -0
  32. package/dist/internal.d.ts.map +1 -1
  33. package/dist/issue/template-parser.d.ts +8 -2
  34. package/dist/issue/template-parser.d.ts.map +1 -1
  35. package/dist/lifecycle/pipeline.d.ts +2 -2
  36. package/dist/lifecycle/pipeline.d.ts.map +1 -1
  37. package/dist/lifecycle/state-machine.d.ts +1 -1
  38. package/dist/lifecycle/state-machine.d.ts.map +1 -1
  39. package/dist/memory/brain-lifecycle.d.ts.map +1 -1
  40. package/dist/memory/brain-retrieval.d.ts.map +1 -1
  41. package/dist/memory/brain-row-types.d.ts +40 -6
  42. package/dist/memory/brain-row-types.d.ts.map +1 -1
  43. package/dist/memory/brain-search.d.ts.map +1 -1
  44. package/dist/memory/brain-similarity.d.ts.map +1 -1
  45. package/dist/memory/claude-mem-migration.d.ts.map +1 -1
  46. package/dist/nexus/discover.d.ts.map +1 -1
  47. package/dist/orchestration/bootstrap.d.ts.map +1 -1
  48. package/dist/orchestration/skill-ops.d.ts +4 -4
  49. package/dist/orchestration/skill-ops.d.ts.map +1 -1
  50. package/dist/otel/index.d.ts +1 -1
  51. package/dist/otel/index.d.ts.map +1 -1
  52. package/dist/sessions/briefing.d.ts.map +1 -1
  53. package/dist/sessions/handoff.d.ts.map +1 -1
  54. package/dist/sessions/index.d.ts +1 -1
  55. package/dist/sessions/index.d.ts.map +1 -1
  56. package/dist/sessions/types.d.ts +8 -42
  57. package/dist/sessions/types.d.ts.map +1 -1
  58. package/dist/signaldock/signaldock-transport.d.ts +1 -1
  59. package/dist/signaldock/signaldock-transport.d.ts.map +1 -1
  60. package/dist/skills/injection/subagent.d.ts +3 -3
  61. package/dist/skills/injection/subagent.d.ts.map +1 -1
  62. package/dist/skills/manifests/contribution.d.ts +2 -2
  63. package/dist/skills/manifests/contribution.d.ts.map +1 -1
  64. package/dist/skills/orchestrator/spawn.d.ts +6 -6
  65. package/dist/skills/orchestrator/spawn.d.ts.map +1 -1
  66. package/dist/skills/orchestrator/startup.d.ts +1 -1
  67. package/dist/skills/orchestrator/startup.d.ts.map +1 -1
  68. package/dist/skills/orchestrator/validator.d.ts +2 -2
  69. package/dist/skills/orchestrator/validator.d.ts.map +1 -1
  70. package/dist/skills/precedence-types.d.ts +24 -1
  71. package/dist/skills/precedence-types.d.ts.map +1 -1
  72. package/dist/skills/types.d.ts +70 -4
  73. package/dist/skills/types.d.ts.map +1 -1
  74. package/dist/store/export.d.ts +5 -4
  75. package/dist/store/export.d.ts.map +1 -1
  76. package/dist/store/tasks-schema.d.ts +12 -2
  77. package/dist/store/tasks-schema.d.ts.map +1 -1
  78. package/dist/store/typed-query.d.ts +12 -0
  79. package/dist/store/typed-query.d.ts.map +1 -0
  80. package/dist/store/validation-schemas.d.ts +2422 -50
  81. package/dist/store/validation-schemas.d.ts.map +1 -1
  82. package/dist/system/inject-generate.d.ts.map +1 -1
  83. package/dist/validation/doctor/checks.d.ts +5 -0
  84. package/dist/validation/doctor/checks.d.ts.map +1 -1
  85. package/dist/validation/engine.d.ts +10 -10
  86. package/dist/validation/engine.d.ts.map +1 -1
  87. package/dist/validation/index.d.ts +6 -2
  88. package/dist/validation/index.d.ts.map +1 -1
  89. package/dist/validation/protocol-common.d.ts +10 -2
  90. package/dist/validation/protocol-common.d.ts.map +1 -1
  91. package/migrations/drizzle-tasks/20260320013731_wave0-schema-hardening/migration.sql +84 -0
  92. package/migrations/drizzle-tasks/20260320013731_wave0-schema-hardening/snapshot.json +4060 -0
  93. package/migrations/drizzle-tasks/20260320020000_agent-dimension/migration.sql +35 -0
  94. package/migrations/drizzle-tasks/20260320020000_agent-dimension/snapshot.json +4312 -0
  95. package/package.json +2 -2
  96. package/src/admin/export-tasks.ts +2 -5
  97. package/src/agents/__tests__/capacity.test.ts +219 -0
  98. package/src/agents/__tests__/registry.test.ts +457 -0
  99. package/src/agents/__tests__/retry.test.ts +289 -0
  100. package/src/agents/agent-schema.ts +107 -0
  101. package/src/agents/capacity.ts +151 -0
  102. package/src/agents/index.ts +68 -0
  103. package/src/agents/registry.ts +449 -0
  104. package/src/agents/retry.ts +255 -0
  105. package/src/hooks/index.ts +20 -1
  106. package/src/hooks/payload-schemas.ts +199 -0
  107. package/src/index.ts +69 -0
  108. package/src/inject/index.ts +14 -14
  109. package/src/intelligence/__tests__/impact.test.ts +453 -0
  110. package/src/intelligence/__tests__/patterns.test.ts +450 -0
  111. package/src/intelligence/__tests__/prediction.test.ts +418 -0
  112. package/src/intelligence/impact.ts +638 -0
  113. package/src/intelligence/index.ts +47 -0
  114. package/src/intelligence/patterns.ts +621 -0
  115. package/src/intelligence/prediction.ts +621 -0
  116. package/src/intelligence/types.ts +273 -0
  117. package/src/internal.ts +82 -1
  118. package/src/issue/template-parser.ts +65 -4
  119. package/src/lifecycle/pipeline.ts +14 -7
  120. package/src/lifecycle/state-machine.ts +6 -2
  121. package/src/memory/brain-lifecycle.ts +5 -11
  122. package/src/memory/brain-retrieval.ts +44 -38
  123. package/src/memory/brain-row-types.ts +43 -6
  124. package/src/memory/brain-search.ts +53 -32
  125. package/src/memory/brain-similarity.ts +9 -8
  126. package/src/memory/claude-mem-migration.ts +4 -3
  127. package/src/nexus/__tests__/nexus-e2e.test.ts +1481 -0
  128. package/src/nexus/discover.ts +1 -0
  129. package/src/orchestration/bootstrap.ts +11 -17
  130. package/src/orchestration/skill-ops.ts +52 -32
  131. package/src/otel/index.ts +48 -4
  132. package/src/sessions/__tests__/briefing.test.ts +31 -2
  133. package/src/sessions/briefing.ts +27 -42
  134. package/src/sessions/handoff.ts +52 -86
  135. package/src/sessions/index.ts +5 -1
  136. package/src/sessions/types.ts +9 -43
  137. package/src/signaldock/signaldock-transport.ts +5 -2
  138. package/src/skills/injection/subagent.ts +10 -16
  139. package/src/skills/manifests/contribution.ts +5 -13
  140. package/src/skills/orchestrator/__tests__/spawn-tier.test.ts +44 -30
  141. package/src/skills/orchestrator/spawn.ts +18 -31
  142. package/src/skills/orchestrator/startup.ts +78 -65
  143. package/src/skills/orchestrator/validator.ts +26 -31
  144. package/src/skills/precedence-types.ts +24 -1
  145. package/src/skills/types.ts +72 -5
  146. package/src/store/__tests__/test-db-helper.d.ts +4 -4
  147. package/src/store/__tests__/test-db-helper.js +5 -16
  148. package/src/store/__tests__/test-db-helper.ts +5 -18
  149. package/src/store/chain-schema.ts +1 -1
  150. package/src/store/export.ts +22 -12
  151. package/src/store/tasks-schema.ts +65 -8
  152. package/src/store/typed-query.ts +17 -0
  153. package/src/store/validation-schemas.ts +347 -23
  154. package/src/system/inject-generate.ts +9 -23
  155. package/src/validation/doctor/checks.ts +24 -2
  156. package/src/validation/engine.ts +11 -11
  157. package/src/validation/index.ts +131 -3
  158. package/src/validation/protocol-common.ts +54 -3
  159. package/dist/tasks/reparent.d.ts +0 -38
  160. package/dist/tasks/reparent.d.ts.map +0 -1
  161. package/src/tasks/reparent.ts +0 -134
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/core",
3
- "version": "2026.3.43",
3
+ "version": "2026.3.44",
4
4
  "description": "CLEO core business logic kernel — tasks, sessions, memory, orchestration, lifecycle, with bundled SQLite store",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "write-file-atomic": "^6.0.0",
37
37
  "yaml": "^2.8.2",
38
38
  "zod": "^3.25.76",
39
- "@cleocode/contracts": "2026.3.43"
39
+ "@cleocode/contracts": "2026.3.44"
40
40
  },
41
41
  "engines": {
42
42
  "node": ">=24.0.0"
@@ -175,15 +175,12 @@ export async function exportTasksPackage(params: ExportTasksParams): Promise<Exp
175
175
  }
176
176
 
177
177
  const projectMeta = await accessor.getMetaValue<{ name?: string }>('project');
178
- const taskData = {
179
- tasks: allTasks,
180
- project: projectMeta,
181
- } as import('@cleocode/contracts').TaskFile;
182
- const pkg = buildExportPackage(selectedTasks, taskData, {
178
+ const pkg = buildExportPackage(selectedTasks, {
183
179
  mode: exportMode,
184
180
  rootTaskIds: parsedIds.length > 0 ? parsedIds : selectedTasks.map((t) => t.id),
185
181
  includeChildren: subtreeMode,
186
182
  filters: filters.length > 0 ? filters : undefined,
183
+ projectName: projectMeta?.name,
187
184
  });
188
185
 
189
186
  const content = JSON.stringify(pkg, null, 2);
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Tests for capacity tracking and load balancing.
3
+ *
4
+ * @module agents/__tests__/capacity.test
5
+ */
6
+
7
+ import { mkdir, mkdtemp, rm } from 'node:fs/promises';
8
+ import { tmpdir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
11
+
12
+ import {
13
+ findLeastLoadedAgent,
14
+ getAvailableCapacity,
15
+ getCapacitySummary,
16
+ isOverloaded,
17
+ updateCapacity,
18
+ } from '../capacity.js';
19
+ import { registerAgent, updateAgentStatus } from '../registry.js';
20
+
21
+ describe('Capacity Tracking', () => {
22
+ let tempDir: string;
23
+
24
+ beforeEach(async () => {
25
+ tempDir = await mkdtemp(join(tmpdir(), 'cleo-capacity-test-'));
26
+ await mkdir(join(tempDir, '.cleo'), { recursive: true });
27
+ await mkdir(join(tempDir, '.cleo', 'backups', 'operational'), { recursive: true });
28
+ });
29
+
30
+ afterEach(async () => {
31
+ try {
32
+ const { closeAllDatabases } = await import('../../store/sqlite.js');
33
+ await closeAllDatabases();
34
+ } catch {
35
+ /* module may not be loaded */
36
+ }
37
+ await Promise.race([
38
+ rm(tempDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 300 }).catch(() => {}),
39
+ new Promise<void>((resolve) => setTimeout(resolve, 8_000)),
40
+ ]);
41
+ });
42
+
43
+ // ==========================================================================
44
+ // updateCapacity
45
+ // ==========================================================================
46
+
47
+ describe('updateCapacity', () => {
48
+ it('updates capacity value', async () => {
49
+ const agent = await registerAgent({ agentType: 'executor' }, tempDir);
50
+ const updated = await updateCapacity(agent.id, 0.5, tempDir);
51
+
52
+ expect(updated).not.toBeNull();
53
+ expect(parseFloat(updated!.capacity)).toBeCloseTo(0.5, 4);
54
+ });
55
+
56
+ it('returns null for non-existent agent', async () => {
57
+ const result = await updateCapacity('agt_nonexistent_abc123', 0.5, tempDir);
58
+ expect(result).toBeNull();
59
+ });
60
+
61
+ it('rejects capacity below 0', async () => {
62
+ const agent = await registerAgent({ agentType: 'executor' }, tempDir);
63
+ await expect(updateCapacity(agent.id, -0.1, tempDir)).rejects.toThrow(
64
+ 'Capacity must be between 0.0 and 1.0',
65
+ );
66
+ });
67
+
68
+ it('rejects capacity above 1', async () => {
69
+ const agent = await registerAgent({ agentType: 'executor' }, tempDir);
70
+ await expect(updateCapacity(agent.id, 1.5, tempDir)).rejects.toThrow(
71
+ 'Capacity must be between 0.0 and 1.0',
72
+ );
73
+ });
74
+
75
+ it('accepts boundary values', async () => {
76
+ const agent = await registerAgent({ agentType: 'executor' }, tempDir);
77
+
78
+ const zero = await updateCapacity(agent.id, 0, tempDir);
79
+ expect(parseFloat(zero!.capacity)).toBeCloseTo(0, 4);
80
+
81
+ const one = await updateCapacity(agent.id, 1, tempDir);
82
+ expect(parseFloat(one!.capacity)).toBeCloseTo(1, 4);
83
+ });
84
+ });
85
+
86
+ // ==========================================================================
87
+ // getAvailableCapacity
88
+ // ==========================================================================
89
+
90
+ describe('getAvailableCapacity', () => {
91
+ it('sums capacity of active and idle agents', async () => {
92
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
93
+ const a2 = await registerAgent({ agentType: 'researcher' }, tempDir);
94
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
95
+ await updateAgentStatus(a2.id, { status: 'idle' }, tempDir);
96
+ await updateCapacity(a1.id, 0.7, tempDir);
97
+ await updateCapacity(a2.id, 0.3, tempDir);
98
+
99
+ const capacity = await getAvailableCapacity(tempDir);
100
+ expect(capacity).toBeCloseTo(1.0, 1);
101
+ });
102
+
103
+ it('excludes stopped and crashed agents', async () => {
104
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
105
+ const a2 = await registerAgent({ agentType: 'researcher' }, tempDir);
106
+ const a3 = await registerAgent({ agentType: 'validator' }, tempDir);
107
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
108
+ await updateAgentStatus(a2.id, { status: 'stopped' }, tempDir);
109
+ await updateAgentStatus(a3.id, { status: 'crashed' }, tempDir);
110
+
111
+ const capacity = await getAvailableCapacity(tempDir);
112
+ // Only a1 contributes (1.0 default)
113
+ expect(capacity).toBeCloseTo(1.0, 1);
114
+ });
115
+
116
+ it('returns 0 when no active agents', async () => {
117
+ const capacity = await getAvailableCapacity(tempDir);
118
+ expect(capacity).toBe(0);
119
+ });
120
+ });
121
+
122
+ // ==========================================================================
123
+ // findLeastLoadedAgent
124
+ // ==========================================================================
125
+
126
+ describe('findLeastLoadedAgent', () => {
127
+ it('finds agent with highest capacity', async () => {
128
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
129
+ const a2 = await registerAgent({ agentType: 'executor' }, tempDir);
130
+ const a3 = await registerAgent({ agentType: 'executor' }, tempDir);
131
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
132
+ await updateAgentStatus(a2.id, { status: 'active' }, tempDir);
133
+ await updateAgentStatus(a3.id, { status: 'active' }, tempDir);
134
+ await updateCapacity(a1.id, 0.2, tempDir);
135
+ await updateCapacity(a2.id, 0.8, tempDir);
136
+ await updateCapacity(a3.id, 0.5, tempDir);
137
+
138
+ const least = await findLeastLoadedAgent(undefined, tempDir);
139
+ expect(least).not.toBeNull();
140
+ expect(least!.id).toBe(a2.id);
141
+ });
142
+
143
+ it('filters by agent type', async () => {
144
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
145
+ const a2 = await registerAgent({ agentType: 'researcher' }, tempDir);
146
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
147
+ await updateAgentStatus(a2.id, { status: 'active' }, tempDir);
148
+ await updateCapacity(a1.id, 0.3, tempDir);
149
+ await updateCapacity(a2.id, 0.9, tempDir);
150
+
151
+ const least = await findLeastLoadedAgent('executor', tempDir);
152
+ expect(least).not.toBeNull();
153
+ expect(least!.id).toBe(a1.id);
154
+ expect(least!.agentType).toBe('executor');
155
+ });
156
+
157
+ it('returns null when no matching agents', async () => {
158
+ const result = await findLeastLoadedAgent('orchestrator', tempDir);
159
+ expect(result).toBeNull();
160
+ });
161
+ });
162
+
163
+ // ==========================================================================
164
+ // isOverloaded
165
+ // ==========================================================================
166
+
167
+ describe('isOverloaded', () => {
168
+ it('returns true when capacity below threshold', async () => {
169
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
170
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
171
+ await updateCapacity(a1.id, 0.05, tempDir);
172
+
173
+ expect(await isOverloaded(0.1, tempDir)).toBe(true);
174
+ });
175
+
176
+ it('returns false when capacity above threshold', async () => {
177
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
178
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
179
+ await updateCapacity(a1.id, 0.5, tempDir);
180
+
181
+ expect(await isOverloaded(0.1, tempDir)).toBe(false);
182
+ });
183
+
184
+ it('returns true when no active agents (0 capacity)', async () => {
185
+ expect(await isOverloaded(0.1, tempDir)).toBe(true);
186
+ });
187
+ });
188
+
189
+ // ==========================================================================
190
+ // getCapacitySummary
191
+ // ==========================================================================
192
+
193
+ describe('getCapacitySummary', () => {
194
+ it('produces correct summary', async () => {
195
+ const a1 = await registerAgent({ agentType: 'executor' }, tempDir);
196
+ const a2 = await registerAgent({ agentType: 'researcher' }, tempDir);
197
+ await updateAgentStatus(a1.id, { status: 'active' }, tempDir);
198
+ await updateAgentStatus(a2.id, { status: 'idle' }, tempDir);
199
+ await updateCapacity(a1.id, 0.6, tempDir);
200
+ await updateCapacity(a2.id, 0.4, tempDir);
201
+
202
+ const summary = await getCapacitySummary(0.1, tempDir);
203
+
204
+ expect(summary.totalCapacity).toBeCloseTo(1.0, 1);
205
+ expect(summary.activeAgentCount).toBe(2);
206
+ expect(summary.averageCapacity).toBeCloseTo(0.5, 1);
207
+ expect(summary.overloaded).toBe(false);
208
+ expect(summary.threshold).toBe(0.1);
209
+ });
210
+
211
+ it('reports overloaded when below threshold', async () => {
212
+ const summary = await getCapacitySummary(0.5, tempDir);
213
+
214
+ expect(summary.totalCapacity).toBe(0);
215
+ expect(summary.activeAgentCount).toBe(0);
216
+ expect(summary.overloaded).toBe(true);
217
+ });
218
+ });
219
+ });