holosphere 1.1.20 → 2.0.0-alpha1

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 (147) hide show
  1. package/.env.example +36 -0
  2. package/.eslintrc.json +16 -0
  3. package/.prettierrc.json +7 -0
  4. package/LICENSE +162 -38
  5. package/README.md +483 -367
  6. package/bin/holosphere-activitypub.js +158 -0
  7. package/cleanup-test-data.js +204 -0
  8. package/examples/demo.html +1333 -0
  9. package/examples/example-bot.js +197 -0
  10. package/package.json +47 -87
  11. package/scripts/check-bundle-size.js +54 -0
  12. package/scripts/check-quest-ids.js +77 -0
  13. package/scripts/import-holons.js +578 -0
  14. package/scripts/publish-to-relay.js +101 -0
  15. package/scripts/read-example.js +186 -0
  16. package/scripts/relay-diagnostic.js +59 -0
  17. package/scripts/relay-example.js +179 -0
  18. package/scripts/resync-to-relay.js +245 -0
  19. package/scripts/revert-import.js +196 -0
  20. package/scripts/test-hybrid-mode.js +108 -0
  21. package/scripts/test-local-storage.js +63 -0
  22. package/scripts/test-nostr-direct.js +55 -0
  23. package/scripts/test-read-data.js +45 -0
  24. package/scripts/test-write-read.js +63 -0
  25. package/scripts/verify-import.js +95 -0
  26. package/scripts/verify-relay-data.js +139 -0
  27. package/src/ai/aggregation.js +319 -0
  28. package/src/ai/breakdown.js +511 -0
  29. package/src/ai/classifier.js +217 -0
  30. package/src/ai/council.js +228 -0
  31. package/src/ai/embeddings.js +279 -0
  32. package/src/ai/federation-ai.js +324 -0
  33. package/src/ai/h3-ai.js +955 -0
  34. package/src/ai/index.js +112 -0
  35. package/src/ai/json-ops.js +225 -0
  36. package/src/ai/llm-service.js +205 -0
  37. package/src/ai/nl-query.js +223 -0
  38. package/src/ai/relationships.js +353 -0
  39. package/src/ai/schema-extractor.js +218 -0
  40. package/src/ai/spatial.js +293 -0
  41. package/src/ai/tts.js +194 -0
  42. package/src/content/social-protocols.js +168 -0
  43. package/src/core/holosphere.js +273 -0
  44. package/src/crypto/secp256k1.js +259 -0
  45. package/src/federation/discovery.js +334 -0
  46. package/src/federation/hologram.js +1042 -0
  47. package/src/federation/registry.js +386 -0
  48. package/src/hierarchical/upcast.js +110 -0
  49. package/src/index.js +2669 -0
  50. package/src/schema/validator.js +91 -0
  51. package/src/spatial/h3-operations.js +110 -0
  52. package/src/storage/backend-factory.js +125 -0
  53. package/src/storage/backend-interface.js +142 -0
  54. package/src/storage/backends/activitypub/server.js +653 -0
  55. package/src/storage/backends/activitypub-backend.js +272 -0
  56. package/src/storage/backends/gundb-backend.js +233 -0
  57. package/src/storage/backends/nostr-backend.js +136 -0
  58. package/src/storage/filesystem-storage-browser.js +41 -0
  59. package/src/storage/filesystem-storage.js +138 -0
  60. package/src/storage/global-tables.js +81 -0
  61. package/src/storage/gun-async.js +281 -0
  62. package/src/storage/gun-wrapper.js +221 -0
  63. package/src/storage/indexeddb-storage.js +122 -0
  64. package/src/storage/key-storage-simple.js +76 -0
  65. package/src/storage/key-storage.js +136 -0
  66. package/src/storage/memory-storage.js +59 -0
  67. package/src/storage/migration.js +338 -0
  68. package/src/storage/nostr-async.js +811 -0
  69. package/src/storage/nostr-client.js +939 -0
  70. package/src/storage/nostr-wrapper.js +211 -0
  71. package/src/storage/outbox-queue.js +208 -0
  72. package/src/storage/persistent-storage.js +109 -0
  73. package/src/storage/sync-service.js +164 -0
  74. package/src/subscriptions/manager.js +142 -0
  75. package/test-ai-real-api.js +202 -0
  76. package/tests/unit/ai/aggregation.test.js +295 -0
  77. package/tests/unit/ai/breakdown.test.js +446 -0
  78. package/tests/unit/ai/classifier.test.js +294 -0
  79. package/tests/unit/ai/council.test.js +262 -0
  80. package/tests/unit/ai/embeddings.test.js +384 -0
  81. package/tests/unit/ai/federation-ai.test.js +344 -0
  82. package/tests/unit/ai/h3-ai.test.js +458 -0
  83. package/tests/unit/ai/index.test.js +304 -0
  84. package/tests/unit/ai/json-ops.test.js +307 -0
  85. package/tests/unit/ai/llm-service.test.js +390 -0
  86. package/tests/unit/ai/nl-query.test.js +383 -0
  87. package/tests/unit/ai/relationships.test.js +311 -0
  88. package/tests/unit/ai/schema-extractor.test.js +384 -0
  89. package/tests/unit/ai/spatial.test.js +279 -0
  90. package/tests/unit/ai/tts.test.js +279 -0
  91. package/tests/unit/content.test.js +332 -0
  92. package/tests/unit/contract/core.test.js +88 -0
  93. package/tests/unit/contract/crypto.test.js +198 -0
  94. package/tests/unit/contract/data.test.js +223 -0
  95. package/tests/unit/contract/federation.test.js +181 -0
  96. package/tests/unit/contract/hierarchical.test.js +113 -0
  97. package/tests/unit/contract/schema.test.js +114 -0
  98. package/tests/unit/contract/social.test.js +217 -0
  99. package/tests/unit/contract/spatial.test.js +110 -0
  100. package/tests/unit/contract/subscriptions.test.js +128 -0
  101. package/tests/unit/contract/utils.test.js +159 -0
  102. package/tests/unit/core.test.js +152 -0
  103. package/tests/unit/crypto.test.js +328 -0
  104. package/tests/unit/federation.test.js +234 -0
  105. package/tests/unit/gun-async.test.js +252 -0
  106. package/tests/unit/hierarchical.test.js +399 -0
  107. package/tests/unit/integration/scenario-01-geographic-storage.test.js +74 -0
  108. package/tests/unit/integration/scenario-02-federation.test.js +76 -0
  109. package/tests/unit/integration/scenario-03-subscriptions.test.js +102 -0
  110. package/tests/unit/integration/scenario-04-validation.test.js +129 -0
  111. package/tests/unit/integration/scenario-05-hierarchy.test.js +125 -0
  112. package/tests/unit/integration/scenario-06-social.test.js +135 -0
  113. package/tests/unit/integration/scenario-07-persistence.test.js +130 -0
  114. package/tests/unit/integration/scenario-08-authorization.test.js +161 -0
  115. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +139 -0
  116. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +357 -0
  117. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +410 -0
  118. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +719 -0
  119. package/tests/unit/performance/benchmark.test.js +85 -0
  120. package/tests/unit/schema.test.js +213 -0
  121. package/tests/unit/spatial.test.js +158 -0
  122. package/tests/unit/storage.test.js +195 -0
  123. package/tests/unit/subscriptions.test.js +328 -0
  124. package/tests/unit/test-data-permanence-debug.js +197 -0
  125. package/tests/unit/test-data-permanence.js +340 -0
  126. package/tests/unit/test-key-persistence-fixed.js +148 -0
  127. package/tests/unit/test-key-persistence.js +172 -0
  128. package/tests/unit/test-relay-permanence.js +376 -0
  129. package/tests/unit/test-second-node.js +95 -0
  130. package/tests/unit/test-simple-write.js +89 -0
  131. package/vite.config.js +49 -0
  132. package/vitest.config.js +20 -0
  133. package/FEDERATION.md +0 -213
  134. package/compute.js +0 -298
  135. package/content.js +0 -980
  136. package/federation.js +0 -1234
  137. package/global.js +0 -736
  138. package/hexlib.js +0 -335
  139. package/hologram.js +0 -183
  140. package/holosphere-bundle.esm.js +0 -33256
  141. package/holosphere-bundle.js +0 -33287
  142. package/holosphere-bundle.min.js +0 -39
  143. package/holosphere.d.ts +0 -601
  144. package/holosphere.js +0 -719
  145. package/node.js +0 -246
  146. package/schema.js +0 -139
  147. package/utils.js +0 -302
