coaiajs 0.2.1 → 0.3.1

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 (172) hide show
  1. package/KINSHIP.md +1 -1
  2. package/README.md +191 -75
  3. package/dist/mcp/config.d.ts.map +1 -0
  4. package/dist/mcp/config.js +0 -2
  5. package/dist/mcp/config.js.map +1 -0
  6. package/dist/mcp/prompts.d.ts.map +1 -0
  7. package/dist/mcp/prompts.js.map +1 -0
  8. package/dist/mcp/resources.d.ts.map +1 -0
  9. package/dist/mcp/resources.js.map +1 -0
  10. package/dist/mcp/server.d.ts.map +1 -0
  11. package/dist/mcp/server.js +3 -2
  12. package/dist/mcp/server.js.map +1 -0
  13. package/dist/mcp/tools/coaiapy-tools.d.ts.map +1 -0
  14. package/dist/mcp/tools/coaiapy-tools.js.map +1 -0
  15. package/dist/mcp/tools/index.d.ts.map +1 -0
  16. package/dist/mcp/tools/index.js.map +1 -0
  17. package/dist/src/audio.d.ts.map +1 -0
  18. package/dist/src/audio.js.map +1 -0
  19. package/dist/src/cli-helpers.d.ts.map +1 -0
  20. package/dist/src/cli-helpers.js.map +1 -0
  21. package/dist/src/cli.d.ts.map +1 -0
  22. package/dist/src/cli.js +2 -1
  23. package/dist/src/cli.js.map +1 -0
  24. package/dist/src/config.d.ts.map +1 -0
  25. package/dist/src/config.js.map +1 -0
  26. package/dist/src/environment.d.ts.map +1 -0
  27. package/dist/src/environment.js.map +1 -0
  28. package/dist/src/github.d.ts.map +1 -0
  29. package/dist/src/github.js.map +1 -0
  30. package/dist/src/index.d.ts +1 -0
  31. package/dist/src/index.d.ts.map +1 -0
  32. package/dist/src/index.js +1 -0
  33. package/dist/src/index.js.map +1 -0
  34. package/dist/src/langfuse/client.d.ts.map +1 -0
  35. package/dist/src/langfuse/client.js.map +1 -0
  36. package/dist/src/langfuse/comments.d.ts.map +1 -0
  37. package/dist/src/langfuse/comments.js.map +1 -0
  38. package/dist/src/langfuse/datasets.d.ts.map +1 -0
  39. package/dist/src/langfuse/datasets.js.map +1 -0
  40. package/dist/src/langfuse/index.d.ts.map +1 -0
  41. package/dist/src/langfuse/index.js.map +1 -0
  42. package/dist/src/langfuse/media.d.ts.map +1 -0
  43. package/dist/src/langfuse/media.js.map +1 -0
  44. package/dist/src/langfuse/observations.d.ts.map +1 -0
  45. package/dist/src/langfuse/observations.js.map +1 -0
  46. package/dist/src/langfuse/prompts.d.ts.map +1 -0
  47. package/dist/src/langfuse/prompts.js.map +1 -0
  48. package/dist/src/langfuse/scores.d.ts.map +1 -0
  49. package/dist/src/langfuse/scores.js.map +1 -0
  50. package/dist/src/langfuse/traces.d.ts.map +1 -0
  51. package/dist/src/langfuse/traces.js.map +1 -0
  52. package/dist/src/llm.d.ts.map +1 -0
  53. package/dist/src/llm.js.map +1 -0
  54. package/dist/src/narrative/graph-manager.d.ts.map +1 -0
  55. package/dist/src/narrative/graph-manager.js.map +1 -0
  56. package/dist/src/narrative/index.d.ts.map +1 -0
  57. package/dist/src/narrative/index.js.map +1 -0
  58. package/dist/src/narrative/markdown-export.d.ts.map +1 -0
  59. package/dist/src/narrative/markdown-export.js.map +1 -0
  60. package/dist/src/narrative/tool-definitions.d.ts.map +1 -0
  61. package/dist/src/narrative/tool-definitions.js.map +1 -0
  62. package/dist/src/narrative/tool-handlers.d.ts.map +1 -0
  63. package/dist/src/narrative/tool-handlers.js.map +1 -0
  64. package/dist/src/narrative/types.d.ts.map +1 -0
  65. package/dist/src/narrative/types.js.map +1 -0
  66. package/dist/src/narrative/validation.d.ts.map +1 -0
  67. package/dist/src/narrative/validation.js.map +1 -0
  68. package/dist/src/pde/index.d.ts.map +1 -0
  69. package/dist/src/pde/index.js.map +1 -0
  70. package/dist/src/pde/mcp-handlers.d.ts.map +1 -0
  71. package/dist/src/pde/mcp-handlers.js.map +1 -0
  72. package/dist/src/pde/mcp-tools.d.ts.map +1 -0
  73. package/dist/src/pde/mcp-tools.js.map +1 -0
  74. package/dist/src/pde/session-manager.d.ts.map +1 -0
  75. package/dist/src/pde/session-manager.js.map +1 -0
  76. package/dist/src/pde/stc-mapper.d.ts.map +1 -0
  77. package/dist/src/pde/stc-mapper.js.map +1 -0
  78. package/dist/src/pipeline/index.d.ts.map +1 -0
  79. package/dist/src/pipeline/index.js.map +1 -0
  80. package/dist/src/pipeline/template-engine.d.ts.map +1 -0
  81. package/dist/src/pipeline/template-engine.js.map +1 -0
  82. package/dist/src/planning/index.d.ts.map +1 -0
  83. package/dist/src/planning/index.js.map +1 -0
  84. package/dist/src/planning/mcp-handlers.d.ts.map +1 -0
  85. package/dist/src/planning/mcp-handlers.js.map +1 -0
  86. package/dist/src/planning/mcp-tools.d.ts.map +1 -0
  87. package/dist/src/planning/mcp-tools.js.map +1 -0
  88. package/dist/src/planning/plan-parser.d.ts.map +1 -0
  89. package/dist/src/planning/plan-parser.js.map +1 -0
  90. package/dist/src/redis.d.ts.map +1 -0
  91. package/dist/src/redis.js.map +1 -0
  92. package/dist/src/types.d.ts.map +1 -0
  93. package/dist/src/types.js.map +1 -0
  94. package/dist/src/version.d.ts +3 -0
  95. package/dist/src/version.d.ts.map +1 -0
  96. package/dist/src/version.js +33 -0
  97. package/dist/src/version.js.map +1 -0
  98. package/llms-full.txt +361 -0
  99. package/llms.txt +43 -0
  100. package/package.json +79 -12
  101. package/.claude/settings.local.json +0 -16
  102. package/articles/academic/NOTES.md +0 -1
  103. package/articles/academic/README.md +0 -1
  104. package/articles/academic/creative-orientation-vs-problem-solving.md +0 -177
  105. package/articles/academic/jsonl-knowledge-graphs-agent-memory.md +0 -142
  106. package/articles/academic/langfuse-observability-llm-pipelines.md +0 -144
  107. package/articles/academic/medicine-wheel-software-architecture.md +0 -163
  108. package/articles/academic/mmot-autonomous-agents.md +0 -156
  109. package/articles/academic/model-context-protocol-interagent.md +0 -161
  110. package/articles/academic/pde-prompt-decomposition.md +0 -186
  111. package/articles/academic/structural-tension-in-ai-agents.md +0 -134
  112. package/articles/reviews/mcp-protocol-design-review.md +0 -170
  113. package/articles/reviews/observability-ai-systems-review.md +0 -176
  114. package/articles/reviews/prompt-engineering-decomposition-review.md +0 -184
  115. package/articles/surveys/agent-orchestration-survey.md +0 -186
  116. package/articles/surveys/knowledge-graph-storage-survey.md +0 -204
  117. package/articles/surveys/structural-tension-methodology-survey.md +0 -154
  118. package/articles/technical/aws-sdk-v3-polly.md +0 -270
  119. package/articles/technical/commander-cli-framework.md +0 -262
  120. package/articles/technical/dotenv-config-patterns.md +0 -360
  121. package/articles/technical/ioredis-vs-redis.md +0 -142
  122. package/articles/technical/langfuse-js-sdk-vs-rest.md +0 -191
  123. package/articles/technical/mcp-sdk-typescript.md +0 -291
  124. package/articles/technical/octokit-github-api.md +0 -293
  125. package/articles/technical/openai-sdk-modern.md +0 -231
  126. package/articles/technical/yaml-parsing-node.md +0 -266
  127. package/articles/technical/zod-runtime-validation.md +0 -212
  128. package/mcp/config.ts +0 -225
  129. package/mcp/prompts.ts +0 -131
  130. package/mcp/resources.ts +0 -84
  131. package/mcp/server.ts +0 -518
  132. package/mcp/tools/coaiapy-tools.ts +0 -366
  133. package/mcp/tools/index.ts +0 -4
  134. package/src/audio.ts +0 -76
  135. package/src/cli-helpers.ts +0 -86
  136. package/src/cli.ts +0 -1260
  137. package/src/config.ts +0 -207
  138. package/src/environment.ts +0 -171
  139. package/src/github.ts +0 -143
  140. package/src/index.ts +0 -82
  141. package/src/langfuse/client.ts +0 -105
  142. package/src/langfuse/comments.ts +0 -52
  143. package/src/langfuse/datasets.ts +0 -178
  144. package/src/langfuse/index.ts +0 -37
  145. package/src/langfuse/media.ts +0 -193
  146. package/src/langfuse/observations.ts +0 -155
  147. package/src/langfuse/prompts.ts +0 -157
  148. package/src/langfuse/scores.ts +0 -456
  149. package/src/langfuse/traces.ts +0 -353
  150. package/src/llm.ts +0 -106
  151. package/src/narrative/graph-manager.ts +0 -1358
  152. package/src/narrative/index.ts +0 -188
  153. package/src/narrative/markdown-export.ts +0 -535
  154. package/src/narrative/tool-definitions.ts +0 -635
  155. package/src/narrative/tool-handlers.ts +0 -528
  156. package/src/narrative/types.ts +0 -9
  157. package/src/narrative/validation.ts +0 -179
  158. package/src/pde/index.ts +0 -34
  159. package/src/pde/mcp-handlers.ts +0 -359
  160. package/src/pde/mcp-tools.ts +0 -201
  161. package/src/pde/session-manager.ts +0 -248
  162. package/src/pde/stc-mapper.ts +0 -298
  163. package/src/pipeline/index.ts +0 -7
  164. package/src/pipeline/template-engine.ts +0 -398
  165. package/src/planning/index.ts +0 -32
  166. package/src/planning/mcp-handlers.ts +0 -369
  167. package/src/planning/mcp-tools.ts +0 -155
  168. package/src/planning/plan-parser.ts +0 -587
  169. package/src/redis.ts +0 -111
  170. package/src/types.ts +0 -281
  171. package/test/config.test.mjs +0 -93
  172. package/tsconfig.json +0 -26
