coaiajs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CLAUDE.md +56 -0
  2. package/KINSHIP.md +63 -0
  3. package/README.md +148 -0
  4. package/articles/academic/creative-orientation-vs-problem-solving.md +177 -0
  5. package/articles/academic/jsonl-knowledge-graphs-agent-memory.md +142 -0
  6. package/articles/academic/langfuse-observability-llm-pipelines.md +144 -0
  7. package/articles/academic/medicine-wheel-software-architecture.md +163 -0
  8. package/articles/academic/mmot-autonomous-agents.md +156 -0
  9. package/articles/academic/model-context-protocol-interagent.md +161 -0
  10. package/articles/academic/pde-prompt-decomposition.md +186 -0
  11. package/articles/academic/structural-tension-in-ai-agents.md +134 -0
  12. package/articles/reviews/mcp-protocol-design-review.md +170 -0
  13. package/articles/reviews/observability-ai-systems-review.md +176 -0
  14. package/articles/reviews/prompt-engineering-decomposition-review.md +184 -0
  15. package/articles/surveys/agent-orchestration-survey.md +186 -0
  16. package/articles/surveys/knowledge-graph-storage-survey.md +204 -0
  17. package/articles/surveys/structural-tension-methodology-survey.md +154 -0
  18. package/articles/technical/aws-sdk-v3-polly.md +270 -0
  19. package/articles/technical/commander-cli-framework.md +262 -0
  20. package/articles/technical/dotenv-config-patterns.md +360 -0
  21. package/articles/technical/ioredis-vs-redis.md +142 -0
  22. package/articles/technical/langfuse-js-sdk-vs-rest.md +191 -0
  23. package/articles/technical/mcp-sdk-typescript.md +291 -0
  24. package/articles/technical/octokit-github-api.md +293 -0
  25. package/articles/technical/openai-sdk-modern.md +231 -0
  26. package/articles/technical/yaml-parsing-node.md +266 -0
  27. package/articles/technical/zod-runtime-validation.md +212 -0
  28. package/dist/mcp/config.d.ts +14 -0
  29. package/dist/mcp/config.js +185 -0
  30. package/dist/mcp/server.d.ts +3 -0
  31. package/dist/mcp/server.js +324 -0
  32. package/dist/mcp/tools/coaiapy-tools.d.ts +8 -0
  33. package/dist/mcp/tools/coaiapy-tools.js +326 -0
  34. package/dist/mcp/tools/index.d.ts +3 -0
  35. package/dist/mcp/tools/index.js +3 -0
  36. package/dist/src/audio.d.ts +12 -0
  37. package/dist/src/audio.js +57 -0
  38. package/dist/src/cli-helpers.d.ts +9 -0
  39. package/dist/src/cli-helpers.js +78 -0
  40. package/dist/src/cli.d.ts +3 -0
  41. package/dist/src/cli.js +1086 -0
  42. package/dist/src/config.d.ts +15 -0
  43. package/dist/src/config.js +145 -0
  44. package/dist/src/environment.d.ts +44 -0
  45. package/dist/src/environment.js +146 -0
  46. package/dist/src/github.d.ts +47 -0
  47. package/dist/src/github.js +79 -0
  48. package/dist/src/langfuse/client.d.ts +30 -0
  49. package/dist/src/langfuse/client.js +75 -0
  50. package/dist/src/langfuse/comments.d.ts +16 -0
  51. package/dist/src/langfuse/comments.js +36 -0
  52. package/dist/src/langfuse/datasets.d.ts +19 -0
  53. package/dist/src/langfuse/datasets.js +140 -0
  54. package/dist/src/langfuse/index.d.ts +13 -0
  55. package/dist/src/langfuse/index.js +10 -0
  56. package/dist/src/langfuse/media.d.ts +11 -0
  57. package/dist/src/langfuse/media.js +167 -0
  58. package/dist/src/langfuse/observations.d.ts +18 -0
  59. package/dist/src/langfuse/observations.js +113 -0
  60. package/dist/src/langfuse/prompts.d.ts +14 -0
  61. package/dist/src/langfuse/prompts.js +127 -0
  62. package/dist/src/langfuse/scores.d.ts +54 -0
  63. package/dist/src/langfuse/scores.js +366 -0
  64. package/dist/src/langfuse/traces.d.ts +29 -0
  65. package/dist/src/langfuse/traces.js +225 -0
  66. package/dist/src/llm.d.ts +23 -0
  67. package/dist/src/llm.js +76 -0
  68. package/dist/src/narrative/graph-manager.d.ts +106 -0
  69. package/dist/src/narrative/graph-manager.js +915 -0
  70. package/dist/src/narrative/index.d.ts +9 -0
  71. package/dist/src/narrative/index.js +7 -0
  72. package/dist/src/narrative/markdown-export.d.ts +21 -0
  73. package/dist/src/narrative/markdown-export.js +383 -0
  74. package/dist/src/narrative/tool-definitions.d.ts +21 -0
  75. package/dist/src/narrative/tool-definitions.js +588 -0
  76. package/dist/src/narrative/tool-handlers.d.ts +11 -0
  77. package/dist/src/narrative/tool-handlers.js +462 -0
  78. package/dist/src/narrative/types.d.ts +2 -0
  79. package/dist/src/narrative/types.js +2 -0
  80. package/dist/src/narrative/validation.d.ts +29 -0
  81. package/dist/src/narrative/validation.js +144 -0
  82. package/dist/src/pde/index.d.ts +8 -0
  83. package/dist/src/pde/index.js +8 -0
  84. package/dist/src/pde/mcp-handlers.d.ts +7 -0
  85. package/dist/src/pde/mcp-handlers.js +300 -0
  86. package/dist/src/pde/mcp-tools.d.ts +15 -0
  87. package/dist/src/pde/mcp-tools.js +191 -0
  88. package/dist/src/pde/session-manager.d.ts +32 -0
  89. package/dist/src/pde/session-manager.js +205 -0
  90. package/dist/src/pde/stc-mapper.d.ts +26 -0
  91. package/dist/src/pde/stc-mapper.js +234 -0
  92. package/dist/src/pipeline/index.d.ts +2 -0
  93. package/dist/src/pipeline/index.js +3 -0
  94. package/dist/src/pipeline/template-engine.d.ts +20 -0
  95. package/dist/src/pipeline/template-engine.js +361 -0
  96. package/dist/src/planning/index.d.ts +7 -0
  97. package/dist/src/planning/index.js +7 -0
  98. package/dist/src/planning/mcp-handlers.d.ts +7 -0
  99. package/dist/src/planning/mcp-handlers.js +310 -0
  100. package/dist/src/planning/mcp-tools.d.ts +15 -0
  101. package/dist/src/planning/mcp-tools.js +145 -0
  102. package/dist/src/planning/plan-parser.d.ts +35 -0
  103. package/dist/src/planning/plan-parser.js +506 -0
  104. package/dist/src/redis.d.ts +21 -0
  105. package/dist/src/redis.js +78 -0
  106. package/dist/src/types.d.ts +244 -0
  107. package/dist/src/types.js +8 -0
  108. package/mcp/config.ts +196 -0
  109. package/mcp/server.ts +402 -0
  110. package/mcp/tools/coaiapy-tools.ts +364 -0
  111. package/mcp/tools/index.ts +4 -0
  112. package/package.json +52 -0
  113. package/rispecs/00-coaiajs-platform.spec.md +102 -0
  114. package/rispecs/01-core-config.spec.md +89 -0
  115. package/rispecs/02-redis-module.spec.md +62 -0
  116. package/rispecs/03-langfuse-module.spec.md +101 -0
  117. package/rispecs/04-narrative-engine.spec.md +185 -0
  118. package/rispecs/05-pde-engine.spec.md +112 -0
  119. package/rispecs/06-planning-engine.spec.md +128 -0
  120. package/rispecs/07-pipeline-templates.spec.md +97 -0
  121. package/rispecs/08-cli-interface.spec.md +134 -0
  122. package/rispecs/09-mcp-server.spec.md +140 -0
  123. package/rispecs/10-audio-module.spec.md +63 -0
  124. package/rispecs/KINSHIP.md +56 -0
  125. package/rispecs/README.md +100 -0
  126. package/src/audio.ts +76 -0
  127. package/src/cli-helpers.ts +86 -0
  128. package/src/cli.ts +1223 -0
  129. package/src/config.ts +172 -0
  130. package/src/environment.ts +171 -0
  131. package/src/github.ts +143 -0
  132. package/src/langfuse/client.ts +105 -0
  133. package/src/langfuse/comments.ts +52 -0
  134. package/src/langfuse/datasets.ts +178 -0
  135. package/src/langfuse/index.ts +33 -0
  136. package/src/langfuse/media.ts +193 -0
  137. package/src/langfuse/observations.ts +131 -0
  138. package/src/langfuse/prompts.ts +157 -0
  139. package/src/langfuse/scores.ts +456 -0
  140. package/src/langfuse/traces.ts +276 -0
  141. package/src/llm.ts +106 -0
  142. package/src/narrative/graph-manager.ts +1358 -0
  143. package/src/narrative/index.ts +32 -0
  144. package/src/narrative/markdown-export.ts +535 -0
  145. package/src/narrative/tool-definitions.ts +635 -0
  146. package/src/narrative/tool-handlers.ts +528 -0
  147. package/src/narrative/types.ts +9 -0
  148. package/src/narrative/validation.ts +179 -0
  149. package/src/pde/index.ts +8 -0
  150. package/src/pde/mcp-handlers.ts +359 -0
  151. package/src/pde/mcp-tools.ts +201 -0
  152. package/src/pde/session-manager.ts +248 -0
  153. package/src/pde/stc-mapper.ts +298 -0
  154. package/src/pipeline/index.ts +7 -0
  155. package/src/pipeline/template-engine.ts +398 -0
  156. package/src/planning/index.ts +13 -0
  157. package/src/planning/mcp-handlers.ts +369 -0
  158. package/src/planning/mcp-tools.ts +155 -0
  159. package/src/planning/plan-parser.ts +587 -0
  160. package/src/redis.ts +97 -0
  161. package/src/types.ts +280 -0
  162. package/tsconfig.json +26 -0
