coaiajs 0.3.0 → 0.3.2

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 (179) 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 +1 -1
  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 +1 -0
  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 +1 -0
  41. package/dist/src/langfuse/index.d.ts.map +1 -0
  42. package/dist/src/langfuse/index.js.map +1 -0
  43. package/dist/src/langfuse/media.d.ts.map +1 -0
  44. package/dist/src/langfuse/media.js.map +1 -0
  45. package/dist/src/langfuse/observations.d.ts.map +1 -0
  46. package/dist/src/langfuse/observations.js.map +1 -0
  47. package/dist/src/langfuse/prompts.d.ts +5 -1
  48. package/dist/src/langfuse/prompts.d.ts.map +1 -0
  49. package/dist/src/langfuse/prompts.js +16 -3
  50. package/dist/src/langfuse/prompts.js.map +1 -0
  51. package/dist/src/langfuse/scores.d.ts.map +1 -0
  52. package/dist/src/langfuse/scores.js.map +1 -0
  53. package/dist/src/langfuse/traces.d.ts.map +1 -0
  54. package/dist/src/langfuse/traces.js.map +1 -0
  55. package/dist/src/llm.d.ts.map +1 -0
  56. package/dist/src/llm.js.map +1 -0
  57. package/dist/src/narrative/graph-manager.d.ts.map +1 -0
  58. package/dist/src/narrative/graph-manager.js.map +1 -0
  59. package/dist/src/narrative/index.d.ts.map +1 -0
  60. package/dist/src/narrative/index.js.map +1 -0
  61. package/dist/src/narrative/markdown-export.d.ts.map +1 -0
  62. package/dist/src/narrative/markdown-export.js.map +1 -0
  63. package/dist/src/narrative/tool-definitions.d.ts.map +1 -0
  64. package/dist/src/narrative/tool-definitions.js.map +1 -0
  65. package/dist/src/narrative/tool-handlers.d.ts.map +1 -0
  66. package/dist/src/narrative/tool-handlers.js.map +1 -0
  67. package/dist/src/narrative/types.d.ts.map +1 -0
  68. package/dist/src/narrative/types.js.map +1 -0
  69. package/dist/src/narrative/validation.d.ts.map +1 -0
  70. package/dist/src/narrative/validation.js.map +1 -0
  71. package/dist/src/pde/index.d.ts.map +1 -0
  72. package/dist/src/pde/index.js.map +1 -0
  73. package/dist/src/pde/mcp-handlers.d.ts.map +1 -0
  74. package/dist/src/pde/mcp-handlers.js.map +1 -0
  75. package/dist/src/pde/mcp-tools.d.ts.map +1 -0
  76. package/dist/src/pde/mcp-tools.js.map +1 -0
  77. package/dist/src/pde/session-manager.d.ts.map +1 -0
  78. package/dist/src/pde/session-manager.js.map +1 -0
  79. package/dist/src/pde/stc-mapper.d.ts.map +1 -0
  80. package/dist/src/pde/stc-mapper.js.map +1 -0
  81. package/dist/src/pipeline/index.d.ts.map +1 -0
  82. package/dist/src/pipeline/index.js.map +1 -0
  83. package/dist/src/pipeline/template-engine.d.ts.map +1 -0
  84. package/dist/src/pipeline/template-engine.js.map +1 -0
  85. package/dist/src/planning/index.d.ts.map +1 -0
  86. package/dist/src/planning/index.js.map +1 -0
  87. package/dist/src/planning/mcp-handlers.d.ts.map +1 -0
  88. package/dist/src/planning/mcp-handlers.js.map +1 -0
  89. package/dist/src/planning/mcp-tools.d.ts.map +1 -0
  90. package/dist/src/planning/mcp-tools.js.map +1 -0
  91. package/dist/src/planning/plan-parser.d.ts.map +1 -0
  92. package/dist/src/planning/plan-parser.js.map +1 -0
  93. package/dist/src/redis.d.ts.map +1 -0
  94. package/dist/src/redis.js.map +1 -0
  95. package/dist/src/types.d.ts.map +1 -0
  96. package/dist/src/types.js.map +1 -0
  97. package/dist/src/version.d.ts.map +1 -0
  98. package/dist/src/version.js.map +1 -0
  99. package/llms-full.txt +361 -0
  100. package/llms.txt +43 -0
  101. package/package.json +79 -12
  102. package/.claude/settings.local.json +0 -17
  103. package/.claude-plugin/marketplace.json +0 -26
  104. package/articles/academic/NOTES.md +0 -1
  105. package/articles/academic/README.md +0 -1
  106. package/articles/academic/creative-orientation-vs-problem-solving.md +0 -177
  107. package/articles/academic/jsonl-knowledge-graphs-agent-memory.md +0 -142
  108. package/articles/academic/langfuse-observability-llm-pipelines.md +0 -144
  109. package/articles/academic/medicine-wheel-software-architecture.md +0 -163
  110. package/articles/academic/mmot-autonomous-agents.md +0 -156
  111. package/articles/academic/model-context-protocol-interagent.md +0 -161
  112. package/articles/academic/pde-prompt-decomposition.md +0 -186
  113. package/articles/academic/structural-tension-in-ai-agents.md +0 -134
  114. package/articles/reviews/mcp-protocol-design-review.md +0 -170
  115. package/articles/reviews/observability-ai-systems-review.md +0 -176
  116. package/articles/reviews/prompt-engineering-decomposition-review.md +0 -184
  117. package/articles/surveys/agent-orchestration-survey.md +0 -186
  118. package/articles/surveys/knowledge-graph-storage-survey.md +0 -204
  119. package/articles/surveys/structural-tension-methodology-survey.md +0 -154
  120. package/articles/technical/aws-sdk-v3-polly.md +0 -270
  121. package/articles/technical/commander-cli-framework.md +0 -262
  122. package/articles/technical/dotenv-config-patterns.md +0 -360
  123. package/articles/technical/ioredis-vs-redis.md +0 -142
  124. package/articles/technical/langfuse-js-sdk-vs-rest.md +0 -191
  125. package/articles/technical/mcp-sdk-typescript.md +0 -291
  126. package/articles/technical/octokit-github-api.md +0 -293
  127. package/articles/technical/openai-sdk-modern.md +0 -231
  128. package/articles/technical/yaml-parsing-node.md +0 -266
  129. package/articles/technical/zod-runtime-validation.md +0 -212
  130. package/coaiajs-langfuse-claude-plugin/.claude-plugin/marketplace.json +0 -16
  131. package/coaiajs-langfuse-claude-plugin/.claude-plugin/plugin.json +0 -10
  132. package/coaiajs-langfuse-claude-plugin/.mcp.json +0 -8
  133. package/coaiajs-langfuse-claude-plugin/README.md +0 -60
  134. package/mcp/config.ts +0 -225
  135. package/mcp/prompts.ts +0 -131
  136. package/mcp/resources.ts +0 -84
  137. package/mcp/server.ts +0 -519
  138. package/mcp/tools/coaiapy-tools.ts +0 -366
  139. package/mcp/tools/index.ts +0 -4
  140. package/src/audio.ts +0 -76
  141. package/src/cli-helpers.ts +0 -86
  142. package/src/cli.ts +0 -1261
  143. package/src/config.ts +0 -207
  144. package/src/environment.ts +0 -171
  145. package/src/github.ts +0 -143
  146. package/src/index.ts +0 -82
  147. package/src/langfuse/client.ts +0 -105
  148. package/src/langfuse/comments.ts +0 -52
  149. package/src/langfuse/datasets.ts +0 -178
  150. package/src/langfuse/index.ts +0 -37
  151. package/src/langfuse/media.ts +0 -193
  152. package/src/langfuse/observations.ts +0 -155
  153. package/src/langfuse/prompts.ts +0 -157
  154. package/src/langfuse/scores.ts +0 -456
  155. package/src/langfuse/traces.ts +0 -353
  156. package/src/llm.ts +0 -106
  157. package/src/narrative/graph-manager.ts +0 -1358
  158. package/src/narrative/index.ts +0 -188
  159. package/src/narrative/markdown-export.ts +0 -535
  160. package/src/narrative/tool-definitions.ts +0 -635
  161. package/src/narrative/tool-handlers.ts +0 -528
  162. package/src/narrative/types.ts +0 -9
  163. package/src/narrative/validation.ts +0 -179
  164. package/src/pde/index.ts +0 -34
  165. package/src/pde/mcp-handlers.ts +0 -359
  166. package/src/pde/mcp-tools.ts +0 -201
  167. package/src/pde/session-manager.ts +0 -248
  168. package/src/pde/stc-mapper.ts +0 -298
  169. package/src/pipeline/index.ts +0 -7
  170. package/src/pipeline/template-engine.ts +0 -398
  171. package/src/planning/index.ts +0 -32
  172. package/src/planning/mcp-handlers.ts +0 -369
  173. package/src/planning/mcp-tools.ts +0 -155
  174. package/src/planning/plan-parser.ts +0 -587
  175. package/src/redis.ts +0 -111
  176. package/src/types.ts +0 -281
  177. package/src/version.ts +0 -39
  178. package/test/config.test.mjs +0 -93
  179. package/tsconfig.json +0 -26
