@renxqoo/renx-code 0.0.4 → 0.0.5

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 (209) hide show
  1. package/bin/renx.cjs +16 -0
  2. package/package.json +2 -45
  3. package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
  4. package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
  5. package/src/agent/runtime/runtime.test.ts +7 -4
  6. package/src/agent/runtime/runtime.ts +3 -9
  7. package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
  8. package/src/agent/runtime/source-modules.test.ts +16 -35
  9. package/src/agent/runtime/source-modules.ts +17 -0
  10. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
  11. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
  12. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
  13. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
  14. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
  15. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
  16. package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
  17. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
  18. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
  19. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
  20. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
  21. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
  22. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
  23. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
  24. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
  25. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
  26. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
  27. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
  28. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
  29. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
  30. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
  31. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
  32. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
  33. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
  34. package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
  35. package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
  36. package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
  37. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
  38. package/vendor/agent-root/src/agent/agent/error.ts +198 -0
  39. package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
  40. package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
  41. package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
  42. package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
  43. package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
  44. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
  45. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
  46. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
  47. package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
  48. package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
  49. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
  50. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
  51. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
  52. package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
  53. package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
  54. package/vendor/agent-root/src/agent/app/index.ts +5 -0
  55. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
  56. package/vendor/agent-root/src/agent/app/ports.ts +72 -0
  57. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
  58. package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
  59. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
  60. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
  61. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
  62. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
  63. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
  64. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
  65. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
  66. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
  67. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
  68. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
  69. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
  70. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
  71. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
  72. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
  73. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
  74. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
  75. package/vendor/agent-root/src/agent/error-contract.ts +154 -0
  76. package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
  77. package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
  78. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
  79. package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
  80. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
  81. package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
  82. package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
  83. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
  84. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
  85. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
  86. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
  87. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
  88. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
  89. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
  90. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
  91. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
  92. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
  93. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
  94. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
  95. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
  96. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
  97. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
  98. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
  99. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
  100. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
  101. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
  102. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
  103. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
  104. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
  105. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
  106. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
  107. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
  108. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
  109. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
  110. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
  111. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
  112. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
  113. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
  114. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
  115. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
  116. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
  117. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
  118. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
  119. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
  120. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
  121. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
  122. package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
  123. package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
  124. package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
  125. package/vendor/agent-root/src/agent/tool/error.ts +131 -0
  126. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
  127. package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
  128. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
  129. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
  130. package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
  131. package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
  132. package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
  133. package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
  134. package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
  135. package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
  136. package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
  137. package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
  138. package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
  139. package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
  140. package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
  141. package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
  142. package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
  143. package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
  144. package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
  145. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
  146. package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
  147. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
  148. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
  149. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
  150. package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
  151. package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
  152. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
  153. package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
  154. package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
  155. package/vendor/agent-root/src/agent/tool/task.ts +209 -0
  156. package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
  157. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
  158. package/vendor/agent-root/src/agent/tool/types.ts +116 -0
  159. package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
  160. package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
  161. package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
  162. package/vendor/agent-root/src/agent/types.ts +232 -0
  163. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
  164. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
  165. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
  166. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
  167. package/vendor/agent-root/src/agent/utils/index.ts +16 -0
  168. package/vendor/agent-root/src/agent/utils/message.ts +171 -0
  169. package/vendor/agent-root/src/agent/utils/token.ts +28 -0
  170. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
  171. package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
  172. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
  173. package/vendor/agent-root/src/config/index.ts +54 -0
  174. package/vendor/agent-root/src/config/loader.ts +431 -0
  175. package/vendor/agent-root/src/config/paths.ts +30 -0
  176. package/vendor/agent-root/src/config/runtime.ts +163 -0
  177. package/vendor/agent-root/src/config/types.ts +70 -0
  178. package/vendor/agent-root/src/logger/index.ts +57 -0
  179. package/vendor/agent-root/src/logger/logger.ts +819 -0
  180. package/vendor/agent-root/src/logger/types.ts +150 -0
  181. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
  182. package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
  183. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
  184. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
  185. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
  186. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
  187. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
  188. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
  189. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
  190. package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
  191. package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
  192. package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
  193. package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
  194. package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
  195. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
  196. package/vendor/agent-root/src/providers/http/client.ts +289 -0
  197. package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
  198. package/vendor/agent-root/src/providers/index.ts +76 -0
  199. package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
  200. package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
  201. package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
  202. package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
  203. package/vendor/agent-root/src/providers/registry.ts +135 -0
  204. package/vendor/agent-root/src/providers/types/api.ts +284 -0
  205. package/vendor/agent-root/src/providers/types/config.ts +58 -0
  206. package/vendor/agent-root/src/providers/types/errors.ts +323 -0
  207. package/vendor/agent-root/src/providers/types/index.ts +72 -0
  208. package/vendor/agent-root/src/providers/types/provider.ts +45 -0
  209. package/vendor/agent-root/src/providers/types/registry.ts +88 -0