@@ -0,0 +1,511 @@
1
+ /**
2
+ * Task Breakdown - Recursively decompose tasks/quests into subtasks
3
+ */
4
+
5
+ /**
6
+ * Task Breakdown class
7
+ */
8
+ export class TaskBreakdown {
9
+ /**
10
+ * @param {LLMService} llmService - LLM service instance
11
+ * @param {Object} holosphere - HoloSphere instance
12
+ */
13
+ constructor(llmService, holosphere = null) {
14
+ this.llm = llmService;
15
+ this.holosphere = holosphere;
16
+ }
17
+
18
+ /**
19
+ * Set HoloSphere instance
20
+ * @param {Object} holosphere - HoloSphere instance
21
+ */
22
+ setHoloSphere(holosphere) {
23
+ this.holosphere = holosphere;
24
+ }
25
+
26
+ /**
27
+ * Recursively break down a task/quest into subtasks
28
+ * @param {Object} item - The item to break down (must have id)
29
+ * @param {string} holonId - Holon where the item lives
30
+ * @param {string} lensName - Lens name (e.g., 'quests', 'tasks')
31
+ * @param {Object} options - Breakdown options
32
+ * @param {number} options.depth - Maximum recursion depth (default: 2)
33
+ * @param {number} options.stepsPerLevel - Number of subtasks per level (default: 3-5)
34
+ * @param {boolean} options.useContext - Look at other items for context (default: true)
35
+ * @param {boolean} options.storeResults - Store generated subtasks (default: true)
36
+ * @param {string} options.dependencyField - Field name for dependencies (default: 'dependencies')
37
+ * @param {string} options.parentField - Field name for parent reference (default: 'parent')
38
+ * @returns {Promise<Object>} Breakdown result with tree structure
39
+ */
40
+ async breakdown(item, holonId, lensName, options = {}) {
41
+ if (!item || !item.id) {
42
+ throw new Error('Item must have an id property');
43
+ }
44
+
45
+ const {
46
+ depth = 2,
47
+ stepsPerLevel = { min: 3, max: 5 },
48
+ useContext = true,
49
+ storeResults = true,
50
+ dependencyField = 'dependencies',
51
+ parentField = 'parent',
52
+ } = options;
53
+
54
+ // Normalize stepsPerLevel
55
+ const steps = typeof stepsPerLevel === 'number'
56
+ ? { min: stepsPerLevel, max: stepsPerLevel }
57
+ : stepsPerLevel;
58
+
59
+ // Get context from other items in the holon
60
+ let context = [];
61
+ if (useContext && this.holosphere) {
62
+ try {
63
+ const allItems = await this.holosphere.getAll(holonId, lensName);
64
+ context = allItems
65
+ .filter(i => i.id !== item.id)
66
+ .slice(0, 10); // Limit context items
67
+ } catch {
68
+ // Skip if can't get context
69
+ }
70
+ }
71
+
72
+ // Get schema for the lens if available
73
+ let schema = null;
74
+ if (this.holosphere) {
75
+ try {
76
+ schema = await this.holosphere.getSchema(lensName);
77
+ } catch {
78
+ // No schema available
79
+ }
80
+ }
81
+
82
+ // Perform recursive breakdown
83
+ const result = await this._breakdownRecursive(
84
+ item,
85
+ holonId,
86
+ lensName,
87
+ depth,
88
+ steps,
89
+ context,
90
+ schema,
91
+ dependencyField,
92
+ parentField,
93
+ storeResults,
94
+ 0 // current depth
95
+ );
96
+
97
+ return {
98
+ original: item,
99
+ holonId,
100
+ lensName,
101
+ breakdown: result,
102
+ totalSubtasks: this._countSubtasks(result),
103
+ maxDepth: depth,
104
+ timestamp: Date.now(),
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Recursive breakdown implementation
110
+ * @private
111
+ */
112
+ async _breakdownRecursive(
113
+ item,
114
+ holonId,
115
+ lensName,
116
+ maxDepth,
117
+ stepsPerLevel,
118
+ context,
119
+ schema,
120
+ dependencyField,
121
+ parentField,
122
+ storeResults,
123
+ currentDepth
124
+ ) {
125
+ if (currentDepth >= maxDepth) {
126
+ return {
127
+ item,
128
+ children: [],
129
+ depth: currentDepth,
130
+ };
131
+ }
132
+
133
+ // Generate subtasks for this item
134
+ const subtasks = await this._generateSubtasks(
135
+ item,
136
+ context,
137
+ schema,
138
+ stepsPerLevel,
139
+ dependencyField,
140
+ parentField
141
+ );
142
+
143
+ // Store subtasks if requested
144
+ if (storeResults && this.holosphere && subtasks.length > 0) {
145
+ for (const subtask of subtasks) {
146
+ try {
147
+ await this.holosphere.write(holonId, lensName, subtask);
148
+ } catch (err) {
149
+ console.warn(`Failed to store subtask ${subtask.id}:`, err.message);
150
+ }
151
+ }
152
+
153
+ // Update parent item with child references if it doesn't have them
154
+ if (item._meta?.childTasks !== subtasks.map(s => s.id)) {
155
+ try {
156
+ await this.holosphere.update(holonId, lensName, item.id, {
157
+ _meta: {
158
+ ...item._meta,
159
+ childTasks: subtasks.map(s => s.id),
160
+ breakdownTimestamp: Date.now(),
161
+ }
162
+ });
163
+ } catch {
164
+ // Skip if can't update
165
+ }
166
+ }
167
+ }
168
+
169
+ // Recursively break down each subtask
170
+ const children = [];
171
+ for (const subtask of subtasks) {
172
+ const childResult = await this._breakdownRecursive(
173
+ subtask,
174
+ holonId,
175
+ lensName,
176
+ maxDepth,
177
+ stepsPerLevel,
178
+ context,
179
+ schema,
180
+ dependencyField,
181
+ parentField,
182
+ storeResults,
183
+ currentDepth + 1
184
+ );
185
+ children.push(childResult);
186
+ }
187
+
188
+ return {
189
+ item,
190
+ children,
191
+ depth: currentDepth,
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Generate subtasks for an item using AI
197
+ * @private
198
+ */
199
+ async _generateSubtasks(item, context, schema, stepsPerLevel, dependencyField, parentField) {
200
+ const { min, max } = stepsPerLevel;
201
+
202
+ const systemPrompt = `You are a task decomposition expert. Break down the given task/quest into ${min}-${max} concrete, actionable subtasks.
203
+
204
+ Each subtask should:
205
+ 1. Be a clear, specific action
206
+ 2. Be smaller and more manageable than the parent
207
+ 3. Together with siblings, fully accomplish the parent task
208
+ 4. Have a unique ID (format: parentId-1, parentId-2, etc.)
209
+ 5. Reference the parent task in the "${parentField}" field
210
+ 6. List any dependencies on sibling tasks in "${dependencyField}" array
211
+
212
+ ${schema ? `Follow this schema structure:\n${JSON.stringify(schema, null, 2)}` : ''}
213
+
214
+ ${context.length > 0 ? `Consider these existing items for context and avoid duplication:\n${JSON.stringify(context.slice(0, 5), null, 2)}` : ''}
215
+
216
+ Return a JSON array of subtasks. Each subtask must have:
217
+ - id: unique identifier (parentId-1, parentId-2, etc.)
218
+ - title/name: clear action title
219
+ - description: what needs to be done
220
+ - ${parentField}: reference to parent id
221
+ - ${dependencyField}: array of sibling task ids this depends on (empty if first task)
222
+ - status: "pending"
223
+ - Any other relevant fields from the parent schema
224
+
225
+ Example output format:
226
+ [
227
+ {
228
+ "id": "parent-1",
229
+ "title": "First subtask",
230
+ "description": "Details...",
231
+ "${parentField}": "parentId",
232
+ "${dependencyField}": [],
233
+ "status": "pending"
234
+ },
235
+ {
236
+ "id": "parent-2",
237
+ "title": "Second subtask (depends on first)",
238
+ "description": "Details...",
239
+ "${parentField}": "parentId",
240
+ "${dependencyField}": ["parent-1"],
241
+ "status": "pending"
242
+ }
243
+ ]`;
244
+
245
+ const userMessage = `Break down this task into ${min}-${max} subtasks:
246
+
247
+ ${JSON.stringify(item, null, 2)}`;
248
+
249
+ try {
250
+ const subtasks = await this.llm.getJSON(systemPrompt, userMessage, {
251
+ temperature: 0.4,
252
+ maxTokens: 2000
253
+ });
254
+
255
+ // Ensure all subtasks have proper parent reference and IDs
256
+ return subtasks.map((subtask, index) => ({
257
+ ...subtask,
258
+ id: subtask.id || `${item.id}-${index + 1}`,
259
+ [parentField]: item.id,
260
+ [dependencyField]: subtask[dependencyField] || [],
261
+ status: subtask.status || 'pending',
262
+ _meta: {
263
+ ...subtask._meta,
264
+ generatedFrom: item.id,
265
+ generatedAt: Date.now(),
266
+ depth: (item._meta?.depth || 0) + 1,
267
+ }
268
+ }));
269
+ } catch (error) {
270
+ console.error('Failed to generate subtasks:', error);
271
+ return [];
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Count total subtasks in a breakdown tree
277
+ * @private
278
+ */
279
+ _countSubtasks(node) {
280
+ if (!node.children || node.children.length === 0) {
281
+ return 0;
282
+ }
283
+ return node.children.length +
284
+ node.children.reduce((sum, child) => sum + this._countSubtasks(child), 0);
285
+ }
286
+
287
+ /**
288
+ * Flatten a breakdown tree into a list
289
+ * @param {Object} breakdownResult - Result from breakdown()
290
+ * @returns {Object[]} Flat list of all items
291
+ */
292
+ flatten(breakdownResult) {
293
+ const items = [];
294
+
295
+ const traverse = (node) => {
296
+ if (node.item) {
297
+ items.push(node.item);
298
+ }
299
+ if (node.children) {
300
+ for (const child of node.children) {
301
+ traverse(child);
302
+ }
303
+ }
304
+ };
305
+
306
+ if (breakdownResult.breakdown) {
307
+ traverse(breakdownResult.breakdown);
308
+ }
309
+
310
+ return items;
311
+ }
312
+
313
+ /**
314
+ * Get dependency order for execution
315
+ * @param {Object} breakdownResult - Result from breakdown()
316
+ * @returns {Object[]} Items in dependency order (parents before children)
317
+ */
318
+ getDependencyOrder(breakdownResult) {
319
+ const items = this.flatten(breakdownResult);
320
+
321
+ // Sort by depth (parents first) then by dependency order within same depth
322
+ return items.sort((a, b) => {
323
+ const depthA = a._meta?.depth || 0;
324
+ const depthB = b._meta?.depth || 0;
325
+ if (depthA !== depthB) return depthA - depthB;
326
+
327
+ // At same depth, check if b depends on a
328
+ const bDeps = b.dependencies || [];
329
+ if (bDeps.includes(a.id)) return -1;
330
+
331
+ const aDeps = a.dependencies || [];
332
+ if (aDeps.includes(b.id)) return 1;
333
+
334
+ return 0;
335
+ });
336
+ }
337
+
338
+ /**
339
+ * Suggest breakdown strategy for an item
340
+ * @param {Object} item - Item to analyze
341
+ * @returns {Promise<Object>} Suggested breakdown strategy
342
+ */
343
+ async suggestStrategy(item) {
344
+ const systemPrompt = `You are a task decomposition expert. Analyze this task and suggest the best breakdown strategy.
345
+
346
+ Consider:
347
+ 1. Task complexity
348
+ 2. Recommended depth (1-4 levels)
349
+ 3. Recommended subtasks per level (2-7)
350
+ 4. Key areas to focus on
351
+ 5. Potential dependencies between subtasks
352
+
353
+ Return JSON:
354
+ {
355
+ "complexity": "simple|moderate|complex|very_complex",
356
+ "recommendedDepth": n,
357
+ "recommendedStepsPerLevel": {"min": n, "max": n},
358
+ "focusAreas": ["area1", "area2"],
359
+ "potentialChallenges": ["challenge1"],
360
+ "estimatedTotalSubtasks": n,
361
+ "reasoning": "explanation"
362
+ }`;
363
+
364
+ return this.llm.getJSON(
365
+ systemPrompt,
366
+ JSON.stringify(item, null, 2),
367
+ { temperature: 0.3 }
368
+ );
369
+ }
370
+
371
+ /**
372
+ * Rebalance a breakdown tree (redistribute subtasks)
373
+ * @param {Object} breakdownResult - Existing breakdown result
374
+ * @param {Object} options - Rebalancing options
375
+ * @returns {Promise<Object>} Rebalanced breakdown
376
+ */
377
+ async rebalance(breakdownResult, options = {}) {
378
+ const { targetStepsPerLevel = { min: 3, max: 5 } } = options;
379
+
380
+ const items = this.flatten(breakdownResult);
381
+
382
+ const systemPrompt = `You are a task organization expert. Rebalance these tasks to have ${targetStepsPerLevel.min}-${targetStepsPerLevel.max} items per level.
383
+
384
+ Current tasks:
385
+ ${JSON.stringify(items, null, 2)}
386
+
387
+ Reorganize by:
388
+ 1. Merging tasks that are too granular
389
+ 2. Splitting tasks that are too large
390
+ 3. Maintaining proper dependency chains
391
+ 4. Keeping the same overall scope
392
+
393
+ Return JSON with the rebalanced structure:
394
+ {
395
+ "tasks": [...],
396
+ "changes": [{"type": "merge|split|move", "description": "..."}],
397
+ "summary": "what changed"
398
+ }`;
399
+
400
+ return this.llm.getJSON(systemPrompt, '', { temperature: 0.3 });
401
+ }
402
+
403
+ /**
404
+ * Update progress on a breakdown tree
405
+ * @param {string} holonId - Holon ID
406
+ * @param {string} lensName - Lens name
407
+ * @param {string} itemId - Root item ID
408
+ * @returns {Promise<Object>} Progress summary
409
+ */
410
+ async getProgress(holonId, lensName, itemId) {
411
+ if (!this.holosphere) {
412
+ throw new Error('HoloSphere instance required');
413
+ }
414
+
415
+ // Get all items
416
+ const allItems = await this.holosphere.getAll(holonId, lensName);
417
+
418
+ // Find root and all descendants
419
+ const root = allItems.find(i => i.id === itemId);
420
+ if (!root) {
421
+ throw new Error(`Item ${itemId} not found`);
422
+ }
423
+
424
+ const descendants = this._findDescendants(itemId, allItems);
425
+
426
+ // Calculate progress
427
+ const total = descendants.length;
428
+ const completed = descendants.filter(i =>
429
+ i.status === 'completed' || i.status === 'done'
430
+ ).length;
431
+ const inProgress = descendants.filter(i =>
432
+ i.status === 'in_progress' || i.status === 'active'
433
+ ).length;
434
+ const pending = total - completed - inProgress;
435
+
436
+ return {
437
+ itemId,
438
+ title: root.title || root.name,
439
+ total,
440
+ completed,
441
+ inProgress,
442
+ pending,
443
+ percentComplete: total > 0 ? Math.round((completed / total) * 100) : 0,
444
+ blockers: this._findBlockers(descendants),
445
+ nextUp: this._findNextTasks(descendants),
446
+ };
447
+ }
448
+
449
+ /**
450
+ * Find all descendants of an item
451
+ * @private
452
+ */
453
+ _findDescendants(itemId, allItems, parentField = 'parent') {
454
+ const descendants = [];
455
+ const children = allItems.filter(i => i[parentField] === itemId);
456
+
457
+ for (const child of children) {
458
+ descendants.push(child);
459
+ descendants.push(...this._findDescendants(child.id, allItems, parentField));
460
+ }
461
+
462
+ return descendants;
463
+ }
464
+
465
+ /**
466
+ * Find blocked tasks
467
+ * @private
468
+ */
469
+ _findBlockers(items, dependencyField = 'dependencies') {
470
+ return items.filter(item => {
471
+ const deps = item[dependencyField] || [];
472
+ if (deps.length === 0) return false;
473
+
474
+ // Check if any dependency is not completed
475
+ return deps.some(depId => {
476
+ const dep = items.find(i => i.id === depId);
477
+ return dep && dep.status !== 'completed' && dep.status !== 'done';
478
+ });
479
+ }).map(item => ({
480
+ id: item.id,
481
+ title: item.title || item.name,
482
+ blockedBy: item[dependencyField],
483
+ }));
484
+ }
485
+
486
+ /**
487
+ * Find next tasks ready to work on
488
+ * @private
489
+ */
490
+ _findNextTasks(items, dependencyField = 'dependencies') {
491
+ return items.filter(item => {
492
+ if (item.status === 'completed' || item.status === 'done') return false;
493
+ if (item.status === 'in_progress' || item.status === 'active') return false;
494
+
495
+ const deps = item[dependencyField] || [];
496
+ if (deps.length === 0) return true;
497
+
498
+ // All dependencies must be completed
499
+ return deps.every(depId => {
500
+ const dep = items.find(i => i.id === depId);
501
+ return !dep || dep.status === 'completed' || dep.status === 'done';
502
+ });
503
+ }).slice(0, 5).map(item => ({
504
+ id: item.id,
505
+ title: item.title || item.name,
506
+ description: item.description,
507
+ }));
508
+ }
509
+ }
510
+
511
+ export default TaskBreakdown;