@@ -1,587 +0,0 @@
1
- /**
2
- * Plan Parser — Transforms markdown plans into structural tension charts
3
- * Ported from coaia-planning/src/plan-parser.ts
4
- */
5
-
6
- import { promises as fs } from 'fs';
7
- import path from 'path';
8
- import type {
9
- Entity,
10
- Relation,
11
- StructuralElement,
12
- StructuralTensionPlan,
13
- DecompositionResult,
14
- } from '../types.js';
15
-
16
- // ═══════════════════════════════════════════════════════════════════════════
17
- // PATTERN RECOGNITION
18
- // ═══════════════════════════════════════════════════════════════════════════
19
-
20
- const DESIRED_OUTCOME_PATTERNS: RegExp[] = [
21
- // Explicit markers
22
- /^(?:##?\s*)?(?:desired\s+outcome|goal|objective|end\s+result|vision|target):\s*(.+)/im,
23
- /\*\*(?:desired\s+outcome|goal|objective)\*\*:\s*(.+)/im,
24
- // Creative orientation language
25
- /(?:we\s+want\s+to\s+create|aim\s+to\s+manifest|intend\s+to\s+bring\s+into\s+being)\s+(.+)/i,
26
- /(?:the\s+end\s+result\s+is|what\s+we're\s+creating\s+is)\s+(.+)/i,
27
- // State of being descriptions
28
- /(?:when\s+complete|upon\s+completion)[,:]?\s*(.+)/i,
29
- ];
30
-
31
- const CURRENT_REALITY_PATTERNS: RegExp[] = [
32
- // Explicit markers
33
- /^(?:##?\s*)?(?:current\s+reality|current\s+state|where\s+we\s+are|starting\s+point):\s*(.+)/im,
34
- /\*\*(?:current\s+reality|current\s+state)\*\*:\s*(.+)/im,
35
- // Factual assessment language
36
- /(?:currently|at\s+present|as\s+of\s+now)[,:]?\s*(.+)/i,
37
- /(?:the\s+current\s+situation\s+is|we\s+currently\s+have)\s+(.+)/i,
38
- ];
39
-
40
- const ACTION_STEP_PATTERNS: RegExp[] = [
41
- // Phase markers (these telescope)
42
- /^(?:##?\s*)?phase\s+(\d+)[:\s]+(.+)/im,
43
- /^(?:##?\s*)?step\s+(\d+)[:\s]+(.+)/im,
44
- // Numbered items
45
- /^(\d+)\.\s+(.+)$/gm,
46
- // Checklist items
47
- /^-\s*\[([ x])\]\s+(.+)$/gm,
48
- // Action-oriented subsections
49
- /^###?\s+(.+)$/gm,
50
- ];
51
-
52
- // ═══════════════════════════════════════════════════════════════════════════
53
- // PARSING FUNCTIONS
54
- // ═══════════════════════════════════════════════════════════════════════════
55
-
56
- /**
57
- * Parse a plan file as a structural tension chart
58
- */
59
- export async function parsePlan(planPath: string): Promise<StructuralTensionPlan> {
60
- const content = await fs.readFile(planPath, 'utf-8');
61
- return parsePlanContent(content, planPath);
62
- }
63
-
64
- /**
65
- * Parse plan content directly
66
- */
67
- export function parsePlanContent(
68
- content: string,
69
- filePath: string = 'inline',
70
- telescopeLevel: number = 0
71
- ): StructuralTensionPlan {
72
- const lines = content.split('\n');
73
-
74
- const titleMatch = content.match(/^#\s+(.+)$/m);
75
- const title = titleMatch ? titleMatch[1] : path.basename(filePath, '.md');
76
-
77
- const desiredOutcome = extractDesiredOutcome(content, lines);
78
- const currentReality = extractCurrentReality(content, lines);
79
- const actionSteps = extractActionSteps(content, lines);
80
- const observations = extractObservations(content, lines, desiredOutcome, currentReality, actionSteps);
81
-
82
- return {
83
- title,
84
- filePath,
85
- desiredOutcome,
86
- currentReality,
87
- actionSteps,
88
- observations,
89
- metadata: {
90
- parsedAt: new Date().toISOString(),
91
- telescopeLevel,
92
- completionStatus: 'pending',
93
- },
94
- };
95
- }
96
-
97
- /**
98
- * Convert structural tension plan to Entity[]/Relation[] (JSONL-compatible)
99
- */
100
- export function planToSTC(
101
- plan: StructuralTensionPlan,
102
- chartIdPrefix: string = 'plan'
103
- ): { entities: Entity[]; relations: Relation[] } {
104
- const chartId = `${chartIdPrefix}_${sanitizeName(plan.title)}`;
105
- const entities: Entity[] = [];
106
- const relations: Relation[] = [];
107
- const now = new Date().toISOString();
108
-
109
- // Chart entity
110
- entities.push({
111
- name: `${chartId}_chart`,
112
- entityType: 'structural_tension_chart',
113
- observations: [`Parsed from: ${plan.filePath}`],
114
- metadata: {
115
- chartId,
116
- level: plan.metadata.telescopeLevel,
117
- createdAt: now,
118
- updatedAt: now,
119
- dueDate: plan.metadata.dueDate,
120
- },
121
- });
122
-
123
- // Desired outcome
124
- if (plan.desiredOutcome) {
125
- const doName = `${chartId}_desired_outcome`;
126
- entities.push({
127
- name: doName,
128
- entityType: 'desired_outcome',
129
- observations: [plan.desiredOutcome.content],
130
- metadata: {
131
- chartId,
132
- confidence: plan.desiredOutcome.confidence,
133
- createdAt: now,
134
- },
135
- });
136
- relations.push({
137
- from: `${chartId}_chart`,
138
- to: doName,
139
- relationType: 'contains',
140
- });
141
- }
142
-
143
- // Current reality
144
- if (plan.currentReality) {
145
- const crName = `${chartId}_current_reality`;
146
- entities.push({
147
- name: crName,
148
- entityType: 'current_reality',
149
- observations: [plan.currentReality.content],
150
- metadata: {
151
- chartId,
152
- confidence: plan.currentReality.confidence,
153
- createdAt: now,
154
- },
155
- });
156
- relations.push({
157
- from: `${chartId}_chart`,
158
- to: crName,
159
- relationType: 'contains',
160
- });
161
-
162
- // Structural tension relation
163
- if (plan.desiredOutcome) {
164
- relations.push({
165
- from: crName,
166
- to: `${chartId}_desired_outcome`,
167
- relationType: 'creates_tension_with',
168
- });
169
- }
170
- }
171
-
172
- // Action steps (each is a potential telescoped STC)
173
- plan.actionSteps.forEach((step, index) => {
174
- const actionName = `${chartId}_action_${index + 1}`;
175
- entities.push({
176
- name: actionName,
177
- entityType: 'action_step',
178
- observations: [step.content],
179
- metadata: {
180
- chartId,
181
- order: index + 1,
182
- completionStatus: false,
183
- confidence: step.confidence,
184
- createdAt: now,
185
- },
186
- });
187
-
188
- relations.push({
189
- from: `${chartId}_chart`,
190
- to: actionName,
191
- relationType: 'contains',
192
- });
193
-
194
- if (plan.desiredOutcome) {
195
- relations.push({
196
- from: actionName,
197
- to: `${chartId}_desired_outcome`,
198
- relationType: 'advances_toward',
199
- });
200
- }
201
-
202
- // If action telescopes, recursively convert
203
- if (step.telescopesInto) {
204
- const nestedSTC = planToSTC(step.telescopesInto, actionName);
205
- entities.push(...nestedSTC.entities);
206
- relations.push(...nestedSTC.relations);
207
-
208
- relations.push({
209
- from: actionName,
210
- to: `${actionName}_chart`,
211
- relationType: 'telescopes_into',
212
- });
213
- }
214
- });
215
-
216
- return { entities, relations };
217
- }
218
-
219
- /**
220
- * Export Entity[]/Relation[] to JSONL format
221
- */
222
- export function exportToJSONL(stc: { entities: Entity[]; relations: Relation[] }): string {
223
- const lines: string[] = [];
224
-
225
- for (const entity of stc.entities) {
226
- lines.push(JSON.stringify({ type: 'entity', ...entity }));
227
- }
228
-
229
- for (const relation of stc.relations) {
230
- lines.push(JSON.stringify({ type: 'relation', ...relation }));
231
- }
232
-
233
- return lines.join('\n');
234
- }
235
-
236
- /**
237
- * PDE bridge: Convert DecompositionResult into Entity[]/Relation[]
238
- */
239
- export function decompositionResultToPlan(
240
- decomposition: DecompositionResult,
241
- originalPrompt?: string
242
- ): { entities: Entity[]; relations: Relation[] } {
243
- const chartId = `pde_${Date.now()}`;
244
- const entities: Entity[] = [];
245
- const relations: Relation[] = [];
246
- const now = new Date().toISOString();
247
-
248
- // Collect direction observations for chart entity
249
- const directionObservations: string[] = [];
250
- for (const [dir, items] of Object.entries(decomposition.directions)) {
251
- for (const item of items) {
252
- directionObservations.push(`[${dir.toUpperCase()}] ${item.text}`);
253
- }
254
- }
255
-
256
- // Chart entity
257
- entities.push({
258
- name: `${chartId}_chart`,
259
- entityType: 'structural_tension_chart',
260
- observations: [
261
- `PDE decomposition of: ${originalPrompt || `${decomposition.primary.action} ${decomposition.primary.target}`}`,
262
- `Primary confidence: ${decomposition.primary.confidence}`,
263
- `Urgency: ${decomposition.primary.urgency}`,
264
- ...directionObservations,
265
- ],
266
- metadata: {
267
- chartId,
268
- level: 0,
269
- createdAt: now,
270
- updatedAt: now,
271
- },
272
- });
273
-
274
- // Desired outcome from primary intent + expected outputs
275
- const doName = `${chartId}_desired_outcome`;
276
- const doObservations = [
277
- `${decomposition.primary.action}: ${decomposition.primary.target}`,
278
- ...decomposition.outputs.artifacts.map(a => `Artifact: ${a}`),
279
- ...decomposition.outputs.updates.map(u => `Update: ${u}`),
280
- ...decomposition.outputs.communications.map(c => `Communication: ${c}`),
281
- ];
282
- entities.push({
283
- name: doName,
284
- entityType: 'desired_outcome',
285
- observations: doObservations,
286
- metadata: {
287
- chartId,
288
- confidence: decomposition.primary.confidence,
289
- createdAt: now,
290
- },
291
- });
292
- relations.push({
293
- from: `${chartId}_chart`,
294
- to: doName,
295
- relationType: 'contains',
296
- });
297
-
298
- // Current reality from context requirements
299
- const crName = `${chartId}_current_reality`;
300
- const crObservations = [
301
- ...decomposition.context.assumptions,
302
- ...decomposition.context.files_needed.map(f => `File needed: ${f}`),
303
- ...decomposition.context.tools_required.map(t => `Tool required: ${t}`),
304
- ];
305
- if (crObservations.length === 0) {
306
- crObservations.push('No explicit current reality captured from decomposition context');
307
- }
308
- entities.push({
309
- name: crName,
310
- entityType: 'current_reality',
311
- observations: crObservations,
312
- metadata: {
313
- chartId,
314
- createdAt: now,
315
- },
316
- });
317
- relations.push({
318
- from: `${chartId}_chart`,
319
- to: crName,
320
- relationType: 'contains',
321
- });
322
- relations.push({
323
- from: crName,
324
- to: doName,
325
- relationType: 'creates_tension_with',
326
- });
327
-
328
- // Action steps from actionStack
329
- decomposition.actionStack.forEach((action, index) => {
330
- const actionName = `${chartId}_action_${index + 1}`;
331
- entities.push({
332
- name: actionName,
333
- entityType: 'action_step',
334
- observations: [action.text],
335
- metadata: {
336
- chartId,
337
- order: index + 1,
338
- completionStatus: action.completed || false,
339
- direction: action.direction,
340
- createdAt: now,
341
- },
342
- });
343
-
344
- relations.push({
345
- from: `${chartId}_chart`,
346
- to: actionName,
347
- relationType: 'contains',
348
- });
349
- relations.push({
350
- from: actionName,
351
- to: doName,
352
- relationType: 'advances_toward',
353
- });
354
-
355
- // Dependency relations — match by text against other actions
356
- if (action.dependency) {
357
- const depIndex = decomposition.actionStack.findIndex(a => a.text === action.dependency);
358
- if (depIndex >= 0) {
359
- relations.push({
360
- from: actionName,
361
- to: `${chartId}_action_${depIndex + 1}`,
362
- relationType: 'depends_on',
363
- });
364
- }
365
- }
366
- });
367
-
368
- // Secondary intents as observation entities
369
- decomposition.secondary.forEach((intent, index) => {
370
- const secName = `${chartId}_secondary_${index + 1}`;
371
- entities.push({
372
- name: secName,
373
- entityType: 'observation',
374
- observations: [
375
- `${intent.action}: ${intent.target}`,
376
- intent.implicit ? '(implicit intent)' : '(explicit intent)',
377
- ],
378
- metadata: {
379
- chartId,
380
- confidence: intent.confidence,
381
- createdAt: now,
382
- },
383
- });
384
- relations.push({
385
- from: `${chartId}_chart`,
386
- to: secName,
387
- relationType: 'contains',
388
- });
389
- });
390
-
391
- // Ambiguities as observation entities
392
- decomposition.ambiguities.forEach((amb, index) => {
393
- const ambName = `${chartId}_ambiguity_${index + 1}`;
394
- entities.push({
395
- name: ambName,
396
- entityType: 'observation',
397
- observations: [
398
- `Ambiguity: ${amb.text}`,
399
- `Suggestion: ${amb.suggestion}`,
400
- ],
401
- metadata: {
402
- chartId,
403
- createdAt: now,
404
- },
405
- });
406
- relations.push({
407
- from: `${chartId}_chart`,
408
- to: ambName,
409
- relationType: 'contains',
410
- });
411
- });
412
-
413
- return { entities, relations };
414
- }
415
-
416
- // ═══════════════════════════════════════════════════════════════════════════
417
- // INTERNAL HELPERS
418
- // ═══════════════════════════════════════════════════════════════════════════
419
-
420
- function extractDesiredOutcome(content: string, lines: string[]): StructuralElement | null {
421
- for (const pattern of DESIRED_OUTCOME_PATTERNS) {
422
- const match = content.match(pattern);
423
- if (match && match[1]) {
424
- const lineNum = findLineNumber(lines, match[0]);
425
- return {
426
- type: 'desired_outcome',
427
- content: match[1].trim(),
428
- confidence: 0.9,
429
- sourceLines: { start: lineNum, end: lineNum },
430
- };
431
- }
432
- }
433
-
434
- // Fallback: Look for "Desired Outcome" section
435
- const sectionMatch = content.match(/##\s*Desired\s+Outcome\s*\n([\s\S]*?)(?=\n##|\n#|$)/i);
436
- if (sectionMatch) {
437
- const sectionContent = sectionMatch[1].trim();
438
- const firstParagraph = sectionContent.split('\n\n')[0];
439
- const lineNum = findLineNumber(lines, sectionMatch[0]);
440
- return {
441
- type: 'desired_outcome',
442
- content: firstParagraph,
443
- confidence: 0.8,
444
- sourceLines: { start: lineNum, end: lineNum + firstParagraph.split('\n').length },
445
- };
446
- }
447
-
448
- return null;
449
- }
450
-
451
- function extractCurrentReality(content: string, lines: string[]): StructuralElement | null {
452
- for (const pattern of CURRENT_REALITY_PATTERNS) {
453
- const match = content.match(pattern);
454
- if (match && match[1]) {
455
- const lineNum = findLineNumber(lines, match[0]);
456
- return {
457
- type: 'current_reality',
458
- content: match[1].trim(),
459
- confidence: 0.9,
460
- sourceLines: { start: lineNum, end: lineNum },
461
- };
462
- }
463
- }
464
-
465
- // Fallback: Look for "Current Reality" or "Current State" section
466
- const sectionMatch = content.match(/##\s*Current\s+(?:Reality|State)\s*\n([\s\S]*?)(?=\n##|\n#|$)/i);
467
- if (sectionMatch) {
468
- const sectionContent = sectionMatch[1].trim();
469
- const firstParagraph = sectionContent.split('\n\n')[0];
470
- const lineNum = findLineNumber(lines, sectionMatch[0]);
471
- return {
472
- type: 'current_reality',
473
- content: firstParagraph,
474
- confidence: 0.8,
475
- sourceLines: { start: lineNum, end: lineNum + firstParagraph.split('\n').length },
476
- };
477
- }
478
-
479
- return null;
480
- }
481
-
482
- function extractActionSteps(content: string, lines: string[]): StructuralElement[] {
483
- const steps: StructuralElement[] = [];
484
-
485
- // Look for Phase sections (highest priority — these telescope)
486
- const phasePattern = /^##\s*Phase\s+(\d+)[:\s]*(.+)?$/gim;
487
- let phaseMatch;
488
- while ((phaseMatch = phasePattern.exec(content)) !== null) {
489
- const phaseNum = phaseMatch[1];
490
- const phaseTitle = phaseMatch[2]?.trim() || `Phase ${phaseNum}`;
491
- const lineNum = findLineNumber(lines, phaseMatch[0]);
492
-
493
- // Extract phase content for telescoping
494
- const phaseStart = phaseMatch.index + phaseMatch[0].length;
495
- const remainingContent = content.slice(phaseStart);
496
- const nextPhaseMatch = remainingContent.match(/^##\s*(?:Phase\s+\d+|[^#])/m);
497
- const phaseEnd = nextPhaseMatch
498
- ? phaseStart + nextPhaseMatch.index!
499
- : content.length;
500
- const phaseContent = content.slice(phaseStart, phaseEnd).trim();
501
-
502
- const step: StructuralElement = {
503
- type: 'action_step',
504
- content: phaseTitle,
505
- confidence: 1.0,
506
- sourceLines: { start: lineNum, end: lineNum },
507
- };
508
-
509
- // Telescope: parse phase content as nested STC
510
- if (phaseContent.length > 20) {
511
- step.telescopesInto = parsePlanContent(phaseContent, `phase_${phaseNum}`, 1);
512
- }
513
-
514
- steps.push(step);
515
- }
516
-
517
- // If no phases, look for numbered action items
518
- if (steps.length === 0) {
519
- const numberedPattern = /^(\d+)\.\s+(.+)$/gm;
520
- let numMatch;
521
- while ((numMatch = numberedPattern.exec(content)) !== null) {
522
- const lineNum = findLineNumber(lines, numMatch[0]);
523
- steps.push({
524
- type: 'action_step',
525
- content: numMatch[2].trim(),
526
- confidence: 0.7,
527
- sourceLines: { start: lineNum, end: lineNum },
528
- });
529
- }
530
- }
531
-
532
- // Also check for checklist items as action steps
533
- const checklistPattern = /^-\s*\[([ x])\]\s+(.+)$/gm;
534
- let checkMatch;
535
- while ((checkMatch = checklistPattern.exec(content)) !== null) {
536
- const lineNum = findLineNumber(lines, checkMatch[0]);
537
-
538
- // Only add if not already captured
539
- const exists = steps.some(s => s.content === checkMatch![2].trim());
540
- if (!exists) {
541
- steps.push({
542
- type: 'action_step',
543
- content: checkMatch[2].trim(),
544
- confidence: 0.6,
545
- sourceLines: { start: lineNum, end: lineNum },
546
- });
547
- }
548
- }
549
-
550
- return steps;
551
- }
552
-
553
- function extractObservations(
554
- content: string,
555
- _lines: string[],
556
- _desiredOutcome: StructuralElement | null,
557
- _currentReality: StructuralElement | null,
558
- _actionSteps: StructuralElement[]
559
- ): string[] {
560
- const observations: string[] = [];
561
-
562
- const obsPattern = /(?:note|observation|insight):\s*(.+)/gi;
563
- let obsMatch;
564
- while ((obsMatch = obsPattern.exec(content)) !== null) {
565
- observations.push(obsMatch[1].trim());
566
- }
567
-
568
- return observations;
569
- }
570
-
571
- function findLineNumber(lines: string[], searchStr: string): number {
572
- const searchLine = searchStr.split('\n')[0];
573
- for (let i = 0; i < lines.length; i++) {
574
- if (lines[i].includes(searchLine.trim().substring(0, 30))) {
575
- return i + 1;
576
- }
577
- }
578
- return 1;
579
- }
580
-
581
- function sanitizeName(str: string): string {
582
- return str
583
- .toLowerCase()
584
- .replace(/[^a-z0-9]+/g, '_')
585
- .replace(/^_|_$/g, '')
586
- .substring(0, 50);
587
- }
package/src/redis.ts DELETED
@@ -1,111 +0,0 @@
1
- // coaiajs/src/redis.ts — Redis key-value operations
2
- // Parity with coaiapy's tash/fetch pattern
3
-
4
- import IORedis from 'ioredis';
5
- import { getConfig } from './config.js';
6
- import type { CoaiaConfig } from './types.js';
7
-
8
- const Redis = IORedis.default ?? IORedis;
9
- type RedisClient = InstanceType<typeof Redis>;
10
-
11
- let _client: RedisClient | null = null;
12
-
13
- function upstashClient(url: string, token?: string): RedisClient {
14
- const parsed = new URL(url);
15
- const tls = parsed.protocol === 'https:' || parsed.protocol === 'rediss:';
16
- const password = token ?? decodeURIComponent(parsed.password);
17
-
18
- return new Redis({
19
- host: parsed.hostname,
20
- port: parsed.port ? parseInt(parsed.port, 10) : 6379,
21
- username: parsed.username ? decodeURIComponent(parsed.username) : undefined,
22
- password: password || undefined,
23
- lazyConnect: true,
24
- tls: tls ? {} : undefined,
25
- });
26
- }
27
-
28
- function buildClient(cfg: CoaiaConfig): RedisClient {
29
- const r = cfg.redis;
30
-
31
- // Upstash/Vercel REST env vars take priority, matching coaiapy.
32
- if (r?.upstashUrl) {
33
- return upstashClient(r.upstashUrl, r.upstashToken);
34
- }
35
-
36
- // Explicit URL takes priority
37
- if (r?.url) {
38
- return new Redis(r.url, {
39
- lazyConnect: true,
40
- tls: r.url.startsWith('rediss://') ? {} : undefined,
41
- });
42
- }
43
-
44
- // Host / port fallback
45
- return new Redis({
46
- host: r?.host ?? '127.0.0.1',
47
- port: r?.port ?? 6379,
48
- password: r?.password,
49
- lazyConnect: true,
50
- tls: r?.ssl ? {} : undefined,
51
- });
52
- }
53
-
54
- /** Get or create the lazy Redis client. */
55
- export function getClient(): RedisClient {
56
- if (!_client) {
57
- _client = buildClient(getConfig());
58
- }
59
- return _client;
60
- }
61
-
62
- /** Store a key-value pair with optional TTL in minutes, matching coaiapy. */
63
- export async function tash(
64
- key: string,
65
- value: string,
66
- ttl?: number,
67
- ): Promise<void> {
68
- const client = getClient();
69
- if (ttl && ttl > 0) {
70
- await client.set(key, value, 'EX', ttl * 60);
71
- } else {
72
- await client.set(key, value);
73
- }
74
- }
75
-
76
- /** Fetch a value by key. Returns null if not found. */
77
- export async function fetch(key: string): Promise<string | null> {
78
- const client = getClient();
79
- return client.get(key);
80
- }
81
-
82
- /** Delete a key. Returns number of keys removed. */
83
- export async function del(key: string): Promise<number> {
84
- const client = getClient();
85
- return client.del(key);
86
- }
87
-
88
- /** List keys matching a pattern. */
89
- export async function keys(pattern: string): Promise<string[]> {
90
- const client = getClient();
91
- return client.keys(pattern);
92
- }
93
-
94
- /** Check if a key exists. */
95
- export async function exists(key: string): Promise<boolean> {
96
- const client = getClient();
97
- return (await client.exists(key)) === 1;
98
- }
99
-
100
- /** Gracefully disconnect. */
101
- export async function disconnect(): Promise<void> {
102
- if (_client) {
103
- await _client.quit();
104
- _client = null;
105
- }
106
- }
107
-
108
- /** Reset client (testing). */
109
- export function resetClient(): void {
110
- _client = null;
111
- }