@@ -0,0 +1,494 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ TASK_STATUS_VALUES,
4
+ TASK_PRIORITY_VALUES,
5
+ AGENT_RUN_STATUS_VALUES,
6
+ SUBAGENT_TYPE_VALUES,
7
+ DEFAULT_RETRY_CONFIG,
8
+ VALID_TASK_TRANSITIONS,
9
+ createTaskId,
10
+ createAgentId,
11
+ isTaskTerminal,
12
+ isTaskFinal,
13
+ isAgentRunTerminal,
14
+ validateTaskTransition,
15
+ createEmptyNamespaceState,
16
+ evaluateTaskCanStart,
17
+ safeJsonClone,
18
+ } from '../task-types';
19
+ import type { TaskEntity } from '../task-types';
20
+
21
+ describe('constants', () => {
22
+ it('TASK_STATUS_VALUES contains expected values', () => {
23
+ expect(TASK_STATUS_VALUES).toEqual([
24
+ 'pending',
25
+ 'in_progress',
26
+ 'completed',
27
+ 'cancelled',
28
+ 'failed',
29
+ ]);
30
+ });
31
+
32
+ it('TASK_PRIORITY_VALUES contains expected values', () => {
33
+ expect(TASK_PRIORITY_VALUES).toEqual(['critical', 'high', 'normal', 'low']);
34
+ });
35
+
36
+ it('AGENT_RUN_STATUS_VALUES contains expected values', () => {
37
+ expect(AGENT_RUN_STATUS_VALUES).toEqual([
38
+ 'queued',
39
+ 'running',
40
+ 'completed',
41
+ 'failed',
42
+ 'cancelled',
43
+ 'paused',
44
+ 'timed_out',
45
+ ]);
46
+ });
47
+
48
+ it('SUBAGENT_TYPE_VALUES contains expected values', () => {
49
+ expect(SUBAGENT_TYPE_VALUES).toContain('Bash');
50
+ expect(SUBAGENT_TYPE_VALUES).toContain('general-purpose');
51
+ expect(SUBAGENT_TYPE_VALUES).toContain('Explore');
52
+ expect(SUBAGENT_TYPE_VALUES).toContain('Restore');
53
+ expect(SUBAGENT_TYPE_VALUES).toContain('Plan');
54
+ });
55
+
56
+ it('DEFAULT_RETRY_CONFIG has expected values', () => {
57
+ expect(DEFAULT_RETRY_CONFIG.maxRetries).toBe(3);
58
+ expect(DEFAULT_RETRY_CONFIG.retryDelayMs).toBe(5000);
59
+ expect(DEFAULT_RETRY_CONFIG.backoffMultiplier).toBe(2);
60
+ expect(DEFAULT_RETRY_CONFIG.retryOn).toEqual(['timeout', 'network_error']);
61
+ });
62
+
63
+ it('VALID_TASK_TRANSITIONS defines correct transitions', () => {
64
+ expect(VALID_TASK_TRANSITIONS.pending).toEqual(['in_progress', 'cancelled']);
65
+ expect(VALID_TASK_TRANSITIONS.in_progress).toEqual([
66
+ 'completed',
67
+ 'pending',
68
+ 'cancelled',
69
+ 'failed',
70
+ ]);
71
+ expect(VALID_TASK_TRANSITIONS.completed).toEqual([]);
72
+ expect(VALID_TASK_TRANSITIONS.cancelled).toEqual([]);
73
+ expect(VALID_TASK_TRANSITIONS.failed).toEqual(['pending']);
74
+ });
75
+ });
76
+
77
+ describe('createTaskId', () => {
78
+ it('creates unique task IDs', () => {
79
+ const id1 = createTaskId();
80
+ const id2 = createTaskId();
81
+
82
+ expect(id1).not.toBe(id2);
83
+ });
84
+
85
+ it('creates IDs with task_ prefix', () => {
86
+ const id = createTaskId();
87
+ expect(id.startsWith('task_')).toBe(true);
88
+ });
89
+
90
+ it('creates IDs with timestamp and UUID', () => {
91
+ const id = createTaskId();
92
+ const parts = id.split('_');
93
+
94
+ expect(parts.length).toBe(3);
95
+ expect(parts[0]).toBe('task');
96
+ expect(Number(parts[1])).toBeGreaterThan(0);
97
+ expect(parts[2]).toHaveLength(8);
98
+ });
99
+ });
100
+
101
+ describe('createAgentId', () => {
102
+ it('creates unique agent IDs', () => {
103
+ const id1 = createAgentId();
104
+ const id2 = createAgentId();
105
+
106
+ expect(id1).not.toBe(id2);
107
+ });
108
+
109
+ it('creates IDs with agent_ prefix', () => {
110
+ const id = createAgentId();
111
+ expect(id.startsWith('agent_')).toBe(true);
112
+ });
113
+
114
+ it('creates IDs with timestamp and UUID', () => {
115
+ const id = createAgentId();
116
+ const parts = id.split('_');
117
+
118
+ expect(parts.length).toBe(3);
119
+ expect(parts[0]).toBe('agent');
120
+ expect(Number(parts[1])).toBeGreaterThan(0);
121
+ expect(parts[2]).toHaveLength(8);
122
+ });
123
+ });
124
+
125
+ describe('isTaskTerminal', () => {
126
+ it('returns true for completed status', () => {
127
+ expect(isTaskTerminal('completed')).toBe(true);
128
+ });
129
+
130
+ it('returns true for cancelled status', () => {
131
+ expect(isTaskTerminal('cancelled')).toBe(true);
132
+ });
133
+
134
+ it('returns false for pending status', () => {
135
+ expect(isTaskTerminal('pending')).toBe(false);
136
+ });
137
+
138
+ it('returns false for in_progress status', () => {
139
+ expect(isTaskTerminal('in_progress')).toBe(false);
140
+ });
141
+
142
+ it('returns false for failed status', () => {
143
+ expect(isTaskTerminal('failed')).toBe(false);
144
+ });
145
+ });
146
+
147
+ describe('isTaskFinal', () => {
148
+ it('returns true for completed status', () => {
149
+ expect(isTaskFinal('completed')).toBe(true);
150
+ });
151
+
152
+ it('returns true for cancelled status', () => {
153
+ expect(isTaskFinal('cancelled')).toBe(true);
154
+ });
155
+
156
+ it('returns true for failed status', () => {
157
+ expect(isTaskFinal('failed')).toBe(true);
158
+ });
159
+
160
+ it('returns false for pending status', () => {
161
+ expect(isTaskFinal('pending')).toBe(false);
162
+ });
163
+
164
+ it('returns false for in_progress status', () => {
165
+ expect(isTaskFinal('in_progress')).toBe(false);
166
+ });
167
+ });
168
+
169
+ describe('isAgentRunTerminal', () => {
170
+ it('returns true for completed status', () => {
171
+ expect(isAgentRunTerminal('completed')).toBe(true);
172
+ });
173
+
174
+ it('returns true for failed status', () => {
175
+ expect(isAgentRunTerminal('failed')).toBe(true);
176
+ });
177
+
178
+ it('returns true for cancelled status', () => {
179
+ expect(isAgentRunTerminal('cancelled')).toBe(true);
180
+ });
181
+
182
+ it('returns true for timed_out status', () => {
183
+ expect(isAgentRunTerminal('timed_out')).toBe(true);
184
+ });
185
+
186
+ it('returns false for queued status', () => {
187
+ expect(isAgentRunTerminal('queued')).toBe(false);
188
+ });
189
+
190
+ it('returns false for running status', () => {
191
+ expect(isAgentRunTerminal('running')).toBe(false);
192
+ });
193
+
194
+ it('returns false for paused status', () => {
195
+ expect(isAgentRunTerminal('paused')).toBe(false);
196
+ });
197
+ });
198
+
199
+ describe('validateTaskTransition', () => {
200
+ it('allows same status transition', () => {
201
+ expect(validateTaskTransition('pending', 'pending')).toBe(true);
202
+ expect(validateTaskTransition('in_progress', 'in_progress')).toBe(true);
203
+ expect(validateTaskTransition('completed', 'completed')).toBe(true);
204
+ });
205
+
206
+ it('allows valid transitions from pending', () => {
207
+ expect(validateTaskTransition('pending', 'in_progress')).toBe(true);
208
+ expect(validateTaskTransition('pending', 'cancelled')).toBe(true);
209
+ });
210
+
211
+ it('denies invalid transitions from pending', () => {
212
+ expect(validateTaskTransition('pending', 'completed')).toBe(false);
213
+ expect(validateTaskTransition('pending', 'failed')).toBe(false);
214
+ });
215
+
216
+ it('allows valid transitions from in_progress', () => {
217
+ expect(validateTaskTransition('in_progress', 'completed')).toBe(true);
218
+ expect(validateTaskTransition('in_progress', 'pending')).toBe(true);
219
+ expect(validateTaskTransition('in_progress', 'cancelled')).toBe(true);
220
+ expect(validateTaskTransition('in_progress', 'failed')).toBe(true);
221
+ });
222
+
223
+ it('denies any transitions from completed', () => {
224
+ expect(validateTaskTransition('completed', 'pending')).toBe(false);
225
+ expect(validateTaskTransition('completed', 'in_progress')).toBe(false);
226
+ expect(validateTaskTransition('completed', 'cancelled')).toBe(false);
227
+ expect(validateTaskTransition('completed', 'failed')).toBe(false);
228
+ });
229
+
230
+ it('denies any transitions from cancelled', () => {
231
+ expect(validateTaskTransition('cancelled', 'pending')).toBe(false);
232
+ expect(validateTaskTransition('cancelled', 'in_progress')).toBe(false);
233
+ expect(validateTaskTransition('cancelled', 'completed')).toBe(false);
234
+ expect(validateTaskTransition('cancelled', 'failed')).toBe(false);
235
+ });
236
+
237
+ it('allows valid transitions from failed', () => {
238
+ expect(validateTaskTransition('failed', 'pending')).toBe(true);
239
+ });
240
+
241
+ it('denies invalid transitions from failed', () => {
242
+ expect(validateTaskTransition('failed', 'in_progress')).toBe(false);
243
+ expect(validateTaskTransition('failed', 'completed')).toBe(false);
244
+ expect(validateTaskTransition('failed', 'cancelled')).toBe(false);
245
+ });
246
+ });
247
+
248
+ describe('createEmptyNamespaceState', () => {
249
+ it('creates empty state with correct namespace', () => {
250
+ const state = createEmptyNamespaceState('test-namespace');
251
+
252
+ expect(state.namespace).toBe('test-namespace');
253
+ expect(state.tasks).toEqual({});
254
+ expect(state.agentRuns).toEqual({});
255
+ expect(state.graph.adjacency).toEqual({});
256
+ expect(state.graph.reverse).toEqual({});
257
+ expect(state.schemaVersion).toBe(1);
258
+ expect(state.updatedAt).toBeGreaterThan(0);
259
+ });
260
+
261
+ it('creates state with default namespace', () => {
262
+ const state = createEmptyNamespaceState('default');
263
+
264
+ expect(state.namespace).toBe('default');
265
+ });
266
+
267
+ it('creates state with empty string namespace', () => {
268
+ const state = createEmptyNamespaceState('');
269
+
270
+ expect(state.namespace).toBe('');
271
+ });
272
+ });
273
+
274
+ describe('evaluateTaskCanStart', () => {
275
+ const createTask = (overrides: Partial<TaskEntity> = {}): TaskEntity => ({
276
+ id: 'task_1',
277
+ subject: 'Test Task',
278
+ description: 'Test description',
279
+ activeForm: 'Testing',
280
+ status: 'pending',
281
+ priority: 'normal',
282
+ owner: null,
283
+ blockedBy: [],
284
+ blocks: [],
285
+ progress: 0,
286
+ checkpoints: [],
287
+ retryConfig: DEFAULT_RETRY_CONFIG,
288
+ retryCount: 0,
289
+ tags: [],
290
+ metadata: {},
291
+ history: [],
292
+ createdAt: Date.now(),
293
+ updatedAt: Date.now(),
294
+ version: 1,
295
+ ...overrides,
296
+ });
297
+
298
+ it('allows pending task with no blockers to start', () => {
299
+ const task = createTask();
300
+ const result = evaluateTaskCanStart(task, {});
301
+
302
+ expect(result.canStart).toBe(true);
303
+ expect(result.reason).toBeUndefined();
304
+ });
305
+
306
+ it('denies non-pending task', () => {
307
+ const task = createTask({ status: 'in_progress' });
308
+ const result = evaluateTaskCanStart(task, {});
309
+
310
+ expect(result.canStart).toBe(false);
311
+ expect(result.reason).toContain('Task status is in_progress');
312
+ });
313
+
314
+ it('denies task with owner', () => {
315
+ const task = createTask({ owner: 'user_1' });
316
+ const result = evaluateTaskCanStart(task, {});
317
+
318
+ expect(result.canStart).toBe(false);
319
+ expect(result.reason).toContain('Task is already owned by user_1');
320
+ });
321
+
322
+ it('denies task with incomplete blockers', () => {
323
+ const task = createTask({ blockedBy: ['task_2'] });
324
+ const allTasks: Record<string, TaskEntity> = {
325
+ task_2: createTask({ id: 'task_2', status: 'in_progress' }),
326
+ };
327
+
328
+ const result = evaluateTaskCanStart(task, allTasks);
329
+
330
+ expect(result.canStart).toBe(false);
331
+ expect(result.reason).toContain('Blocked by incomplete dependencies');
332
+ expect(result.reason).toContain('task_2');
333
+ });
334
+
335
+ it('denies task with cancelled blockers', () => {
336
+ const task = createTask({ blockedBy: ['task_2'] });
337
+ const allTasks: Record<string, TaskEntity> = {
338
+ task_2: createTask({ id: 'task_2', status: 'cancelled' }),
339
+ };
340
+
341
+ const result = evaluateTaskCanStart(task, allTasks);
342
+
343
+ expect(result.canStart).toBe(false);
344
+ expect(result.reason).toContain('Blocked by cancelled/failed dependencies');
345
+ expect(result.reason).toContain('task_2');
346
+ });
347
+
348
+ it('denies task with failed blockers', () => {
349
+ const task = createTask({ blockedBy: ['task_2'] });
350
+ const allTasks: Record<string, TaskEntity> = {
351
+ task_2: createTask({ id: 'task_2', status: 'failed' }),
352
+ };
353
+
354
+ const result = evaluateTaskCanStart(task, allTasks);
355
+
356
+ expect(result.canStart).toBe(false);
357
+ expect(result.reason).toContain('Blocked by cancelled/failed dependencies');
358
+ expect(result.reason).toContain('task_2');
359
+ });
360
+
361
+ it('allows task with completed blockers', () => {
362
+ const task = createTask({ blockedBy: ['task_2'] });
363
+ const allTasks: Record<string, TaskEntity> = {
364
+ task_2: createTask({ id: 'task_2', status: 'completed' }),
365
+ };
366
+
367
+ const result = evaluateTaskCanStart(task, allTasks);
368
+
369
+ expect(result.canStart).toBe(true);
370
+ });
371
+
372
+ it('denies task with non-existent blockers', () => {
373
+ const task = createTask({ blockedBy: ['task_2'] });
374
+ const allTasks: Record<string, TaskEntity> = {};
375
+
376
+ const result = evaluateTaskCanStart(task, allTasks);
377
+
378
+ expect(result.canStart).toBe(false);
379
+ expect(result.reason).toContain('Blocked by incomplete dependencies');
380
+ expect(result.reason).toContain('task_2');
381
+ });
382
+
383
+ it('handles multiple blockers', () => {
384
+ const task = createTask({ blockedBy: ['task_2', 'task_3', 'task_4'] });
385
+ const allTasks: Record<string, TaskEntity> = {
386
+ task_2: createTask({ id: 'task_2', status: 'completed' }),
387
+ task_3: createTask({ id: 'task_3', status: 'in_progress' }),
388
+ task_4: createTask({ id: 'task_4', status: 'cancelled' }),
389
+ };
390
+
391
+ const result = evaluateTaskCanStart(task, allTasks);
392
+
393
+ expect(result.canStart).toBe(false);
394
+ expect(result.reason).toContain('Blocked by cancelled/failed dependencies');
395
+ expect(result.reason).toContain('task_4');
396
+ });
397
+
398
+ it('handles mixed blocker statuses', () => {
399
+ const task = createTask({ blockedBy: ['task_2', 'task_3'] });
400
+ const allTasks: Record<string, TaskEntity> = {
401
+ task_2: createTask({ id: 'task_2', status: 'completed' }),
402
+ task_3: createTask({ id: 'task_3', status: 'pending' }),
403
+ };
404
+
405
+ const result = evaluateTaskCanStart(task, allTasks);
406
+
407
+ expect(result.canStart).toBe(false);
408
+ expect(result.reason).toContain('Blocked by incomplete dependencies');
409
+ expect(result.reason).toContain('task_3');
410
+ });
411
+ });
412
+
413
+ describe('safeJsonClone', () => {
414
+ it('clones simple objects', () => {
415
+ const obj = { a: 1, b: 'test', c: true };
416
+ const cloned = safeJsonClone(obj);
417
+
418
+ expect(cloned).toEqual(obj);
419
+ expect(cloned).not.toBe(obj);
420
+ });
421
+
422
+ it('clones nested objects', () => {
423
+ const obj = { a: { b: { c: 1 } } };
424
+ const cloned = safeJsonClone(obj);
425
+
426
+ expect(cloned).toEqual(obj);
427
+ expect(cloned.a).not.toBe(obj.a);
428
+ expect(cloned.a.b).not.toBe(obj.a.b);
429
+ });
430
+
431
+ it('clones arrays', () => {
432
+ const arr = [1, 2, 3, { a: 4 }];
433
+ const cloned = safeJsonClone(arr);
434
+
435
+ expect(cloned).toEqual(arr);
436
+ expect(cloned).not.toBe(arr);
437
+ expect(cloned[3]).not.toBe(arr[3]);
438
+ });
439
+
440
+ it('clones null', () => {
441
+ expect(safeJsonClone(null)).toBeNull();
442
+ });
443
+
444
+ it('throws for undefined', () => {
445
+ // JSON.stringify(undefined) returns undefined (not a string)
446
+ // JSON.parse(undefined) throws an error
447
+ expect(() => safeJsonClone(undefined)).toThrow();
448
+ });
449
+
450
+ it('clones numbers', () => {
451
+ expect(safeJsonClone(42)).toBe(42);
452
+ expect(safeJsonClone(3.14)).toBe(3.14);
453
+ expect(safeJsonClone(-1)).toBe(-1);
454
+ });
455
+
456
+ it('clones strings', () => {
457
+ expect(safeJsonClone('test')).toBe('test');
458
+ expect(safeJsonClone('')).toBe('');
459
+ });
460
+
461
+ it('clones booleans', () => {
462
+ expect(safeJsonClone(true)).toBe(true);
463
+ expect(safeJsonClone(false)).toBe(false);
464
+ });
465
+
466
+ it('handles Date objects', () => {
467
+ const date = new Date('2024-01-01');
468
+ const cloned = safeJsonClone(date);
469
+
470
+ // Date objects are serialized as strings
471
+ expect(typeof cloned).toBe('string');
472
+ });
473
+
474
+ it('handles circular references by throwing', () => {
475
+ const obj: Record<string, unknown> = { a: 1 };
476
+ obj.self = obj;
477
+
478
+ expect(() => safeJsonClone(obj)).toThrow();
479
+ });
480
+
481
+ it('handles functions by omitting them', () => {
482
+ const obj = { a: 1, fn: () => {} };
483
+ const cloned = safeJsonClone(obj);
484
+
485
+ expect(cloned).toEqual({ a: 1 });
486
+ });
487
+
488
+ it('handles symbols by omitting them', () => {
489
+ const obj = { a: 1, [Symbol('test')]: 'value' };
490
+ const cloned = safeJsonClone(obj);
491
+
492
+ expect(cloned).toEqual({ a: 1 });
493
+ });
494
+ });
@@ -0,0 +1,175 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildTaskFailure, buildTaskSuccess, parsePrefixedError } from '../task-errors';
3
+ import {
4
+ addDependencyEdge,
5
+ ensureGraphNode,
6
+ hasPath,
7
+ removeDependencyEdge,
8
+ wouldCreateCycle,
9
+ } from '../task-graph';
10
+ import {
11
+ createAgentId,
12
+ createEmptyNamespaceState,
13
+ createTaskId,
14
+ evaluateTaskCanStart,
15
+ isAgentRunTerminal,
16
+ isTaskFinal,
17
+ isTaskTerminal,
18
+ safeJsonClone,
19
+ validateTaskTransition,
20
+ type TaskEntity,
21
+ } from '../task-types';
22
+
23
+ function makeTask(overrides: Partial<TaskEntity> = {}): TaskEntity {
24
+ const now = 1;
25
+ return {
26
+ id: overrides.id || 'task-x',
27
+ subject: overrides.subject || 'Subject',
28
+ description: overrides.description || 'Description long enough for validation.',
29
+ activeForm: overrides.activeForm || 'Doing subject',
30
+ status: overrides.status || 'pending',
31
+ priority: overrides.priority || 'normal',
32
+ owner: overrides.owner === undefined ? null : overrides.owner,
33
+ blockedBy: overrides.blockedBy || [],
34
+ blocks: overrides.blocks || [],
35
+ progress: overrides.progress || 0,
36
+ checkpoints: overrides.checkpoints || [],
37
+ retryConfig: overrides.retryConfig || {
38
+ maxRetries: 1,
39
+ retryDelayMs: 1,
40
+ backoffMultiplier: 1,
41
+ retryOn: ['timeout'],
42
+ },
43
+ retryCount: overrides.retryCount || 0,
44
+ lastError: overrides.lastError,
45
+ lastErrorAt: overrides.lastErrorAt,
46
+ timeoutMs: overrides.timeoutMs,
47
+ tags: overrides.tags || [],
48
+ metadata: overrides.metadata || {},
49
+ history: overrides.history || [],
50
+ agentId: overrides.agentId,
51
+ createdAt: overrides.createdAt || now,
52
+ updatedAt: overrides.updatedAt || now,
53
+ startedAt: overrides.startedAt,
54
+ completedAt: overrides.completedAt,
55
+ cancelledAt: overrides.cancelledAt,
56
+ version: overrides.version || 1,
57
+ };
58
+ }
59
+
60
+ describe('task utility modules branch coverage', () => {
61
+ it('covers task error builders and prefixed error parser fallback', () => {
62
+ const failed = buildTaskFailure('TASK_X', 'something bad', { a: 1 });
63
+ expect(failed.success).toBe(false);
64
+ expect(failed.output).toContain('TASK_X: something bad');
65
+ expect(failed.metadata).toMatchObject({
66
+ error: 'TASK_X',
67
+ message: 'something bad',
68
+ a: 1,
69
+ });
70
+
71
+ const success = buildTaskSuccess({ ok: true, n: 2 });
72
+ expect(success.success).toBe(true);
73
+ expect(success.metadata).toMatchObject({ ok: true, n: 2 });
74
+
75
+ expect(parsePrefixedError('TASK_ABC: fine detail')).toEqual({
76
+ code: 'TASK_ABC',
77
+ detail: 'fine detail',
78
+ });
79
+ expect(parsePrefixedError('plain failure message')).toEqual({
80
+ code: 'TASK_OPERATION_FAILED',
81
+ detail: 'plain failure message',
82
+ });
83
+ });
84
+
85
+ it('covers dependency graph node/edge/path/cycle branches', () => {
86
+ const graph = {
87
+ adjacency: {} as Record<string, string[]>,
88
+ reverse: {} as Record<string, string[]>,
89
+ };
90
+
91
+ ensureGraphNode(graph, 'a');
92
+ ensureGraphNode(graph, 'a');
93
+ expect(graph.adjacency.a).toEqual([]);
94
+ expect(graph.reverse.a).toEqual([]);
95
+
96
+ addDependencyEdge(graph, 'a', 'b');
97
+ addDependencyEdge(graph, 'a', 'b');
98
+ expect(graph.adjacency.a).toEqual(['b']);
99
+ expect(graph.reverse.b).toEqual(['a']);
100
+
101
+ addDependencyEdge(graph, 'a', 'c');
102
+ addDependencyEdge(graph, 'b', 'd');
103
+ addDependencyEdge(graph, 'c', 'd');
104
+ expect(hasPath(graph, 'a', 'd')).toBe(true);
105
+ expect(hasPath(graph, 'a', 'a')).toBe(true);
106
+ expect(hasPath(graph, 'a', 'z')).toBe(false);
107
+ expect(hasPath({ adjacency: {}, reverse: {} }, 'missing', 'target')).toBe(false);
108
+
109
+ expect(wouldCreateCycle(graph, 'x', 'x')).toBe(true);
110
+ expect(wouldCreateCycle(graph, 'd', 'a')).toBe(true);
111
+ expect(wouldCreateCycle(graph, 'z', 'a')).toBe(false);
112
+
113
+ removeDependencyEdge(graph, 'a', 'b');
114
+ expect(graph.adjacency.a).toEqual(['c']);
115
+ expect(graph.reverse.b).toEqual([]);
116
+ });
117
+
118
+ it('covers task type helpers and evaluateTaskCanStart branches', () => {
119
+ expect(createTaskId()).toContain('task_');
120
+ expect(createAgentId()).toContain('agent_');
121
+
122
+ expect(isTaskTerminal('completed')).toBe(true);
123
+ expect(isTaskTerminal('cancelled')).toBe(true);
124
+ expect(isTaskTerminal('failed')).toBe(false);
125
+ expect(isTaskFinal('failed')).toBe(true);
126
+ expect(isAgentRunTerminal('timed_out')).toBe(true);
127
+ expect(isAgentRunTerminal('paused')).toBe(false);
128
+
129
+ expect(validateTaskTransition('pending', 'pending')).toBe(true);
130
+ expect(validateTaskTransition('pending', 'in_progress')).toBe(true);
131
+ expect(validateTaskTransition('pending', 'completed')).toBe(false);
132
+
133
+ const ns = createEmptyNamespaceState('n1');
134
+ expect(ns.namespace).toBe('n1');
135
+ expect(ns.schemaVersion).toBe(1);
136
+ expect(ns.tasks).toEqual({});
137
+
138
+ const cloneSource = { x: { y: 1 } };
139
+ const clone = safeJsonClone(cloneSource);
140
+ clone.x.y = 99;
141
+ expect(cloneSource.x.y).toBe(1);
142
+
143
+ const nonPending = evaluateTaskCanStart(makeTask({ status: 'in_progress' }), {});
144
+ expect(nonPending.canStart).toBe(false);
145
+ expect(nonPending.reason).toContain('in_progress');
146
+
147
+ const owned = evaluateTaskCanStart(makeTask({ owner: 'agent-1' }), {});
148
+ expect(owned.canStart).toBe(false);
149
+ expect(owned.reason).toContain('already owned');
150
+
151
+ const blockerMap = {
152
+ b1: makeTask({ id: 'b1', status: 'cancelled' }),
153
+ b2: makeTask({ id: 'b2', status: 'failed' }),
154
+ b3: makeTask({ id: 'b3', status: 'in_progress' }),
155
+ b4: makeTask({ id: 'b4', status: 'completed' }),
156
+ };
157
+ const cancelledOrFailed = evaluateTaskCanStart(
158
+ makeTask({ blockedBy: ['missing', 'b1', 'b2', 'b3', 'b4'] }),
159
+ blockerMap
160
+ );
161
+ expect(cancelledOrFailed.canStart).toBe(false);
162
+ expect(cancelledOrFailed.reason).toContain('cancelled/failed');
163
+ expect(cancelledOrFailed.reason).toContain('b1');
164
+ expect(cancelledOrFailed.reason).toContain('b2');
165
+
166
+ const incomplete = evaluateTaskCanStart(makeTask({ blockedBy: ['missing', 'b3'] }), blockerMap);
167
+ expect(incomplete.canStart).toBe(false);
168
+ expect(incomplete.reason).toContain('incomplete dependencies');
169
+ expect(incomplete.reason).toContain('missing');
170
+ expect(incomplete.reason).toContain('b3');
171
+
172
+ const canStart = evaluateTaskCanStart(makeTask({ blockedBy: ['b4'] }), blockerMap);
173
+ expect(canStart).toEqual({ canStart: true });
174
+ });
175
+ });