@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
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Validation system barrel exports.
3
3
  *
4
- * Provides the complete validation system ported from lib/validation/*.
4
+ * Provides the complete validation system ported from lib/validation/*,
5
+ * plus canonical Zod enum schemas for all domain enums so consumers can
6
+ * import them from `@cleocode/core` instead of duplicating.
5
7
  *
6
8
  * @task T4523
7
9
  * @epic T4454
@@ -9,6 +11,132 @@
9
11
 
10
12
  // Core validation engine — also re-export registry constants for convenience
11
13
  export { TASK_STATUSES } from '@cleocode/contracts';
14
+ // Inferred types
15
+ export type {
16
+ AuditLogInsert,
17
+ AuditLogSelect,
18
+ InsertArchitectureDecision,
19
+ InsertAuditLog,
20
+ InsertExternalTaskLink,
21
+ InsertLifecycleEvidence,
22
+ InsertLifecycleGateResult,
23
+ InsertLifecyclePipeline,
24
+ InsertLifecycleStage,
25
+ InsertLifecycleTransition,
26
+ InsertManifestEntry,
27
+ InsertPipelineManifest,
28
+ InsertReleaseManifest,
29
+ InsertSchemaMeta,
30
+ InsertSession,
31
+ InsertTask,
32
+ InsertTaskDependency,
33
+ InsertTaskRelation,
34
+ InsertTokenUsage,
35
+ InsertWorkHistory,
36
+ SelectArchitectureDecision,
37
+ SelectAuditLog,
38
+ SelectExternalTaskLink,
39
+ SelectLifecycleEvidence,
40
+ SelectLifecycleGateResult,
41
+ SelectLifecyclePipeline,
42
+ SelectLifecycleStage,
43
+ SelectLifecycleTransition,
44
+ SelectManifestEntry,
45
+ SelectPipelineManifest,
46
+ SelectReleaseManifest,
47
+ SelectSchemaMeta,
48
+ SelectSession,
49
+ SelectTask,
50
+ SelectTaskDependency,
51
+ SelectTaskRelation,
52
+ SelectTokenUsage,
53
+ SelectWorkHistory,
54
+ } from '../store/validation-schemas.js';
55
+ // ---------------------------------------------------------------------------
56
+ // Canonical Zod enum schemas (from validation-schemas.ts)
57
+ // ---------------------------------------------------------------------------
58
+ // Task enums
59
+ // Session enums
60
+ // Lifecycle enums
61
+ // Governance enums
62
+ // Token usage enums
63
+ // Relation / link enums
64
+ // Brain enums
65
+ // Insert/select schemas for all tables
66
+ export {
67
+ AuditLogInsertSchema,
68
+ AuditLogSelectSchema,
69
+ adrStatusSchema,
70
+ brainConfidenceLevelSchema,
71
+ brainDecisionTypeSchema,
72
+ brainEdgeTypeSchema,
73
+ brainImpactLevelSchema,
74
+ brainLinkTypeSchema,
75
+ brainMemoryTypeSchema,
76
+ brainNodeTypeSchema,
77
+ brainObservationSourceTypeSchema,
78
+ brainObservationTypeSchema,
79
+ brainOutcomeTypeSchema,
80
+ brainPatternTypeSchema,
81
+ brainStickyColorSchema,
82
+ brainStickyPrioritySchema,
83
+ brainStickyStatusSchema,
84
+ externalLinkTypeSchema,
85
+ gateStatusSchema,
86
+ insertArchitectureDecisionSchema,
87
+ insertAuditLogSchema,
88
+ insertExternalTaskLinkSchema,
89
+ insertLifecycleEvidenceSchema,
90
+ insertLifecycleGateResultSchema,
91
+ insertLifecyclePipelineSchema,
92
+ insertLifecycleStageSchema,
93
+ insertLifecycleTransitionSchema,
94
+ insertManifestEntrySchema,
95
+ insertPipelineManifestSchema,
96
+ insertReleaseManifestSchema,
97
+ insertSchemaMetaSchema,
98
+ insertSessionSchema,
99
+ insertTaskDependencySchema,
100
+ insertTaskRelationSchema,
101
+ insertTaskSchema,
102
+ insertTokenUsageSchema,
103
+ insertWorkHistorySchema,
104
+ lifecycleEvidenceTypeSchema,
105
+ lifecycleGateResultSchema,
106
+ lifecyclePipelineStatusSchema,
107
+ lifecycleStageNameSchema,
108
+ lifecycleStageStatusSchema,
109
+ lifecycleTransitionTypeSchema,
110
+ manifestStatusSchema,
111
+ selectArchitectureDecisionSchema,
112
+ selectAuditLogSchema,
113
+ selectExternalTaskLinkSchema,
114
+ selectLifecycleEvidenceSchema,
115
+ selectLifecycleGateResultSchema,
116
+ selectLifecyclePipelineSchema,
117
+ selectLifecycleStageSchema,
118
+ selectLifecycleTransitionSchema,
119
+ selectManifestEntrySchema,
120
+ selectPipelineManifestSchema,
121
+ selectReleaseManifestSchema,
122
+ selectSchemaMetaSchema,
123
+ selectSessionSchema,
124
+ selectTaskDependencySchema,
125
+ selectTaskRelationSchema,
126
+ selectTaskSchema,
127
+ selectTokenUsageSchema,
128
+ selectWorkHistorySchema,
129
+ sessionStatusSchema,
130
+ syncDirectionSchema,
131
+ taskPrioritySchema,
132
+ taskRelationTypeSchema,
133
+ taskSizeSchema,
134
+ taskStatusSchema,
135
+ taskTypeSchema,
136
+ tokenUsageConfidenceSchema,
137
+ tokenUsageMethodSchema,
138
+ tokenUsageTransportSchema,
139
+ } from '../store/validation-schemas.js';
12
140
  // Compliance checking
13
141
  export {
14
142
  type ComplianceMetrics,
@@ -37,7 +165,7 @@ export {
37
165
  // Doctor health checks
38
166
  export * from './doctor/index.js';
39
167
  export {
40
- type ArchiveFile,
168
+ type ArchiveData,
41
169
  type ComprehensiveValidationResult,
42
170
  checkIdUniqueness,
43
171
  checkTimestampSanity,
@@ -47,7 +175,7 @@ export {
47
175
  normalizeLabels,
48
176
  sanitizeFilePath,
49
177
  type Task,
50
- type TaskFile,
178
+ type TaskData,
51
179
  type TaskStatus,
52
180
  VALID_OPERATIONS,
53
181
  type ValidationError,
@@ -88,16 +88,49 @@ const VALID_TYPES = [
88
88
  const VALID_STATUSES_MSG = MANIFEST_STATUSES.filter((s) => s !== 'archived');
89
89
  const VALID_DETAILS = ['summary', 'details', 'blocker details'];
90
90
 
91
+ /**
92
+ * Map from protocol type identifiers to the expected message type prefix.
93
+ * When a protocolType is provided, the return message must use the matching type.
94
+ */
95
+ const PROTOCOL_TYPE_MAP: Record<string, string> = {
96
+ research: 'Research',
97
+ implementation: 'Implementation',
98
+ validation: 'Validation',
99
+ testing: 'Testing',
100
+ specification: 'Specification',
101
+ consensus: 'Consensus',
102
+ decomposition: 'Decomposition',
103
+ contribution: 'Contribution',
104
+ release: 'Release',
105
+ };
106
+
91
107
  /**
92
108
  * Check if return message follows protocol format.
93
109
  * Expected: "<Type> <status>. See MANIFEST.jsonl for <detail>."
110
+ *
111
+ * When protocolType is provided, the message type must match the protocol
112
+ * (e.g., a 'research' protocol must produce a "Research ..." message).
113
+ *
94
114
  * @task T4527
95
115
  */