@@ -0,0 +1,915 @@
1
+ /**
2
+ * KnowledgeGraphManager — JSONL-backed knowledge graph engine
3
+ *
4
+ * Ported from coaia-narrative/src/graph-manager.ts (1294 lines).
5
+ * Implements structural tension charts, narrative beats, MMOT evaluation,
6
+ * and general-purpose entity/relation CRUD over a JSONL file.
7
+ */
8
+ import { promises as fs } from 'fs';
9
+ export class KnowledgeGraphManager {
10
+ memoryFilePath;
11
+ constructor(memoryFilePath) {
12
+ this.memoryFilePath = memoryFilePath;
13
+ }
14
+ // ─── JSONL Storage ──────────────────────────────────────────────────
15
+ async loadGraph() {
16
+ try {
17
+ const data = await fs.readFile(this.memoryFilePath, 'utf-8');
18
+ const lines = data.split('\n').filter(line => line.trim() !== '');
19
+ return lines.reduce((graph, line) => {
20
+ const item = JSON.parse(line);
21
+ if (item.type === 'entity')
22
+ graph.entities.push(item);
23
+ if (item.type === 'relation')
24
+ graph.relations.push(item);
25
+ // Support narrative_beat entities stored in legacy format
26
+ if (item.type === 'narrative_beat') {
27
+ const narrativeBeat = {
28
+ name: item.name,
29
+ entityType: 'narrative_beat',
30
+ observations: item.observations || [],
31
+ metadata: {
32
+ ...item.metadata,
33
+ narrative: item.narrative,
34
+ relationalAlignment: item.relational_alignment,
35
+ fourDirections: item.four_directions,
36
+ },
37
+ };
38
+ graph.entities.push(narrativeBeat);
39
+ }
40
+ return graph;
41
+ }, { entities: [], relations: [] });
42
+ }
43
+ catch (error) {
44
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
45
+ return { entities: [], relations: [] };
46
+ }
47
+ throw error;
48
+ }
49
+ }
50
+ async saveGraph(graph) {
51
+ const lines = [
52
+ ...graph.entities.map(e => JSON.stringify({ type: 'entity', ...e })),
53
+ ...graph.relations.map(r => JSON.stringify({ type: 'relation', ...r })),
54
+ ];
55
+ await fs.writeFile(this.memoryFilePath, lines.join('\n'));
56
+ }
57
+ // ─── Knowledge Graph CRUD ───────────────────────────────────────────
58
+ async createEntities(entities) {
59
+ const graph = await this.loadGraph();
60
+ const newEntities = entities.filter(e => !graph.entities.some(existing => existing.name === e.name));
61
+ graph.entities.push(...newEntities);
62
+ await this.saveGraph(graph);
63
+ return newEntities;
64
+ }
65
+ async createRelations(relations) {
66
+ const graph = await this.loadGraph();
67
+ const newRelations = relations.filter(r => !graph.relations.some(existing => existing.from === r.from &&
68
+ existing.to === r.to &&
69
+ existing.relationType === r.relationType));
70
+ graph.relations.push(...newRelations);
71
+ await this.saveGraph(graph);
72
+ return newRelations;
73
+ }
74
+ async addObservations(observations) {
75
+ const graph = await this.loadGraph();
76
+ const results = observations.map(o => {
77
+ const entity = graph.entities.find(e => e.name === o.entityName);
78
+ if (!entity) {
79
+ throw new Error(`Entity with name ${o.entityName} not found`);
80
+ }
81
+ const newObservations = o.contents.filter(content => !entity.observations.includes(content));
82
+ entity.observations.push(...newObservations);
83
+ return { entityName: o.entityName, addedObservations: newObservations };
84
+ });
85
+ await this.saveGraph(graph);
86
+ return results;
87
+ }
88
+ async deleteEntities(entityNames) {
89
+ const graph = await this.loadGraph();
90
+ graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
91
+ graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to));
92
+ await this.saveGraph(graph);
93
+ }
94
+ async deleteObservations(deletions) {
95
+ const graph = await this.loadGraph();
96
+ deletions.forEach(d => {
97
+ const entity = graph.entities.find(e => e.name === d.entityName);
98
+ if (entity) {
99
+ entity.observations = entity.observations.filter(o => !d.observations.includes(o));
100
+ }
101
+ });
102
+ await this.saveGraph(graph);
103
+ }
104
+ async deleteRelations(relations) {
105
+ const graph = await this.loadGraph();
106
+ graph.relations = graph.relations.filter(r => !relations.some(del => r.from === del.from &&
107
+ r.to === del.to &&
108
+ r.relationType === del.relationType));
109
+ await this.saveGraph(graph);
110
+ }
111
+ async readGraph() {
112
+ return this.loadGraph();
113
+ }
114
+ async searchNodes(query) {
115
+ const graph = await this.loadGraph();
116
+ const q = query.toLowerCase();
117
+ const filteredEntities = graph.entities.filter(e => e.name.toLowerCase().includes(q) ||
118
+ e.entityType.toLowerCase().includes(q) ||
119
+ e.observations.some(o => o.toLowerCase().includes(q)));
120
+ const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
121
+ const filteredRelations = graph.relations.filter(r => filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to));
122
+ return { entities: filteredEntities, relations: filteredRelations };
123
+ }
124
+ async openNodes(names) {
125
+ const graph = await this.loadGraph();
126
+ const filteredEntities = graph.entities.filter(e => names.includes(e.name));
127
+ const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
128
+ const filteredRelations = graph.relations.filter(r => filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to));
129
+ return { entities: filteredEntities, relations: filteredRelations };
130
+ }
131
+ // ─── Chart Details ──────────────────────────────────────────────────
132
+ async getChartDetails(chartId) {
133
+ const graph = await this.loadGraph();
134
+ const chartEntities = graph.entities.filter(e => e.metadata?.chartId === chartId);
135
+ if (chartEntities.length === 0)
136
+ return null;
137
+ const chartEntityNames = new Set(chartEntities.map(e => e.name));
138
+ const chartRelations = graph.relations.filter(r => chartEntityNames.has(r.from) && chartEntityNames.has(r.to));
139
+ return { entities: chartEntities, relations: chartRelations };
140
+ }
141
+ async getActionStepDetails(actionStepName) {
142
+ const graph = await this.loadGraph();
143
+ const actionStepEntity = graph.entities.find(e => e.name === actionStepName &&
144
+ (e.entityType === 'action_step' || e.entityType === 'desired_outcome'));
145
+ if (!actionStepEntity)
146
+ return null;
147
+ // Follow the telescopes_into relation
148
+ const telescopesRelation = graph.relations.find(r => r.from === actionStepName && r.relationType === 'telescopes_into');
149
+ if (!telescopesRelation)
150
+ return null;
151
+ const telescopedOutcomeEntity = graph.entities.find(e => e.name === telescopesRelation.to);
152
+ if (!telescopedOutcomeEntity || !telescopedOutcomeEntity.metadata?.chartId) {
153
+ return null;
154
+ }
155
+ return this.getChartDetails(telescopedOutcomeEntity.metadata.chartId);
156
+ }
157
+ // ─── Structural Tension Charts ──────────────────────────────────────
158
+ async createStructuralTensionChart(desiredOutcome, currentReality, dueDate, actionSteps, elementsOfPerformance) {
159
+ // Creative orientation validation
160
+ const problemSolvingWords = ['fix', 'solve', 'eliminate', 'prevent', 'stop', 'avoid', 'reduce', 'remove'];
161
+ const detectedProblemWords = problemSolvingWords.filter(word => desiredOutcome.toLowerCase().includes(word));
162
+ if (detectedProblemWords.length > 0) {
163
+ throw new Error(`🌊 CREATIVE ORIENTATION REQUIRED\n\n` +
164
+ `Desired Outcome: "${desiredOutcome}"\n\n` +
165
+ `❌ **Problem**: Contains problem-solving language: "${detectedProblemWords.join(', ')}"\n` +
166
+ `📚 **Principle**: Structural Tension Charts use creative orientation - focus on what you want to CREATE, not what you want to eliminate.\n\n` +
167
+ `🎯 **Reframe Your Outcome**:\n` +
168
+ `Instead of elimination → Creation focus\n\n` +
169
+ `✅ **Examples**:\n` +
170
+ `- Instead of: "Fix communication problems"\n` +
171
+ `- Use: "Establish clear, effective communication practices"\n\n` +
172
+ `- Instead of: "Reduce website loading time"\n` +
173
+ `- Use: "Achieve fast, responsive website performance"\n\n` +
174
+ `**Why This Matters**: Problem-solving creates oscillating patterns. Creative orientation creates advancing patterns toward desired outcomes.\n\n` +
175
+ `💡 **Tip**: Run 'init_llm_guidance' for complete methodology overview.`);
176
+ }
177
+ // Delayed resolution validation
178
+ const readinessWords = ['ready to', 'prepared to', 'all set', 'ready for', 'set to'];
179
+ const detectedReadinessWords = readinessWords.filter(phrase => currentReality.toLowerCase().includes(phrase));
180
+ if (detectedReadinessWords.length > 0) {
181
+ throw new Error(`🌊 DELAYED RESOLUTION PRINCIPLE VIOLATION\n\n` +
182
+ `Current Reality: "${currentReality}"\n\n` +
183
+ `❌ **Problem**: Contains readiness assumptions: "${detectedReadinessWords.join(', ')}"\n` +
184
+ `📚 **Principle**: "Tolerate discrepancy, tension, and delayed resolution" - Robert Fritz\n\n` +
185
+ `🎯 **What's Needed**: Factual assessment of your actual current state (not readiness or preparation).\n\n` +
186
+ `✅ **Examples**:\n` +
187
+ `- Instead of: "Ready to learn Python"\n` +
188
+ `- Use: "Never programmed before, interested in web development"\n\n` +
189
+ `- Instead of: "Prepared to start the project"\n` +
190
+ `- Use: "Have project requirements, no code written yet"\n\n` +
191
+ `**Why This Matters**: Readiness assumptions prematurely resolve the structural tension needed for creative advancement.\n\n` +
192
+ `💡 **Tip**: Run 'init_llm_guidance' for complete methodology overview.`);
193
+ }
194
+ const chartId = `chart_${Date.now()}`;
195
+ const timestamp = new Date().toISOString();
196
+ const entities = [
197
+ {
198
+ name: `${chartId}_chart`,
199
+ entityType: 'structural_tension_chart',
200
+ observations: [`Chart created on ${timestamp}`],
201
+ metadata: {
202
+ chartId,
203
+ dueDate,
204
+ level: 0,
205
+ createdAt: timestamp,
206
+ updatedAt: timestamp,
207
+ ...(elementsOfPerformance && elementsOfPerformance.length > 0
208
+ ? { elementsOfPerformance }
209
+ : {}),
210
+ },
211
+ },
212
+ {
213
+ name: `${chartId}_desired_outcome`,
214
+ entityType: 'desired_outcome',
215
+ observations: [desiredOutcome],
216
+ metadata: {
217
+ chartId,
218
+ dueDate,
219
+ createdAt: timestamp,
220
+ updatedAt: timestamp,
221
+ },
222
+ },
223
+ {
224
+ name: `${chartId}_current_reality`,
225
+ entityType: 'current_reality',
226
+ observations: [currentReality],
227
+ metadata: {
228
+ chartId,
229
+ createdAt: timestamp,
230
+ updatedAt: timestamp,
231
+ },
232
+ },
233
+ ];
234
+ // Add action steps if provided
235
+ if (actionSteps && actionSteps.length > 0) {
236
+ const stepDueDates = this.distributeActionStepDates(new Date(), new Date(dueDate), actionSteps.length);
237
+ actionSteps.forEach((step, index) => {
238
+ entities.push({
239
+ name: `${chartId}_action_${index + 1}`,
240
+ entityType: 'action_step',
241
+ observations: [step],
242
+ metadata: {
243
+ chartId,
244
+ dueDate: stepDueDates[index].toISOString(),
245
+ completionStatus: false,
246
+ createdAt: timestamp,
247
+ updatedAt: timestamp,
248
+ },
249
+ });
250
+ });
251
+ }
252
+ // Create relations
253
+ const relations = [
254
+ {
255
+ from: `${chartId}_chart`,
256
+ to: `${chartId}_desired_outcome`,
257
+ relationType: 'contains',
258
+ metadata: { createdAt: timestamp },
259
+ },
260
+ {
261
+ from: `${chartId}_chart`,
262
+ to: `${chartId}_current_reality`,
263
+ relationType: 'contains',
264
+ metadata: { createdAt: timestamp },
265
+ },
266
+ {
267
+ from: `${chartId}_current_reality`,
268
+ to: `${chartId}_desired_outcome`,
269
+ relationType: 'creates_tension_with',
270
+ metadata: { createdAt: timestamp },
271
+ },
272
+ ];
273
+ // Add action step relations
274
+ if (actionSteps && actionSteps.length > 0) {
275
+ actionSteps.forEach((_, index) => {
276
+ const actionName = `${chartId}_action_${index + 1}`;
277
+ relations.push({
278
+ from: `${chartId}_chart`,
279
+ to: actionName,
280
+ relationType: 'contains',
281
+ metadata: { createdAt: timestamp },
282
+ }, {
283
+ from: actionName,
284
+ to: `${chartId}_desired_outcome`,
285
+ relationType: 'advances_toward',
286
+ metadata: { createdAt: timestamp },
287
+ });
288
+ });
289
+ }
290
+ await this.createEntities(entities);
291
+ await this.createRelations(relations);
292
+ return { chartId, entities, relations };
293
+ }
294
+ // ─── Telescope Action Step ──────────────────────────────────────────
295
+ async telescopeActionStep(actionStepName, newCurrentReality, initialActionSteps) {
296
+ const graph = await this.loadGraph();
297
+ const actionStep = graph.entities.find(e => e.name === actionStepName && e.entityType === 'action_step');
298
+ if (!actionStep || !actionStep.metadata?.chartId) {
299
+ throw new Error(`Action step ${actionStepName} not found or not properly configured`);
300
+ }
301
+ const parentChartId = actionStep.metadata.chartId;
302
+ const inheritedDueDate = actionStep.metadata.dueDate ||
303
+ new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
304
+ const desiredOutcome = actionStep.observations[0];
305
+ const result = await this.createStructuralTensionChart(desiredOutcome, newCurrentReality, inheritedDueDate, initialActionSteps);
306
+ // Update new chart metadata to reflect telescoping relationship
307
+ const newGraph = await this.loadGraph();
308
+ const chartEntity = newGraph.entities.find(e => e.name === `${result.chartId}_chart`);
309
+ if (chartEntity && chartEntity.metadata) {
310
+ chartEntity.metadata.parentChart = parentChartId;
311
+ chartEntity.metadata.parentActionStep = actionStepName;
312
+ chartEntity.metadata.level = (actionStep.metadata.level || 0) + 1;
313
+ chartEntity.metadata.updatedAt = new Date().toISOString();
314
+ }
315
+ await this.saveGraph(newGraph);
316
+ return { chartId: result.chartId, parentChart: parentChartId };
317
+ }
318
+ // ─── Mark Action Complete ───────────────────────────────────────────
319
+ async markActionStepComplete(actionStepName) {
320
+ const graph = await this.loadGraph();
321
+ const actionStep = graph.entities.find(e => e.name === actionStepName &&
322
+ (e.entityType === 'action_step' || e.entityType === 'desired_outcome'));
323
+ if (!actionStep) {
324
+ throw new Error(`Action step ${actionStepName} not found`);
325
+ }
326
+ const chartId = actionStep.metadata?.chartId;
327
+ if (!chartId) {
328
+ throw new Error(`Chart ID not found for action step ${actionStepName}`);
329
+ }
330
+ if (actionStep.metadata) {
331
+ actionStep.metadata.completionStatus = true;
332
+ actionStep.metadata.updatedAt = new Date().toISOString();
333
+ }
334
+ // Also mark the parent chart entity as complete
335
+ const chartEntity = graph.entities.find(e => e.name === `${chartId}_chart`);
336
+ if (chartEntity && chartEntity.metadata) {
337
+ chartEntity.metadata.completionStatus = true;
338
+ chartEntity.metadata.updatedAt = new Date().toISOString();
339
+ }
340
+ // Completed action steps flow into parent chart's current reality
341
+ const parentChartId = chartEntity?.metadata?.parentChart;
342
+ if (parentChartId) {
343
+ const parentCurrentReality = graph.entities.find(e => e.name === `${parentChartId}_current_reality` &&
344
+ e.entityType === 'current_reality');
345
+ if (parentCurrentReality) {
346
+ const completionMessage = `Completed: ${actionStep.observations[0]}`;
347
+ if (!parentCurrentReality.observations.includes(completionMessage)) {
348
+ parentCurrentReality.observations.push(completionMessage);
349
+ if (parentCurrentReality.metadata) {
350
+ parentCurrentReality.metadata.updatedAt = new Date().toISOString();
351
+ }
352
+ }
353
+ }
354
+ }
355
+ await this.saveGraph(graph);
356
+ }
357
+ // ─── Chart Progress ─────────────────────────────────────────────────
358
+ async getChartProgress(chartId, preloadedGraph) {
359
+ const graph = preloadedGraph ?? (await this.loadGraph());
360
+ const actionSteps = graph.entities.filter(e => e.entityType === 'action_step' && e.metadata?.chartId === chartId);
361
+ const completedActions = actionSteps.filter(e => e.metadata?.completionStatus === true).length;
362
+ const totalActions = actionSteps.length;
363
+ const progress = totalActions > 0 ? completedActions / totalActions : 0;
364
+ // Next incomplete action step by earliest due date
365
+ const incompleteActions = actionSteps
366
+ .filter(e => e.metadata?.completionStatus !== true)
367
+ .sort((a, b) => {
368
+ const dateA = new Date(a.metadata?.dueDate || '').getTime();
369
+ const dateB = new Date(b.metadata?.dueDate || '').getTime();
370
+ return dateA - dateB;
371
+ });
372
+ const chart = graph.entities.find(e => e.name === `${chartId}_chart`);
373
+ return {
374
+ chartId,
375
+ progress,
376
+ completedActions,
377
+ totalActions,
378
+ nextAction: incompleteActions[0]?.name,
379
+ dueDate: chart?.metadata?.dueDate,
380
+ };
381
+ }
382
+ // ─── List Active Charts ─────────────────────────────────────────────
383
+ async listActiveCharts() {
384
+ const graph = await this.loadGraph();
385
+ const charts = graph.entities.filter(e => e.entityType === 'structural_tension_chart');
386
+ const chartSummaries = await Promise.all(charts.map(async (chart) => {
387
+ const chartId = chart.metadata?.chartId || chart.name.replace('_chart', '');
388
+ const progress = await this.getChartProgress(chartId, graph);
389
+ const desiredOutcome = graph.entities.find(e => e.name === `${chartId}_desired_outcome` &&
390
+ e.entityType === 'desired_outcome');
391
+ return {
392
+ chartId,
393
+ desiredOutcome: desiredOutcome?.observations[0] || 'Unknown outcome',
394
+ dueDate: chart.metadata?.dueDate,
395
+ progress: progress.progress,
396
+ completedActions: progress.completedActions,
397
+ totalActions: progress.totalActions,
398
+ level: chart.metadata?.level || 0,
399
+ parentChart: chart.metadata?.parentChart,
400
+ };
401
+ }));
402
+ return chartSummaries.sort((a, b) => {
403
+ if (a.level !== b.level)
404
+ return a.level - b.level;
405
+ const dateA = new Date(a.dueDate || '').getTime();
406
+ const dateB = new Date(b.dueDate || '').getTime();
407
+ return dateA - dateB;
408
+ });
409
+ }
410
+ // ─── Update Action Progress ─────────────────────────────────────────
411
+ async updateActionProgress(actionStepName, progressObservation, updateCurrentReality) {
412
+ const graph = await this.loadGraph();
413
+ const actionStep = graph.entities.find(e => e.name === actionStepName &&
414
+ (e.entityType === 'action_step' || e.entityType === 'desired_outcome'));
415
+ if (!actionStep) {
416
+ throw new Error(`Action step ${actionStepName} not found`);
417
+ }
418
+ actionStep.observations.push(progressObservation);
419
+ if (actionStep.metadata) {
420
+ actionStep.metadata.updatedAt = new Date().toISOString();
421
+ }
422
+ if (updateCurrentReality && actionStep.metadata?.chartId) {
423
+ const chartEntity = graph.entities.find(e => e.name === `${actionStep.metadata.chartId}_chart`);
424
+ const parentChartId = chartEntity?.metadata?.parentChart;
425
+ const targetChartId = parentChartId || actionStep.metadata.chartId;
426
+ const currentReality = graph.entities.find(e => e.name === `${targetChartId}_current_reality` &&
427
+ e.entityType === 'current_reality');
428
+ if (currentReality) {
429
+ const progressMessage = `Progress on ${actionStep.observations[0]}: ${progressObservation}`;
430
+ if (!currentReality.observations.includes(progressMessage)) {
431
+ currentReality.observations.push(progressMessage);
432
+ if (currentReality.metadata) {
433
+ currentReality.metadata.updatedAt = new Date().toISOString();
434
+ }
435
+ }
436
+ }
437
+ }
438
+ await this.saveGraph(graph);
439
+ }
440
+ // ─── Update Current Reality ─────────────────────────────────────────
441
+ async updateCurrentReality(chartId, newObservations) {
442
+ const graph = await this.loadGraph();
443
+ const currentReality = graph.entities.find(e => e.name === `${chartId}_current_reality` &&
444
+ e.entityType === 'current_reality');
445
+ if (!currentReality) {
446
+ throw new Error(`Chart ${chartId} not found or missing current reality`);
447
+ }
448
+ const uniqueObservations = newObservations.filter(obs => !currentReality.observations.includes(obs));
449
+ currentReality.observations.push(...uniqueObservations);
450
+ if (currentReality.metadata) {
451
+ currentReality.metadata.updatedAt = new Date().toISOString();
452
+ }
453
+ await this.saveGraph(graph);
454
+ }
455
+ // ─── Update Desired Outcome ─────────────────────────────────────────
456
+ async updateDesiredOutcome(chartId, newDesiredOutcome) {
457
+ const graph = await this.loadGraph();
458
+ const desiredOutcomeEntity = graph.entities.find(e => e.name === `${chartId}_desired_outcome` &&
459
+ e.entityType === 'desired_outcome');
460
+ if (!desiredOutcomeEntity) {
461
+ throw new Error(`Chart ${chartId} desired outcome not found`);
462
+ }
463
+ desiredOutcomeEntity.observations[0] = newDesiredOutcome;
464
+ if (desiredOutcomeEntity.metadata) {
465
+ desiredOutcomeEntity.metadata.updatedAt = new Date().toISOString();
466
+ }
467
+ await this.saveGraph(graph);
468
+ }
469
+ // ─── MMOT Evaluation ────────────────────────────────────────────────
470
+ async performMmotEvaluation(chartId, phase = 'full', assessment, direction, correctiveActions, updateReality = true) {
471
+ const graph = await this.loadGraph();
472
+ const chartEntity = graph.entities.find(e => e.entityType === 'structural_tension_chart' &&
473
+ e.metadata?.chartId === chartId);
474
+ if (!chartEntity) {
475
+ throw new Error(`Chart ${chartId} not found`);
476
+ }
477
+ const desiredOutcome = graph.entities.find(e => e.name === `${chartId}_desired_outcome`);
478
+ const currentReality = graph.entities.find(e => e.name === `${chartId}_current_reality`);
479
+ const actionSteps = graph.entities.filter(e => e.entityType === 'action_step' && e.metadata?.chartId === chartId);
480
+ const completedActions = actionSteps.filter(a => a.metadata?.completionStatus);
481
+ const totalActions = actionSteps.length;
482
+ const progressPct = totalActions > 0
483
+ ? Math.round((completedActions.length / totalActions) * 100)
484
+ : 0;
485
+ const elementsOfPerformance = chartEntity.metadata?.elementsOfPerformance || [];
486
+ const designElements = elementsOfPerformance.filter(e => e.type === 'DESIGN');
487
+ const executionElements = elementsOfPerformance.filter(e => e.type === 'EXECUTION');
488
+ const directionLabel = direction ? ` [${direction}]` : '';
489
+ const timestamp = new Date().toISOString();
490
+ // Build phase-specific guidance
491
+ const phaseGuidance = {
492
+ acknowledge: `## MMOT Phase 1: Acknowledge the Truth${directionLabel}\n\n` +
493
+ `**Chart**: ${chartId}\n` +
494
+ `**Desired Outcome**: ${desiredOutcome?.observations[0] || 'Unknown'}\n` +
495
+ `**Current Reality**: ${currentReality?.observations.join('; ') || 'Unknown'}\n` +
496
+ `**Progress**: ${progressPct}% (${completedActions.length}/${totalActions} actions)\n\n` +
497
+ (elementsOfPerformance.length > 0
498
+ ? `**Elements of Performance:**\n` +
499
+ designElements.map(e => `- 🏗️ DESIGN: ${e.description}`).join('\n') +
500
+ '\n' +
501
+ executionElements.map(e => `- ⚡ EXECUTION: ${e.description}`).join('\n') +
502
+ '\n\n'
503
+ : '') +
504
+ `**Task**: Compare produced output against each element of performance. What difference exists between expected and delivered?\n\n` +
505
+ (assessment
506
+ ? `**Assessment**: ${assessment}`
507
+ : 'Provide honest assessment of what was expected vs. what actually happened.'),
508
+ analyze: `## MMOT Phase 2: Analyze How It Got There${directionLabel}\n\n` +
509
+ `**Task**: Blow-by-blow of what actions were taken and what dynamics produced the current result.\n` +
510
+ `- What assumptions were made?\n` +
511
+ `- What worked and what didn't?\n` +
512
+ `- What did the engagement reveal?\n\n` +
513
+ (assessment
514
+ ? `**Analysis**: ${assessment}`
515
+ : 'Walk through the sequence of events that led to the current state.'),
516
+ update: `## MMOT Phase 3: Update the Chart${directionLabel}\n\n` +
517
+ `**Task**: Based on what was learned:\n` +
518
+ `- Update current reality with new observations\n` +
519
+ `- Adjust remaining action steps\n` +
520
+ `- Add corrective actions if needed\n\n` +
521
+ (assessment
522
+ ? `**Updates Applied**: ${assessment}`
523
+ : 'Describe what observations should flow into current reality.'),
524
+ recommit: `## MMOT Phase 4: Recommit or Redirect${directionLabel}\n\n` +
525
+ `**Desired Outcome**: ${desiredOutcome?.observations[0] || 'Unknown'}\n\n` +
526
+ `**Task**: Is this desired outcome still what you want to create?\n` +
527
+ `- If yes: What are the next strategic secondary choices?\n` +
528
+ `- If no: Close this chart and create a new one with the actual desired outcome.\n\n` +
529
+ (assessment
530
+ ? `**Decision**: ${assessment}`
531
+ : 'Recommit to the desired outcome or redirect.'),
532
+ };
533
+ if (phase === 'full') {
534
+ phaseGuidance.full = Object.values(phaseGuidance).join('\n\n---\n\n');
535
+ }
536
+ const guidance = phaseGuidance[phase] || phaseGuidance.full || phaseGuidance.acknowledge;
537
+ let evaluationStored = false;
538
+ let beatEmitted = false;
539
+ // Store evaluation observations
540
+ if (assessment && updateReality) {
541
+ const evalObservation = `[MMOT ${phase}${directionLabel}] ${assessment}`;
542
+ if (currentReality) {
543
+ currentReality.observations.push(evalObservation);
544
+ if (currentReality.metadata) {
545
+ currentReality.metadata.updatedAt = timestamp;
546
+ }
547
+ }
548
+ if (!chartEntity.metadata.mmotEvaluations) {
549
+ chartEntity.metadata.mmotEvaluations = [];
550
+ }
551
+ chartEntity.metadata.mmotEvaluations.push({
552
+ phase: phase,
553
+ assessment,
554
+ direction,
555
+ timestamp,
556
+ });
557
+ chartEntity.metadata.updatedAt = timestamp;
558
+ evaluationStored = true;
559
+ }
560
+ // Add corrective action steps
561
+ if (correctiveActions && correctiveActions.length > 0) {
562
+ const existingActionCount = actionSteps.length;
563
+ correctiveActions.forEach((action, index) => {
564
+ const actionName = `${chartId}_action_${existingActionCount + index + 1}`;
565
+ graph.entities.push({
566
+ name: actionName,
567
+ entityType: 'action_step',
568
+ observations: [action],
569
+ metadata: {
570
+ chartId,
571
+ completionStatus: false,
572
+ createdAt: timestamp,
573
+ updatedAt: timestamp,
574
+ },
575
+ });
576
+ graph.relations.push({
577
+ from: actionName,
578
+ to: `${chartId}_desired_outcome`,
579
+ relationType: 'advances_toward',
580
+ metadata: { createdAt: timestamp },
581
+ });
582
+ });
583
+ }
584
+ // Persist when there's something meaningful
585
+ const shouldSave = evaluationStored || (correctiveActions && correctiveActions.length > 0);
586
+ if (shouldSave) {
587
+ const beatName = `${chartId}_mmot_${Date.now()}`;
588
+ const mmotBeat = {
589
+ name: beatName,
590
+ entityType: 'narrative_beat',
591
+ observations: [
592
+ `MMOT evaluation: ${phase}${directionLabel}`,
593
+ ...(assessment ? [`Assessment: ${assessment}`] : []),
594
+ ],
595
+ metadata: {
596
+ chartId,
597
+ type_dramatic: 'mmot_evaluation',
598
+ timestamp,
599
+ fourDirections: direction
600
+ ? {
601
+ north_vision: direction === 'North' ? assessment || null : null,
602
+ east_intention: direction === 'East' ? assessment || null : null,
603
+ south_emotion: direction === 'South' ? assessment || null : null,
604
+ west_introspection: direction === 'West' ? assessment || null : null,
605
+ }
606
+ : undefined,
607
+ },
608
+ };
609
+ graph.entities.push(mmotBeat);
610
+ graph.relations.push({
611
+ from: beatName,
612
+ to: `${chartId}_chart`,
613
+ relationType: 'evaluates',
614
+ metadata: { createdAt: timestamp },
615
+ });
616
+ beatEmitted = true;
617
+ await this.saveGraph(graph);
618
+ }
619
+ return { guidance, evaluationStored, beatEmitted };
620
+ }
621
+ // ─── Narrative Beats ────────────────────────────────────────────────
622
+ async createNarrativeBeat(parentChartId, title, act, type_dramatic, universes, description, prose, lessons, assessRelationalAlignment = false, initiateFourDirectionsInquiry = false, _filePath) {
623
+ const timestamp = Date.now();
624
+ const beatName = `${parentChartId}_beat_${timestamp}`;
625
+ const entity = {
626
+ name: beatName,
627
+ entityType: 'narrative_beat',
628
+ observations: [
629
+ `Act ${act} ${type_dramatic}`,
630
+ `Timestamp: ${new Date().toISOString()}`,
631
+ `Universe: ${universes.join(', ')}`,
632
+ ],
633
+ metadata: {
634
+ chartId: parentChartId,
635
+ act,
636
+ type_dramatic,
637
+ universes,
638
+ timestamp: new Date().toISOString(),
639
+ createdAt: new Date().toISOString(),
640
+ narrative: {
641
+ description,
642
+ prose,
643
+ lessons,
644
+ },
645
+ relationalAlignment: {
646
+ assessed: false,
647
+ score: null,
648
+ principles: [],
649
+ },
650
+ fourDirections: {
651
+ north_vision: null,
652
+ east_intention: null,
653
+ south_emotion: null,
654
+ west_introspection: null,
655
+ },
656
+ },
657
+ };
658
+ await this.createEntities([entity]);
659
+ // Create relation to parent chart if it exists
660
+ const graph = await this.loadGraph();
661
+ const parentChart = graph.entities.find(e => e.entityType === 'structural_tension_chart' &&
662
+ e.metadata?.chartId === parentChartId);
663
+ if (parentChart) {
664
+ await this.createRelations([
665
+ {
666
+ from: beatName,
667
+ to: `${parentChartId}_chart`,
668
+ relationType: 'documents',
669
+ metadata: {
670
+ createdAt: new Date().toISOString(),
671
+ description: 'Narrative beat documents chart progress',
672
+ },
673
+ },
674
+ ]);
675
+ }
676
+ if (assessRelationalAlignment) {
677
+ console.log('🔮 Relational alignment assessment requested (iaip-mcp integration pending)');
678
+ }
679
+ if (initiateFourDirectionsInquiry) {
680
+ console.log('🧭 Four Directions inquiry requested (iaip-mcp integration pending)');
681
+ }
682
+ return { entity, beatName };
683
+ }
684
+ async telescopeNarrativeBeat(parentBeatName, newCurrentReality, initialSubBeats) {
685
+ const graph = await this.loadGraph();
686
+ const parentBeat = graph.entities.find(e => e.name === parentBeatName && e.entityType === 'narrative_beat');
687
+ if (!parentBeat) {
688
+ throw new Error(`Parent narrative beat not found: ${parentBeatName}`);
689
+ }
690
+ parentBeat.observations.push(`Telescoped: ${newCurrentReality}`);
691
+ if (parentBeat.metadata) {
692
+ parentBeat.metadata.updatedAt = new Date().toISOString();
693
+ }
694
+ const subBeats = [];
695
+ if (initialSubBeats && initialSubBeats.length > 0) {
696
+ for (let i = 0; i < initialSubBeats.length; i++) {
697
+ const subBeat = initialSubBeats[i];
698
+ const result = await this.createNarrativeBeat(parentBeatName, subBeat.title, i + 1, subBeat.type_dramatic, parentBeat.metadata?.universes || ['engineer-world'], subBeat.description, subBeat.prose, subBeat.lessons);
699
+ subBeats.push(result.entity);
700
+ }
701
+ }
702
+ await this.saveGraph(graph);
703
+ return { parentBeat, subBeats };
704
+ }
705
+ async listNarrativeBeats(parentChartId) {
706
+ const graph = await this.loadGraph();
707
+ const beats = graph.entities.filter(e => e.entityType === 'narrative_beat');
708
+ if (parentChartId) {
709
+ return beats.filter(beat => beat.metadata?.chartId === parentChartId);
710
+ }
711
+ return beats;
712
+ }
713
+ // ─── Add Action Step (telescoped chart) ─────────────────────────────
714
+ async addActionStep(parentChartId, actionStepTitle, dueDate, currentReality, performanceElements) {
715
+ const graph = await this.loadGraph();
716
+ const parentChart = graph.entities.find(e => e.entityType === 'structural_tension_chart' &&
717
+ e.metadata?.chartId === parentChartId);
718
+ if (!parentChart) {
719
+ throw new Error(`Parent chart ${parentChartId} not found`);
720
+ }
721
+ const parentDueDate = parentChart.metadata?.dueDate;
722
+ if (!parentDueDate) {
723
+ throw new Error(`Parent chart ${parentChartId} has no due date`);
724
+ }
725
+ let actionStepDueDate = dueDate;
726
+ if (!actionStepDueDate) {
727
+ const now = new Date();
728
+ const parentEnd = new Date(parentDueDate);
729
+ const midpoint = new Date(now.getTime() + (parentEnd.getTime() - now.getTime()) / 2);
730
+ actionStepDueDate = midpoint.toISOString();
731
+ }
732
+ if (!currentReality) {
733
+ throw new Error(`🌊 DELAYED RESOLUTION PRINCIPLE VIOLATION\n\n` +
734
+ `Action step: "${actionStepTitle}"\n\n` +
735
+ `❌ **Problem**: Current reality assessment missing\n` +
736
+ `📚 **Principle**: "Tolerate discrepancy, tension, and delayed resolution" - Robert Fritz\n\n` +
737
+ `🎯 **What's Needed**: Honest assessment of your actual current state relative to this action step.\n\n` +
738
+ `✅ **Examples**:\n` +
739
+ `- "Never used Django, completed Python basics"\n` +
740
+ `- "Built one API, struggling with authentication"\n` +
741
+ `- "Read 3 chapters, concepts still unclear"\n\n` +
742
+ `❌ **Avoid**: "Ready to begin", "Prepared to start", "All set to..."\n\n` +
743
+ `**Why This Matters**: Premature resolution destroys the structural tension that generates creative advancement. The system NEEDS honest current reality to create productive tension.\n\n` +
744
+ `💡 **Tip**: Run 'init_llm_guidance' for complete methodology overview.`);
745
+ }
746
+ const actionCurrentReality = currentReality;
747
+ // Create telescoped structural tension chart
748
+ const telescopedChart = await this.createStructuralTensionChart(actionStepTitle, actionCurrentReality, actionStepDueDate, undefined, performanceElements);
749
+ // Load once, apply all mutations, save once
750
+ const updatedGraph = await this.loadGraph();
751
+ const timestamp = new Date().toISOString();
752
+ const telescopedChartEntity = updatedGraph.entities.find(e => e.name === `${telescopedChart.chartId}_chart`);
753
+ if (telescopedChartEntity && telescopedChartEntity.metadata) {
754
+ telescopedChartEntity.metadata.parentChart = parentChartId;
755
+ telescopedChartEntity.metadata.level =
756
+ (parentChart.metadata?.level || 0) + 1;
757
+ telescopedChartEntity.metadata.updatedAt = timestamp;
758
+ }
759
+ const parentDesiredOutcome = updatedGraph.entities.find(e => e.name === `${parentChartId}_desired_outcome` &&
760
+ e.entityType === 'desired_outcome');
761
+ if (parentDesiredOutcome) {
762
+ updatedGraph.relations.push({
763
+ from: `${telescopedChart.chartId}_desired_outcome`,
764
+ to: parentDesiredOutcome.name,
765
+ relationType: 'advances_toward',
766
+ metadata: { createdAt: timestamp },
767
+ });
768
+ }
769
+ await this.saveGraph(updatedGraph);
770
+ return {
771
+ chartId: telescopedChart.chartId,
772
+ actionStepName: `${telescopedChart.chartId}_desired_outcome`,
773
+ };
774
+ }
775
+ // ─── Manage Action Step (unified interface) ─────────────────────────
776
+ async manageActionStep(parentReference, actionDescription, currentReality, initialActionSteps, dueDate, performanceElements) {
777
+ const graph = await this.loadGraph();
778
+ const actionStepPattern = /^chart_\d+_action_\d+$/;
779
+ const desiredOutcomePattern = /^chart_\d+_desired_outcome$/;
780
+ const chartIdPattern = /^chart_\d+$/;
781
+ const isActionStepEntity = actionStepPattern.test(parentReference);
782
+ const isDesiredOutcomeEntity = desiredOutcomePattern.test(parentReference);
783
+ const isChartId = chartIdPattern.test(parentReference);
784
+ // Route 1: Expanding existing action_step entity (legacy pattern)
785
+ if (isActionStepEntity) {
786
+ const actionStep = graph.entities.find(e => e.name === parentReference && e.entityType === 'action_step');
787
+ if (!actionStep) {
788
+ const allActionSteps = graph.entities
789
+ .filter(e => e.entityType === 'action_step')
790
+ .map(e => `- ${e.name}: "${e.observations[0]}"`);
791
+ throw new Error(`🔍 ACTION STEP ENTITY NOT FOUND\n\n` +
792
+ `Received: "${parentReference}"\n` +
793
+ `Expected: Valid action_step entity name (e.g., "chart_123_action_1")\n\n` +
794
+ `Available action steps in memory:\n` +
795
+ `${allActionSteps.length > 0 ? allActionSteps.join('\n') : '(none found)'}\n\n` +
796
+ `Tip: If creating a new action step, use the parent chart ID instead.`);
797
+ }
798
+ const currentRealityToUse = currentReality || 'Expanding action step into detailed sub-chart';
799
+ const telescopedResult = await this.telescopeActionStep(parentReference, currentRealityToUse, initialActionSteps);
800
+ return {
801
+ chartId: telescopedResult.chartId,
802
+ actionStepName: `${telescopedResult.chartId}_desired_outcome`,
803
+ };
804
+ }
805
+ // Route 2: Expanding existing desired_outcome entity (modern pattern)
806
+ if (isDesiredOutcomeEntity) {
807
+ const desiredOutcome = graph.entities.find(e => e.name === parentReference && e.entityType === 'desired_outcome');
808
+ if (!desiredOutcome || !desiredOutcome.metadata?.chartId) {
809
+ throw new Error(`🔍 DESIRED OUTCOME ENTITY NOT FOUND\n\n` +
810
+ `Received: "${parentReference}"\n` +
811
+ `Expected: Valid desired_outcome entity name (e.g., "chart_123_desired_outcome")\n\n` +
812
+ `Tip: If creating a new action step, use the parent chart ID instead.`);
813
+ }
814
+ const currentRealityToUse = currentReality || 'Expanding desired outcome into detailed sub-chart';
815
+ const telescopedResult = await this.telescopeActionStep(parentReference, currentRealityToUse, initialActionSteps);
816
+ return {
817
+ chartId: telescopedResult.chartId,
818
+ actionStepName: `${telescopedResult.chartId}_desired_outcome`,
819
+ };
820
+ }
821
+ // Route 3: Creating new action step under parent chart
822
+ if (isChartId) {
823
+ const parentChart = graph.entities.find(e => e.entityType === 'structural_tension_chart' &&
824
+ e.metadata?.chartId === parentReference);
825
+ if (!parentChart) {
826
+ const allCharts = graph.entities
827
+ .filter(e => e.entityType === 'structural_tension_chart')
828
+ .map(e => {
829
+ const outcome = graph.entities.find(o => o.name === `${e.metadata?.chartId}_desired_outcome`);
830
+ return `- ${e.metadata?.chartId}: "${outcome?.observations[0] || 'Unknown'}"`;
831
+ });
832
+ throw new Error(`🔍 PARENT CHART NOT FOUND\n\n` +
833
+ `Received: "${parentReference}"\n` +
834
+ `Expected: Valid chart ID (e.g., "chart_123")\n\n` +
835
+ `Available charts in memory:\n` +
836
+ `${allCharts.length > 0 ? allCharts.join('\n') : '(none found)'}\n\n` +
837
+ `Tip: Use 'list_active_charts' to see all available charts.`);
838
+ }
839
+ if (!currentReality) {
840
+ throw new Error(`🌊 DELAYED RESOLUTION PRINCIPLE VIOLATION\n\n` +
841
+ `Action step: "${actionDescription}"\n` +
842
+ `Parent chart: "${parentReference}"\n\n` +
843
+ `❌ **Problem**: Current reality assessment missing\n` +
844
+ `📚 **Principle**: "Tolerate discrepancy, tension, and delayed resolution" - Robert Fritz\n\n` +
845
+ `🎯 **What's Needed**: Honest assessment of actual current state relative to this action step.\n\n` +
846
+ `✅ **Examples**:\n` +
847
+ `- "Never used Django, completed Python basics"\n` +
848
+ `- "Built one API, struggling with authentication"\n` +
849
+ `- "Read 3 chapters, concepts still unclear"\n\n` +
850
+ `❌ **Avoid**: "Ready to begin", "Prepared to start", "All set to..."\n\n` +
851
+ `**Why This Matters**: Premature resolution destroys structural tension essential for creative advancement.\n\n` +
852
+ `💡 **Tip**: Run 'init_llm_guidance' for complete methodology overview.`);
853
+ }
854
+ return await this.addActionStep(parentReference, actionDescription, dueDate, currentReality, performanceElements);
855
+ }
856
+ // Route 4: Invalid format
857
+ throw new Error(`🚨 INVALID PARENT REFERENCE FORMAT\n\n` +
858
+ `Received: "${parentReference}"\n\n` +
859
+ `Valid formats:\n` +
860
+ `1. Chart ID: "chart_123" → Creates new action step\n` +
861
+ `2. Action entity: "chart_123_action_1" → Expands existing legacy action step\n` +
862
+ `3. Desired outcome: "chart_123_desired_outcome" → Expands existing modern action step\n\n` +
863
+ `Examples:\n` +
864
+ `- Create new action: manageActionStep("chart_123", "Complete tutorial", "Never used Django")\n` +
865
+ `- Expand existing: manageActionStep("chart_123_action_1", "Complete tutorial", undefined, ["Step 1", "Step 2"])\n\n` +
866
+ `💡 **Tip**: Use 'list_active_charts' to see available charts and their IDs.`);
867
+ }
868
+ // ─── Remove Action Step ─────────────────────────────────────────────
869
+ async removeActionStep(parentChartId, actionStepName) {
870
+ const graph = await this.loadGraph();
871
+ const actionStepEntity = graph.entities.find(e => e.name === actionStepName);
872
+ if (!actionStepEntity || !actionStepEntity.metadata?.chartId) {
873
+ throw new Error(`Action step ${actionStepName} not found`);
874
+ }
875
+ const telescopedChartId = actionStepEntity.metadata.chartId;
876
+ // Verify it belongs to the parent chart
877
+ const telescopedChart = graph.entities.find(e => e.entityType === 'structural_tension_chart' &&
878
+ e.metadata?.chartId === telescopedChartId &&
879
+ e.metadata?.parentChart === parentChartId);
880
+ if (!telescopedChart) {
881
+ throw new Error(`Action step ${actionStepName} does not belong to chart ${parentChartId}`);
882
+ }
883
+ // Remove all entities belonging to the telescoped chart
884
+ const entitiesToRemove = graph.entities
885
+ .filter(e => e.metadata?.chartId === telescopedChartId)
886
+ .map(e => e.name);
887
+ await this.deleteEntities(entitiesToRemove);
888
+ }
889
+ // ─── Private Helpers ────────────────────────────────────────────────
890
+ extractCurrentRealityFromContext(userInput, _actionStepTitle) {
891
+ const realityPatterns = [
892
+ /(?:currently|right now|at present|today)\s+(.{10,})/i,
893
+ /(?:i am|we are|the situation is)\s+(.{10,})/i,
894
+ /(?:i have|we have|there is|there are)\s+(.{10,})/i,
895
+ /(?:my current|our current|the current)\s+(.{10,})/i,
896
+ ];
897
+ for (const pattern of realityPatterns) {
898
+ const match = userInput.match(pattern);
899
+ if (match && match[1]) {
900
+ return match[1].trim();
901
+ }
902
+ }
903
+ return null;
904
+ }
905
+ distributeActionStepDates(startDate, endDate, stepCount) {
906
+ const totalTime = endDate.getTime() - startDate.getTime();
907
+ const stepInterval = totalTime / (stepCount + 1);
908
+ const dates = [];
909
+ for (let i = 1; i <= stepCount; i++) {
910
+ dates.push(new Date(startDate.getTime() + stepInterval * i));
911
+ }
912
+ return dates;
913
+ }
914
+ }
915
+ //# sourceMappingURL=graph-manager.js.map