@@ -1,535 +0,0 @@
1
- /**
2
- * Markdown Export Module for COAIA Narrative
3
- *
4
- * Provides markdown generation for structural tension charts,
5
- * narrative beats, and associated data structures.
6
- */
7
-
8
- import { promises as fs } from 'fs';
9
- import path from 'path';
10
- import type { Entity, KnowledgeGraph } from '../types.js';
11
- import type { KnowledgeGraphManager } from './graph-manager.js';
12
-
13
- export interface MarkdownOptions {
14
- includeMetadata?: boolean;
15
- includeObservations?: boolean;
16
- observationLimit?: number;
17
- includeToc?: boolean;
18
- outputPath?: string;
19
- }
20
-
21
- // ─── Utility Functions ────────────────────────────────────────────────
22
-
23
- function escapeMarkdown(text: string): string {
24
- return text
25
- .replace(/\\/g, '\\\\')
26
- .replace(/\*/g, '\\*')
27
- .replace(/\[/g, '\\[')
28
- .replace(/\]/g, '\\]')
29
- .replace(/\(/g, '\\(')
30
- .replace(/\)/g, '\\)');
31
- }
32
-
33
- function formatDateForMarkdown(dateStr?: string): string {
34
- if (!dateStr) return 'No due date';
35
- const date = new Date(dateStr);
36
- const now = new Date();
37
- const days = Math.ceil((date.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
38
-
39
- if (days < 0) return `Overdue by ${Math.abs(days)} days`;
40
- if (days === 0) return 'Due today';
41
- if (days === 1) return 'Due tomorrow';
42
- if (days <= 7) return `Due in ${days} days`;
43
- return `${date.toLocaleDateString()}`;
44
- }
45
-
46
- function formatProgressBar(progress: number): string {
47
- const width = 20;
48
- const filled = Math.round(progress * width);
49
- const empty = width - filled;
50
- const bar = '█'.repeat(filled) + '░'.repeat(empty);
51
- const percent = Math.round(progress * 100);
52
- return `[${bar}] ${percent}%`;
53
- }
54
-
55
- function getStatusIcon(completed: boolean): string {
56
- return completed ? '✅' : '⏳';
57
- }
58
-
59
- function slugify(text: string): string {
60
- return text
61
- .toLowerCase()
62
- .replace(/[^\w\s-]/g, '')
63
- .replace(/\s+/g, '-')
64
- .replace(/-+/g, '-');
65
- }
66
-
67
- // ─── Single Chart Export ──────────────────────────────────────────────
68
-
69
- export async function exportChartToMarkdown(
70
- chartId: string,
71
- manager: KnowledgeGraphManager,
72
- options: MarkdownOptions = {},
73
- ): Promise<string> {
74
- const graph = await manager.readGraph();
75
- const {
76
- includeMetadata = true,
77
- includeObservations = true,
78
- observationLimit = 0,
79
- } = options;
80
-
81
- const chart = graph.entities.find(
82
- e =>
83
- e.entityType === 'structural_tension_chart' &&
84
- e.metadata?.chartId === chartId,
85
- );
86
-
87
- if (!chart) {
88
- return `# Error\n\nChart '${chartId}' not found.`;
89
- }
90
-
91
- let md = '';
92
-
93
- md += `# Chart: ${chartId}\n\n`;
94
-
95
- if (includeMetadata) {
96
- if (chart.metadata?.createdAt) {
97
- const created = new Date(chart.metadata.createdAt).toLocaleString();
98
- md += `> **Created**: ${created}\n`;
99
- }
100
- if (chart.metadata?.parentChart) {
101
- md += `> **Parent Chart**: ${chart.metadata.parentChart} (Level ${chart.metadata.level})\n`;
102
- } else {
103
- md += `> **Master Chart** (Level ${chart.metadata?.level || 0})\n`;
104
- }
105
- if (chart.metadata?.dueDate) {
106
- md += `> **Due**: ${formatDateForMarkdown(chart.metadata.dueDate)}\n`;
107
- }
108
- md += '\n';
109
- }
110
-
111
- // Desired Outcome
112
- const outcome = graph.entities.find(
113
- e =>
114
- e.name === `${chartId}_desired_outcome` &&
115
- e.entityType === 'desired_outcome',
116
- );
117
- md += '## Desired Outcome\n\n';
118
- if (outcome) {
119
- md += `${escapeMarkdown(outcome.observations[0])}\n\n`;
120
- } else {
121
- md += '*(Unknown)*\n\n';
122
- }
123
-
124
- // Current Reality
125
- const currentReality = graph.entities.find(
126
- e =>
127
- e.name === `${chartId}_current_reality` &&
128
- e.entityType === 'current_reality',
129
- );
130
- md += '## Current Reality\n\n';
131
- if (currentReality && currentReality.observations.length > 0) {
132
- if (includeObservations && observationLimit > 0) {
133
- const obs = currentReality.observations.slice(-observationLimit);
134
- obs.forEach(o => (md += `- ${escapeMarkdown(o)}\n`));
135
- } else if (includeObservations) {
136
- currentReality.observations.forEach(o => (md += `- ${escapeMarkdown(o)}\n`));
137
- } else {
138
- md += `- ${escapeMarkdown(currentReality.observations[currentReality.observations.length - 1])}\n`;
139
- }
140
- md += '\n';
141
- } else {
142
- md += '*(Not assessed)*\n\n';
143
- }
144
-
145
- // Progress & Structural Tension
146
- const actionSteps = graph.entities.filter(
147
- e => e.entityType === 'action_step' && e.metadata?.chartId === chartId,
148
- );
149
- const completed = actionSteps.filter(
150
- a => a.metadata?.completionStatus === true,
151
- ).length;
152
- const total = actionSteps.length;
153
- const progress = total > 0 ? completed / total : 0;
154
-
155
- md += '## Structural Tension\n\n';
156
- md += `${formatProgressBar(progress)}\n\n`;
157
- md += `- **Completed**: ${completed}/${total} action steps\n\n`;
158
-
159
- // Action Steps
160
- if (actionSteps.length > 0) {
161
- md += '## Action Steps\n\n';
162
- actionSteps.forEach((step, idx) => {
163
- const isComplete = step.metadata?.completionStatus === true;
164
- const status = getStatusIcon(isComplete);
165
- const stepId = (step.metadata?.chartId as string) || `step_${idx + 1}`;
166
-
167
- md += `### ${status} ${escapeMarkdown(step.observations[0])}\n\n`;
168
- md += `- **ID**: ${stepId}\n`;
169
- md += `- **Status**: ${isComplete ? 'Completed' : 'In Progress'}\n`;
170
- if (step.metadata?.dueDate) {
171
- md += `- **Due**: ${formatDateForMarkdown(step.metadata.dueDate)}\n`;
172
- }
173
-
174
- if (step.observations.length > 1 && includeObservations) {
175
- md += `- **Notes**:\n`;
176
- step.observations.slice(1).forEach(note => {
177
- md += ` - ${escapeMarkdown(note)}\n`;
178
- });
179
- }
180
- md += '\n';
181
- });
182
- }
183
-
184
- // Narrative Beats
185
- const narrativeBeats = graph.entities
186
- .filter(
187
- e =>
188
- e.entityType === 'narrative_beat' && e.metadata?.chartId === chartId,
189
- )
190
- .sort((a, b) => ((a.metadata?.act as number) || 0) - ((b.metadata?.act as number) || 0));
191
-
192
- if (narrativeBeats.length > 0) {
193
- md += '## Narrative Beats\n\n';
194
- narrativeBeats.forEach(beat => {
195
- const act = beat.metadata?.act || '?';
196
- const type = beat.metadata?.type_dramatic || 'Unknown';
197
- const universes = (beat.metadata?.universes as string[]) || [];
198
-
199
- md += `### Act ${act}: ${escapeMarkdown(type as string)}\n\n`;
200
-
201
- if (universes.length > 0) {
202
- md += `- **Universes**: ${universes.join(', ')}\n`;
203
- }
204
- if (beat.metadata?.timestamp) {
205
- const ts = new Date(beat.metadata.timestamp).toLocaleString();
206
- md += `- **Timestamp**: ${ts}\n`;
207
- }
208
-
209
- if (beat.metadata?.narrative?.description) {
210
- md += `\n**Description**:\n\n${escapeMarkdown(beat.metadata.narrative.description)}\n`;
211
- }
212
-
213
- if (beat.metadata?.narrative?.prose) {
214
- md += `\n**Prose**:\n\n${escapeMarkdown(beat.metadata.narrative.prose)}\n`;
215
- }
216
-
217
- if (
218
- beat.metadata?.narrative?.lessons &&
219
- beat.metadata.narrative.lessons.length > 0
220
- ) {
221
- md += `\n**Lessons**:\n\n`;
222
- beat.metadata.narrative.lessons.forEach(lesson => {
223
- md += `- ${escapeMarkdown(lesson)}\n`;
224
- });
225
- }
226
-
227
- const dirs = beat.metadata?.fourDirections;
228
- if (
229
- dirs &&
230
- (dirs.north_vision ||
231
- dirs.east_intention ||
232
- dirs.south_emotion ||
233
- dirs.west_introspection)
234
- ) {
235
- md += `\n**Four Directions**:\n\n`;
236
- if (dirs.north_vision) md += `- **North (Vision)**: ${escapeMarkdown(dirs.north_vision)}\n`;
237
- if (dirs.east_intention) md += `- **East (Intention)**: ${escapeMarkdown(dirs.east_intention)}\n`;
238
- if (dirs.south_emotion) md += `- **South (Emotion)**: ${escapeMarkdown(dirs.south_emotion)}\n`;
239
- if (dirs.west_introspection) md += `- **West (Introspection)**: ${escapeMarkdown(dirs.west_introspection)}\n`;
240
- }
241
-
242
- md += '\n';
243
- });
244
- }
245
-
246
- return md;
247
- }
248
-
249
- // ─── All Charts Export ────────────────────────────────────────────────
250
-
251
- export async function exportAllCharts(
252
- manager: KnowledgeGraphManager,
253
- options: MarkdownOptions = {},
254
- ): Promise<string> {
255
- const graph = await manager.readGraph();
256
- const { includeToc = true } = options;
257
-
258
- const charts = graph.entities.filter(
259
- e => e.entityType === 'structural_tension_chart',
260
- );
261
- const masterCharts = charts.filter(c => c.metadata?.level === 0);
262
-
263
- let md = '# Structural Tension Charts\n\n';
264
-
265
- if (includeToc && masterCharts.length > 0) {
266
- md += '## Table of Contents\n\n';
267
- masterCharts.forEach(master => {
268
- const cId = (master.metadata?.chartId as string) || master.name;
269
- const slug = slugify(cId);
270
- md += `- [${cId}](#${slug})\n`;
271
- });
272
- md += '\n---\n\n';
273
- }
274
-
275
- masterCharts.forEach((master, masterIdx) => {
276
- const cId = (master.metadata?.chartId as string) || master.name;
277
-
278
- md += `## ${cId}\n\n`;
279
-
280
- const outcome = graph.entities.find(
281
- e =>
282
- e.name === `${cId}_desired_outcome` &&
283
- e.entityType === 'desired_outcome',
284
- );
285
- md += `**Desired Outcome**: ${outcome?.observations[0] || 'Unknown'}\n\n`;
286
-
287
- const cr = graph.entities.find(
288
- e =>
289
- e.name === `${cId}_current_reality` &&
290
- e.entityType === 'current_reality',
291
- );
292
- if (cr && cr.observations.length > 0) {
293
- md += `**Current Reality**: ${cr.observations[cr.observations.length - 1]}\n\n`;
294
- }
295
-
296
- const actionSteps = graph.entities.filter(
297
- e => e.entityType === 'action_step' && e.metadata?.chartId === cId,
298
- );
299
- const completed = actionSteps.filter(
300
- a => a.metadata?.completionStatus === true,
301
- ).length;
302
- const total = actionSteps.length;
303
- const progress = total > 0 ? completed / total : 0;
304
-
305
- md += `**Progress**: ${formatProgressBar(progress)} (${completed}/${total})\n\n`;
306
-
307
- if (master.metadata?.dueDate) {
308
- md += `**Due**: ${formatDateForMarkdown(master.metadata.dueDate)}\n\n`;
309
- }
310
-
311
- const actionCharts = charts.filter(
312
- c => c.metadata?.parentChart === cId && c.metadata?.level === 1,
313
- );
314
-
315
- if (actionCharts.length > 0) {
316
- md += '### Action Steps\n\n';
317
- actionCharts.forEach(actionChart => {
318
- const actionChartId = actionChart.metadata?.chartId as string;
319
- const actionOutcome = graph.entities.find(
320
- e =>
321
- e.name === `${actionChartId}_desired_outcome` &&
322
- e.entityType === 'desired_outcome',
323
- );
324
- const actionActions = graph.entities.filter(
325
- e =>
326
- e.entityType === 'action_step' &&
327
- e.metadata?.chartId === actionChartId,
328
- );
329
-
330
- const actionCompleted = actionActions.filter(
331
- a => a.metadata?.completionStatus === true,
332
- ).length;
333
- const actionTotal = actionActions.length;
334
- const actionProgress =
335
- actionTotal > 0 ? actionCompleted / actionTotal : 0;
336
- const isComplete = actionChart.metadata?.completionStatus === true;
337
- const status = isComplete ? '✅' : actionProgress > 0 ? '🔄' : '⏳';
338
-
339
- md += `- ${status} **${escapeMarkdown(actionOutcome?.observations[0] || 'Unknown')}**\n`;
340
- md += ` - ID: ${actionChartId}\n`;
341
- if (actionChart.metadata?.dueDate) {
342
- md += ` - Due: ${formatDateForMarkdown(actionChart.metadata.dueDate)}\n`;
343
- }
344
- if (actionTotal > 0) {
345
- md += ` - Progress: ${formatProgressBar(actionProgress)}\n`;
346
- }
347
- });
348
- md += '\n';
349
- }
350
-
351
- if (masterIdx < masterCharts.length - 1) {
352
- md += '---\n\n';
353
- }
354
- });
355
-
356
- return md;
357
- }
358
-
359
- // ─── Progress Report ──────────────────────────────────────────────────
360
-
361
- export async function exportChartProgress(
362
- chartId: string,
363
- manager: KnowledgeGraphManager,
364
- ): Promise<string> {
365
- const graph = await manager.readGraph();
366
-
367
- const chart = graph.entities.find(
368
- e =>
369
- e.entityType === 'structural_tension_chart' &&
370
- e.metadata?.chartId === chartId,
371
- );
372
-
373
- if (!chart) {
374
- return `# Error\n\nChart '${chartId}' not found.`;
375
- }
376
-
377
- const outcome = graph.entities.find(
378
- e => e.name === `${chartId}_desired_outcome`,
379
- );
380
- const actions = graph.entities.filter(
381
- e => e.entityType === 'action_step' && e.metadata?.chartId === chartId,
382
- );
383
-
384
- const completed = actions.filter(
385
- a => a.metadata?.completionStatus === true,
386
- );
387
- const incomplete = actions.filter(
388
- a => a.metadata?.completionStatus !== true,
389
- );
390
- const progress = actions.length > 0 ? completed.length / actions.length : 0;
391
-
392
- let md = `# Progress Report: ${chartId}\n\n`;
393
-
394
- md += `**Goal**: ${outcome?.observations[0] || 'Unknown'}\n\n`;
395
-
396
- md += `## Overall Progress\n\n`;
397
- md += `${formatProgressBar(progress)}\n\n`;
398
-
399
- md += '## Completed Actions\n\n';
400
- if (completed.length > 0) {
401
- completed.forEach((action, idx) => {
402
- md += `${idx + 1}. ${escapeMarkdown(action.observations[0])}\n`;
403
- if (action.metadata?.dueDate) {
404
- md += ` - Completed: ${formatDateForMarkdown(action.metadata.dueDate)}\n`;
405
- }
406
- });
407
- } else {
408
- md += '*No completed actions yet.*\n';
409
- }
410
- md += '\n';
411
-
412
- md += '## Remaining Actions\n\n';
413
- if (incomplete.length > 0) {
414
- incomplete.forEach((action, idx) => {
415
- md += `${idx + 1}. ${escapeMarkdown(action.observations[0])}\n`;
416
- if (action.metadata?.dueDate) {
417
- md += ` - Due: ${formatDateForMarkdown(action.metadata.dueDate)}\n`;
418
- }
419
- });
420
- } else {
421
- md += '*All actions completed!*\n';
422
- }
423
- md += '\n';
424
-
425
- const currentReality = graph.entities.find(
426
- e => e.name === `${chartId}_current_reality`,
427
- );
428
- if (currentReality && currentReality.observations.length > 0) {
429
- md += '## Current Reality Notes\n\n';
430
- currentReality.observations.slice(-5).forEach(obs => {
431
- md += `- ${escapeMarkdown(obs)}\n`;
432
- });
433
- }
434
-
435
- return md;
436
- }
437
-
438
- // ─── Statistics ───────────────────────────────────────────────────────
439
-
440
- export async function exportChartStats(
441
- manager: KnowledgeGraphManager,
442
- ): Promise<string> {
443
- const graph = await manager.readGraph();
444
-
445
- const charts = graph.entities.filter(
446
- e => e.entityType === 'structural_tension_chart',
447
- );
448
- const masterCharts = charts.filter(c => c.metadata?.level === 0);
449
- const actionCharts = charts.filter(c => c.metadata?.level === 1);
450
-
451
- const allActions = graph.entities.filter(
452
- e => e.entityType === 'action_step',
453
- );
454
- const completedActions = allActions.filter(
455
- a => a.metadata?.completionStatus === true,
456
- );
457
-
458
- const narrativeBeats = graph.entities.filter(
459
- e => e.entityType === 'narrative_beat',
460
- );
461
-
462
- const overdueCharts = charts.filter(chart => {
463
- if (!chart.metadata?.dueDate) return false;
464
- const dueDate = new Date(chart.metadata.dueDate);
465
- return dueDate < new Date();
466
- });
467
-
468
- let md = '# Structural Tension Charts Statistics\n\n';
469
-
470
- md += '## Overview\n\n';
471
- md += `| Metric | Count |\n`;
472
- md += `|--------|-------|\n`;
473
- md += `| Master Charts | ${masterCharts.length} |\n`;
474
- md += `| Action Step Charts | ${actionCharts.length} |\n`;
475
- md += `| Total Charts | ${charts.length} |\n`;
476
- md += `| Narrative Beats | ${narrativeBeats.length} |\n`;
477
- md += '\n';
478
-
479
- md += '## Completion Status\n\n';
480
- md += `| Status | Count |\n`;
481
- md += `|--------|-------|\n`;
482
- md += `| Completed Actions | ${completedActions.length}/${allActions.length} |\n`;
483
- const overallProgress =
484
- allActions.length > 0
485
- ? Math.round((completedActions.length / allActions.length) * 100)
486
- : 0;
487
- md += `| Overall Progress | ${overallProgress}% |\n`;
488
- md += '\n';
489
-
490
- if (overdueCharts.length > 0) {
491
- md += '## ⚠️ Overdue Charts\n\n';
492
- overdueCharts.forEach((chart, idx) => {
493
- const chartId = (chart.metadata?.chartId as string) || chart.name;
494
- md += `${idx + 1}. **${chartId}** - Due: ${formatDateForMarkdown(chart.metadata?.dueDate)}\n`;
495
- });
496
- } else {
497
- md += '## ✅ Status\n\n';
498
- md += 'All charts are on track!\n';
499
- }
500
- md += '\n';
501
-
502
- return md;
503
- }
504
-
505
- // ─── File Output ──────────────────────────────────────────────────────
506
-
507
- export async function writeMarkdownToFile(
508
- content: string,
509
- outputPath: string,
510
- ): Promise<void> {
511
- const dir = path.dirname(outputPath);
512
- try {
513
- await fs.mkdir(dir, { recursive: true });
514
- } catch (_e) {
515
- // Directory may exist
516
- }
517
- await fs.writeFile(outputPath, content, 'utf-8');
518
- }
519
-
520
- export function getDefaultFilename(exportType: string, chartId?: string): string {
521
- const timestamp = new Date().toISOString().split('T')[0];
522
-
523
- switch (exportType) {
524
- case 'chart':
525
- return `${chartId}-export-${timestamp}.md`;
526
- case 'list':
527
- return `structural-tension-charts-${timestamp}.md`;
528
- case 'progress':
529
- return `${chartId}-progress-${timestamp}.md`;
530
- case 'stats':
531
- return `statistics-${timestamp}.md`;
532
- default:
533
- return `export-${timestamp}.md`;
534
- }
535
- }