96
- export function checkReturnMessageFormat(message: string, _protocolType?: string): boolean {
97
- const typePattern = VALID_TYPES.join('|');
116
+ export function checkReturnMessageFormat(message: string, protocolType?: string): boolean {
98
117
  const statusPattern = VALID_STATUSES_MSG.join('|');
99
118
  const detailPattern = VALID_DETAILS.join('|');
100
119
 
120
+ // If protocolType is given, constrain the type to the matching prefix
121
+ let typePattern: string;
122
+ if (protocolType) {
123
+ const expectedType = PROTOCOL_TYPE_MAP[protocolType.toLowerCase()];
124
+ if (!expectedType) {
125
+ // Unknown protocol type — fall back to allowing any valid type
126
+ typePattern = VALID_TYPES.join('|');
127
+ } else {
128
+ typePattern = expectedType;
129
+ }
130
+ } else {
131
+ typePattern = VALID_TYPES.join('|');
132
+ }
133
+
101
134
  const regex = new RegExp(
102
135
  `^(${typePattern}) (${statusPattern})\\. See MANIFEST\\.jsonl for (${detailPattern})\\.$`,
103
136
  );
@@ -217,11 +250,15 @@ export function checkProvenanceTags(filePath: string, taskId?: string): boolean
217
250
 
218
251
  /**
219
252
  * Validate common manifest requirements across all protocols.
253
+ *
254
+ * When protocolType is provided, additionally validates that the manifest
255
+ * entry's agent_type matches the expected protocol type.
256
+ *
220
257
  * @task T4527
221
258
  */
222
259
  export function validateCommonManifestRequirements(
223
260
  entry: Record<string, unknown>,
224
- _protocolType?: string,
261
+ protocolType?: string,
225
262
  ): ProtocolValidationResult {
226
263
  const violations: ProtocolViolation[] = [];
227
264
  let score = 100;
@@ -289,6 +326,20 @@ export function validateCommonManifestRequirements(
289
326
  score -= 5;
290
327
  }
291
328
 
329
+ // Protocol-specific: verify agent_type matches the protocol when specified
330
+ if (protocolType && checkManifestFieldPresent(entry, 'agent_type')) {
331
+ const expectedType = PROTOCOL_TYPE_MAP[protocolType.toLowerCase()];
332
+ if (expectedType && !checkAgentType(entry, expectedType.toLowerCase())) {
333
+ violations.push({
334
+ requirement: 'COMMON-007',
335
+ severity: 'warning',
336
+ message: `agent_type '${String(entry['agent_type'])}' does not match protocol '${protocolType}'`,
337
+ fix: `Set agent_type to '${expectedType.toLowerCase()}'`,
338
+ });
339
+ score -= 5;
340
+ }
341
+ }
342
+
292
343
  return {
293
344
  valid: score >= 70,
294
345
  violations,
@@ -1,38 +0,0 @@
1
- /**
2
- * Canonical reparent logic — move a task to a different parent in the hierarchy.
3
- * Both CLI (reparent command) and core (updateTask) delegate here.
4
- *
5
- * This module operates on an in-memory TaskFile. The caller is responsible
6
- * for loading and saving the data (via DataAccessor or direct JSON I/O).
7
- *
8
- * @task T4807
9
- * @epic T4454
10
- */
11
- import type { TaskFile } from '@cleocode/contracts';
12
- import type { HierarchyPolicy } from './hierarchy-policy.js';
13
- /** Options for reparenting a task. */
14
- export interface ReparentOptions {
15
- taskId: string;
16
- /** New parent ID, or null to promote to root. */
17
- newParentId: string | null;
18
- /** Optional resolved hierarchy policy. If not provided, uses llm-agent-first defaults. */
19
- policy?: HierarchyPolicy;
20
- }
21
- /** Result of a reparent operation. */
22
- export interface ReparentResult {
23
- oldParent: string | null;
24
- newParent: string | null;
25
- newType: string;
26
- }
27
- /**
28
- * Reparent a task within a TaskFile.
29
- *
30
- * Mutates the task in-place within `data.tasks`. Updates `parentId`, `type`,
31
- * and `updatedAt` on the target task, and `lastUpdated` on the TaskFile.
32
- *
33
- * @param data The loaded TaskFile (mutated in place)
34
- * @param opts Reparent options (taskId, newParentId)
35
- * @returns Result with old/new parent and new type
36
- */
37
- export declare function reparentTask(data: TaskFile, opts: ReparentOptions): Promise<ReparentResult>;
38
- //# sourceMappingURL=reparent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"reparent.d.ts","sourceRoot":"","sources":["../../src/tasks/reparent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAwFjG"}
@@ -1,134 +0,0 @@
1
- /**
2
- * Canonical reparent logic — move a task to a different parent in the hierarchy.
3
- * Both CLI (reparent command) and core (updateTask) delegate here.
4
- *
5
- * This module operates on an in-memory TaskFile. The caller is responsible
6
- * for loading and saving the data (via DataAccessor or direct JSON I/O).
7
- *
8
- * @task T4807
9
- * @epic T4454
10
- */
11
-
12
- import type { TaskFile } from '@cleocode/contracts';
13
- import { ExitCode } from '@cleocode/contracts';
14
- import { loadConfig } from '../config.js';
15
- import { CleoError } from '../errors.js';
16
- import { getDepth, wouldCreateCircle } from './hierarchy.js';
17
- import type { HierarchyPolicy } from './hierarchy-policy.js';
18
- import { resolveHierarchyPolicy, validateHierarchyPlacement } from './hierarchy-policy.js';
19
-
20
- /** Options for reparenting a task. */
21
- export interface ReparentOptions {
22
- taskId: string;
23
- /** New parent ID, or null to promote to root. */
24
- newParentId: string | null;
25
- /** Optional resolved hierarchy policy. If not provided, uses llm-agent-first defaults. */
26
- policy?: HierarchyPolicy;
27
- }
28
-
29
- /** Result of a reparent operation. */
30
- export interface ReparentResult {
31
- oldParent: string | null;
32
- newParent: string | null;
33
- newType: string;
34
- }
35
-
36
- /**
37
- * Reparent a task within a TaskFile.
38
- *
39
- * Mutates the task in-place within `data.tasks`. Updates `parentId`, `type`,
40
- * and `updatedAt` on the target task, and `lastUpdated` on the TaskFile.
41
- *
42
- * @param data The loaded TaskFile (mutated in place)
43
- * @param opts Reparent options (taskId, newParentId)
44
- * @returns Result with old/new parent and new type
45
- */
46
- export async function reparentTask(data: TaskFile, opts: ReparentOptions): Promise<ReparentResult> {
47
- const { taskId, newParentId } = opts;
48
-
49
- const task = data.tasks.find((t) => t.id === taskId);
50
- if (!task) {
51
- throw new CleoError(ExitCode.NOT_FOUND, `Task not found: ${taskId}`, {
52
- fix: `Use 'cleo find "${taskId}"' to search`,
53
- });
54
- }
55
-
56
- const oldParent = task.parentId ?? null;
57
- const effectiveNewParent = newParentId || null;
58
-
59
- // Promote to root
60
- if (!effectiveNewParent) {
61
- task.parentId = null;
62
- if (task.type === 'subtask') {
63
- task.type = 'task';
64
- }
65
- task.updatedAt = new Date().toISOString();
66
- data.lastUpdated = new Date().toISOString();
67
-
68
- return {
69
- oldParent,
70
- newParent: null,
71
- newType: task.type ?? 'task',
72
- };
73
- }
74
-
75
- // Validate target parent exists and hierarchy constraints (depth + sibling limits)
76
- const effectivePolicy = opts.policy ?? resolveHierarchyPolicy(await loadConfig());
77
- const validation = validateHierarchyPlacement(effectiveNewParent, data.tasks, effectivePolicy);
78
- if (!validation.valid) {
79
- const code =
80
- validation.error?.code === 'E_PARENT_NOT_FOUND'
81
- ? ExitCode.PARENT_NOT_FOUND
82
- : validation.error?.code === 'E_DEPTH_EXCEEDED'
83
- ? ExitCode.DEPTH_EXCEEDED
84
- : validation.error?.code === 'E_SIBLING_LIMIT'
85
- ? ExitCode.SIBLING_LIMIT
86
- : ExitCode.INVALID_INPUT;
87
-
88
- throw new CleoError(
89
- code,
90
- validation.error?.message ?? `Cannot reparent under ${effectiveNewParent}`,
91
- { fix: `Check hierarchy constraints with 'cleo show ${effectiveNewParent}'` },
92
- );
93
- }
94
-
95
- const newParentTask = data.tasks.find((t) => t.id === effectiveNewParent);
96
-
97
- // Cannot parent under a subtask
98
- if (newParentTask?.type === 'subtask') {
99
- throw new CleoError(
100
- ExitCode.INVALID_PARENT_TYPE,
101
- `Cannot parent under subtask '${effectiveNewParent}'`,
102
- { fix: `Choose a task or epic as the parent instead` },
103
- );
104
- }
105
-
106
- // Check circular reference
107
- if (wouldCreateCircle(taskId, effectiveNewParent, data.tasks)) {
108
- throw new CleoError(
109
- ExitCode.CIRCULAR_REFERENCE,
110
- `Moving '${taskId}' under '${effectiveNewParent}' would create a circular reference`,
111
- { fix: `The target parent is a descendant of the task being moved` },
112
- );
113
- }
114
-
115
- // Apply the reparent
116
- task.parentId = effectiveNewParent;
117
-
118
- // Update type based on new depth in the hierarchy
119
- const newDepth = getDepth(taskId, data.tasks);
120
- if (newDepth === 1) {
121
- task.type = 'task';
122
- } else if (newDepth >= 2) {
123
- task.type = 'subtask';
124
- }
125
-
126
- task.updatedAt = new Date().toISOString();
127
- data.lastUpdated = new Date().toISOString();
128
-
129
- return {
130
- oldParent,
131
- newParent: effectiveNewParent,
132
- newType: task.type ?? 'task',
133
- };
134
- }