coaia-visualizer 1.6.1 → 1.6.3
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.
- package/README.md +1 -1
- package/app/page.tsx +4 -23
- package/components/chart-detail-editable.tsx +3 -0
- package/components/metadata-projections.tsx +208 -0
- package/lib/chart-editor.ts +13 -13
- package/lib/jsonl-parser.ts +55 -8
- package/lib/jsonl-preservation.ts +405 -0
- package/lib/types.ts +30 -0
- package/package.json +31 -1
- package/.dockerignore +0 -9
- package/COMPLETE_IMPLEMENTATION_REPORT.md +0 -215
- package/Dockerfile +0 -61
- package/Dockerfile.app +0 -50
- package/QUICK_START_MCP_TESTING.md +0 -236
- package/STC.md +0 -18
- package/STCGOAL.md +0 -0
- package/STCISSUE.md +0 -36
- package/STCKIN.md +0 -0
- package/STCMASTERY.md +0 -0
- package/STUDY_REPORT.md +0 -510
- package/direct-test.sh +0 -180
- package/docker-build-push.sh +0 -20
- package/docker-compose.test.yml +0 -69
- package/docker-entrypoint.sh +0 -27
- package/jgwill.coaia-visualizer-8--496dca71-d476-4ac9-ba9f-376add118dd8--260208.txt +0 -2612
- package/mcp/test_mcp/.gemini/settings.json +0 -18
- package/rispecs/README.md +0 -170
- package/rispecs/accountability-responsibility.rispec.md +0 -110
- package/rispecs/api-mcp-interface.spec.md +0 -287
- package/rispecs/app.spec.md +0 -364
- package/rispecs/chart-editing-workflow.spec.md +0 -297
- package/rispecs/chart-visualization-hierarchy.spec.md +0 -235
- package/rispecs/cli-mode.spec.md +0 -224
- package/rispecs/github-project-runtime-memory-integration.spec.md +0 -381
- package/rispecs/jsonl-parsing-data-types.spec.md +0 -243
- package/rispecs/narrative-beats-display.spec.md +0 -189
- package/rispecs/pde-integration.spec.md +0 -280
- package/rispecs/planning-integration.spec.md +0 -329
- package/rispecs/relation-graph-visualization.spec.md +0 -171
- package/rispecs/relation-to-mcp-structural-thinking.kin.md +0 -65
- package/rispecs/ui-component-library.spec.md +0 -258
- package/test-data/test-master.jsonl +0 -11
- package/test-scripts/README.md +0 -325
- package/test-scripts/run-all-tests.sh +0 -38
- package/test-scripts/test-01-basic-operations.sh +0 -87
- package/test-scripts/test-02-telescope-creation.sh +0 -91
- package/test-scripts/test-03-navigation.sh +0 -87
- package/test-scripts/test-global-cli.spec.ts +0 -220
- package/test-scripts/verify-global-cli.sh +0 -87
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EntityRecord,
|
|
3
|
+
MetadataWarning,
|
|
4
|
+
ParsedData,
|
|
5
|
+
RawJSONLRecord,
|
|
6
|
+
RecordProjections,
|
|
7
|
+
RelationRecord,
|
|
8
|
+
} from "./types"
|
|
9
|
+
|
|
10
|
+
const UPSTREAM_ISSUE = "https://github.com/avadisabelle/coaia-narrative/issues/35"
|
|
11
|
+
|
|
12
|
+
const ENTITY_TOP_LEVEL_KEYS = new Set(["type", "name", "entityType", "observations", "metadata"])
|
|
13
|
+
const RELATION_TOP_LEVEL_KEYS = new Set(["type", "from", "to", "relationType", "metadata"])
|
|
14
|
+
const NARRATIVE_BEAT_TOP_LEVEL_KEYS = new Set([
|
|
15
|
+
...ENTITY_TOP_LEVEL_KEYS,
|
|
16
|
+
"narrative",
|
|
17
|
+
"relational_alignment",
|
|
18
|
+
"four_directions",
|
|
19
|
+
])
|
|
20
|
+
const MUTABLE_METADATA_KEYS = new Set([
|
|
21
|
+
"dueDate",
|
|
22
|
+
"chartId",
|
|
23
|
+
"phase",
|
|
24
|
+
"completionStatus",
|
|
25
|
+
"completedAt",
|
|
26
|
+
"parentChart",
|
|
27
|
+
"parentActionStep",
|
|
28
|
+
"level",
|
|
29
|
+
"createdAt",
|
|
30
|
+
"updatedAt",
|
|
31
|
+
"act",
|
|
32
|
+
"type_dramatic",
|
|
33
|
+
"universes",
|
|
34
|
+
"timestamp",
|
|
35
|
+
"elementsOfPerformance",
|
|
36
|
+
"mmotEvaluations",
|
|
37
|
+
"relationalAlignment",
|
|
38
|
+
"fourDirections",
|
|
39
|
+
"narrative",
|
|
40
|
+
"isTelescopedChart",
|
|
41
|
+
"telescopedChartId",
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
function isObject(value: unknown): value is Record<string, any> {
|
|
45
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function cloneJson<T>(value: T): T {
|
|
49
|
+
return value === undefined ? value : JSON.parse(JSON.stringify(value))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function deepEqual(left: unknown, right: unknown): boolean {
|
|
53
|
+
return JSON.stringify(left) === JSON.stringify(right)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function removeUndefined<T extends Record<string, any>>(record: T): T {
|
|
57
|
+
for (const key of Object.keys(record)) {
|
|
58
|
+
if (record[key] === undefined) {
|
|
59
|
+
delete record[key]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return record
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function relationKey(relation: Pick<RelationRecord, "from" | "to" | "relationType">): string {
|
|
66
|
+
return `${relation.from}\u0000${relation.to}\u0000${relation.relationType}`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function isEntityLikeRecord(record: RawJSONLRecord): boolean {
|
|
70
|
+
return (record.type === "entity" || record.type === "narrative_beat") && typeof record.name === "string"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function isRelationLikeRecord(record: RawJSONLRecord): boolean {
|
|
74
|
+
return (
|
|
75
|
+
record.type === "relation" &&
|
|
76
|
+
typeof record.from === "string" &&
|
|
77
|
+
typeof record.to === "string" &&
|
|
78
|
+
typeof record.relationType === "string"
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function normalizeJsonlRecord(record: RawJSONLRecord): EntityRecord | RelationRecord | null {
|
|
83
|
+
if (record.type === "entity" && typeof record.name === "string") {
|
|
84
|
+
return {
|
|
85
|
+
...record,
|
|
86
|
+
type: "entity",
|
|
87
|
+
observations: Array.isArray(record.observations) ? record.observations : [],
|
|
88
|
+
metadata: isObject(record.metadata) ? record.metadata : {},
|
|
89
|
+
} as EntityRecord
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (record.type === "narrative_beat" && typeof record.name === "string") {
|
|
93
|
+
const metadata = {
|
|
94
|
+
...(isObject(record.metadata) ? record.metadata : {}),
|
|
95
|
+
narrative: isObject(record.metadata) && record.metadata.narrative !== undefined
|
|
96
|
+
? record.metadata.narrative
|
|
97
|
+
: record.narrative,
|
|
98
|
+
relationalAlignment: isObject(record.metadata) && record.metadata.relationalAlignment !== undefined
|
|
99
|
+
? record.metadata.relationalAlignment
|
|
100
|
+
: record.relational_alignment,
|
|
101
|
+
fourDirections: isObject(record.metadata) && record.metadata.fourDirections !== undefined
|
|
102
|
+
? record.metadata.fourDirections
|
|
103
|
+
: record.four_directions,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return removeUndefined({
|
|
107
|
+
...record,
|
|
108
|
+
type: "entity",
|
|
109
|
+
name: record.name as string,
|
|
110
|
+
entityType: "narrative_beat",
|
|
111
|
+
observations: Array.isArray(record.observations) ? record.observations : [],
|
|
112
|
+
metadata: removeUndefined(metadata),
|
|
113
|
+
}) as EntityRecord
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (isRelationLikeRecord(record)) {
|
|
117
|
+
return {
|
|
118
|
+
...record,
|
|
119
|
+
type: "relation",
|
|
120
|
+
metadata: isObject(record.metadata) ? record.metadata : {},
|
|
121
|
+
} as RelationRecord
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function mergePreservedMetadata(originalMetadata: unknown, currentMetadata: unknown): Record<string, any> {
|
|
128
|
+
const merged = {
|
|
129
|
+
...(isObject(currentMetadata) ? currentMetadata : {}),
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (isObject(originalMetadata)) {
|
|
133
|
+
for (const [key, value] of Object.entries(originalMetadata)) {
|
|
134
|
+
if (!(key in merged) && (!MUTABLE_METADATA_KEYS.has(key) || key === "github")) {
|
|
135
|
+
merged[key] = cloneJson(value)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return merged
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function serializeEntity(entity: EntityRecord, original?: RawJSONLRecord): RawJSONLRecord {
|
|
144
|
+
const metadata = mergePreservedMetadata(original?.metadata, entity.metadata)
|
|
145
|
+
|
|
146
|
+
if (original?.type === "narrative_beat") {
|
|
147
|
+
const record: RawJSONLRecord = {
|
|
148
|
+
...original,
|
|
149
|
+
type: "narrative_beat",
|
|
150
|
+
name: entity.name,
|
|
151
|
+
observations: entity.observations,
|
|
152
|
+
metadata,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if ("entityType" in original) {
|
|
156
|
+
record.entityType = entity.entityType
|
|
157
|
+
}
|
|
158
|
+
if ("narrative" in original && entity.metadata?.narrative !== undefined) {
|
|
159
|
+
record.narrative = cloneJson(entity.metadata.narrative)
|
|
160
|
+
}
|
|
161
|
+
if ("relational_alignment" in original && entity.metadata?.relationalAlignment !== undefined) {
|
|
162
|
+
record.relational_alignment = cloneJson(entity.metadata.relationalAlignment)
|
|
163
|
+
}
|
|
164
|
+
if ("four_directions" in original && entity.metadata?.fourDirections !== undefined) {
|
|
165
|
+
record.four_directions = cloneJson(entity.metadata.fourDirections)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return removeUndefined(record)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return removeUndefined({
|
|
172
|
+
...original,
|
|
173
|
+
...entity,
|
|
174
|
+
type: "entity",
|
|
175
|
+
metadata,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function serializeRelation(relation: RelationRecord, original?: RawJSONLRecord): RawJSONLRecord {
|
|
180
|
+
return removeUndefined({
|
|
181
|
+
...original,
|
|
182
|
+
...relation,
|
|
183
|
+
type: "relation",
|
|
184
|
+
metadata: mergePreservedMetadata(original?.metadata, relation.metadata),
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function findRecord(records: RawJSONLRecord[], key: string): RawJSONLRecord | undefined {
|
|
189
|
+
return records.find((record) => {
|
|
190
|
+
if (isEntityLikeRecord(record) && record.name === key) return true
|
|
191
|
+
if (isRelationLikeRecord(record)) return relationKey(record as RelationRecord) === key
|
|
192
|
+
return false
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function validateMetadata(label: string, beforeMetadata: unknown, afterMetadata: unknown, failures: string[]): void {
|
|
197
|
+
if (!isObject(beforeMetadata)) return
|
|
198
|
+
if (!isObject(afterMetadata)) {
|
|
199
|
+
failures.push(`${label}: metadata object missing after write`)
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
for (const [key, value] of Object.entries(beforeMetadata)) {
|
|
204
|
+
if (!(key in afterMetadata)) {
|
|
205
|
+
failures.push(`${label}: metadata.${key} missing after write`)
|
|
206
|
+
continue
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if ((key === "github" || !MUTABLE_METADATA_KEYS.has(key)) && !deepEqual(value, afterMetadata[key])) {
|
|
210
|
+
failures.push(`${label}: metadata.${key} changed unexpectedly`)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function validateRecordPreservation(
|
|
216
|
+
beforeRecords: RawJSONLRecord[],
|
|
217
|
+
afterRecords: RawJSONLRecord[],
|
|
218
|
+
entities: Map<string, EntityRecord>,
|
|
219
|
+
relations: RelationRecord[],
|
|
220
|
+
): void {
|
|
221
|
+
const relationKeys = new Set(relations.map((relation) => relationKey(relation)))
|
|
222
|
+
const failures: string[] = []
|
|
223
|
+
|
|
224
|
+
for (const before of beforeRecords) {
|
|
225
|
+
if (isEntityLikeRecord(before)) {
|
|
226
|
+
const name = before.name as string
|
|
227
|
+
if (!entities.has(name)) continue
|
|
228
|
+
|
|
229
|
+
const after = findRecord(afterRecords, name)
|
|
230
|
+
if (!after) {
|
|
231
|
+
failures.push(`${name}: record missing after write`)
|
|
232
|
+
continue
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (before.type === "narrative_beat" && after.type !== "narrative_beat") {
|
|
236
|
+
failures.push(`${name}: legacy narrative_beat record type was flattened`)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const knownKeys = before.type === "narrative_beat" ? NARRATIVE_BEAT_TOP_LEVEL_KEYS : ENTITY_TOP_LEVEL_KEYS
|
|
240
|
+
for (const key of Object.keys(before)) {
|
|
241
|
+
if (!knownKeys.has(key) && !deepEqual(before[key], after[key])) {
|
|
242
|
+
failures.push(`${name}: top-level extension field "${key}" was not preserved`)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
validateMetadata(name, before.metadata, after.metadata, failures)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (isRelationLikeRecord(before)) {
|
|
249
|
+
const key = relationKey(before as RelationRecord)
|
|
250
|
+
if (!relationKeys.has(key)) continue
|
|
251
|
+
|
|
252
|
+
const after = findRecord(afterRecords, key)
|
|
253
|
+
if (!after) {
|
|
254
|
+
failures.push(`${key}: relation missing after write`)
|
|
255
|
+
continue
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
for (const topLevelKey of Object.keys(before)) {
|
|
259
|
+
if (!RELATION_TOP_LEVEL_KEYS.has(topLevelKey) && !deepEqual(before[topLevelKey], after[topLevelKey])) {
|
|
260
|
+
failures.push(`${key}: relation extension field "${topLevelKey}" was not preserved`)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
validateMetadata(key, before.metadata, after.metadata, failures)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (failures.length > 0) {
|
|
268
|
+
throw new Error(`COAIA JSONL metadata preservation failed:\n- ${failures.join("\n- ")}`)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function buildRecordProjections(entities: Map<string, EntityRecord>): RecordProjections {
|
|
273
|
+
const allEntities = Array.from(entities.values())
|
|
274
|
+
return {
|
|
275
|
+
chartRecords: allEntities.filter((entity) => entity.entityType === "structural_tension_chart"),
|
|
276
|
+
actionStepRecords: allEntities.filter((entity) => entity.entityType === "action_step" || entity.metadata?.isTelescopedChart),
|
|
277
|
+
narrativeBeatRecords: allEntities.filter((entity) => entity.entityType === "narrative_beat"),
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function buildMetadataWarnings(records: RawJSONLRecord[]): MetadataWarning[] {
|
|
282
|
+
const warnings: MetadataWarning[] = []
|
|
283
|
+
|
|
284
|
+
for (const record of records) {
|
|
285
|
+
if (!isEntityLikeRecord(record) && !isRelationLikeRecord(record)) continue
|
|
286
|
+
|
|
287
|
+
const recordName = record.name || [record.from, record.to, record.relationType].filter(Boolean).join(" -> ")
|
|
288
|
+
const metadata = record.metadata
|
|
289
|
+
|
|
290
|
+
if (!isObject(metadata)) {
|
|
291
|
+
warnings.push({
|
|
292
|
+
severity: "warning",
|
|
293
|
+
recordName,
|
|
294
|
+
recordType: record.type,
|
|
295
|
+
message: "Record has no metadata object; provenance and extension fields may already be flattened.",
|
|
296
|
+
upstreamIssue: UPSTREAM_ISSUE,
|
|
297
|
+
})
|
|
298
|
+
continue
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (record.github && !metadata.github) {
|
|
302
|
+
warnings.push({
|
|
303
|
+
severity: "warning",
|
|
304
|
+
recordName,
|
|
305
|
+
recordType: record.type,
|
|
306
|
+
message: "GitHub provenance exists outside metadata.github; this shape is suspicious for preservation-aware tools.",
|
|
307
|
+
upstreamIssue: UPSTREAM_ISSUE,
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const normalized = normalizeJsonlRecord(record)
|
|
312
|
+
if (normalized && "entityType" in normalized) {
|
|
313
|
+
if (
|
|
314
|
+
["structural_tension_chart", "action_step", "desired_outcome", "current_reality", "narrative_beat"].includes(
|
|
315
|
+
normalized.entityType,
|
|
316
|
+
) &&
|
|
317
|
+
!normalized.metadata?.chartId
|
|
318
|
+
) {
|
|
319
|
+
warnings.push({
|
|
320
|
+
severity: "warning",
|
|
321
|
+
recordName: normalized.name,
|
|
322
|
+
recordType: normalized.entityType,
|
|
323
|
+
message: "COAIA entity is missing metadata.chartId, so chart/action projection may be incomplete.",
|
|
324
|
+
upstreamIssue: UPSTREAM_ISSUE,
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (
|
|
329
|
+
normalized.entityType === "narrative_beat" &&
|
|
330
|
+
!normalized.metadata?.narrative &&
|
|
331
|
+
!record.narrative &&
|
|
332
|
+
normalized.observations.length <= 1
|
|
333
|
+
) {
|
|
334
|
+
warnings.push({
|
|
335
|
+
severity: "warning",
|
|
336
|
+
recordName: normalized.name,
|
|
337
|
+
recordType: normalized.entityType,
|
|
338
|
+
message: "Narrative beat appears flattened: no narrative metadata or rich beat payload is visible.",
|
|
339
|
+
upstreamIssue: UPSTREAM_ISSUE,
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (record.type === "narrative_beat") {
|
|
345
|
+
warnings.push({
|
|
346
|
+
severity: "warning",
|
|
347
|
+
recordName,
|
|
348
|
+
recordType: "narrative_beat",
|
|
349
|
+
message: "Legacy narrative_beat shape detected. It is rendered separately and preserved on save.",
|
|
350
|
+
upstreamIssue: UPSTREAM_ISSUE,
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return warnings
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function serializeParsedData(data: Pick<ParsedData, "entities" | "relations" | "rawRecords">): string {
|
|
359
|
+
const rawRecords = data.rawRecords || []
|
|
360
|
+
const emittedEntities = new Set<string>()
|
|
361
|
+
const emittedRelations = new Set<string>()
|
|
362
|
+
const records: RawJSONLRecord[] = []
|
|
363
|
+
|
|
364
|
+
for (const original of rawRecords) {
|
|
365
|
+
if (isEntityLikeRecord(original)) {
|
|
366
|
+
const entity = data.entities.get(original.name)
|
|
367
|
+
if (entity) {
|
|
368
|
+
records.push(serializeEntity(entity, original))
|
|
369
|
+
emittedEntities.add(entity.name)
|
|
370
|
+
}
|
|
371
|
+
continue
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (isRelationLikeRecord(original)) {
|
|
375
|
+
const key = relationKey(original as RelationRecord)
|
|
376
|
+
const relation = data.relations.find((candidate) => relationKey(candidate) === key)
|
|
377
|
+
if (relation) {
|
|
378
|
+
records.push(serializeRelation(relation, original))
|
|
379
|
+
emittedRelations.add(key)
|
|
380
|
+
}
|
|
381
|
+
continue
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
records.push(original)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
for (const entity of data.entities.values()) {
|
|
388
|
+
if (!emittedEntities.has(entity.name)) {
|
|
389
|
+
records.push(serializeEntity(entity))
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
for (const relation of data.relations) {
|
|
394
|
+
const key = relationKey(relation)
|
|
395
|
+
if (!emittedRelations.has(key)) {
|
|
396
|
+
records.push(serializeRelation(relation))
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
validateRecordPreservation(rawRecords, records, data.entities, data.relations)
|
|
401
|
+
|
|
402
|
+
return `${records.map((record) => JSON.stringify(record)).join("\n")}\n`
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export { UPSTREAM_ISSUE }
|
package/lib/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface EntityRecord {
|
|
|
6
6
|
entityType: "structural_tension_chart" | "desired_outcome" | "current_reality" | "action_step" | "narrative_beat"
|
|
7
7
|
observations: string[]
|
|
8
8
|
metadata: Record<string, any>
|
|
9
|
+
[key: string]: any
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export interface RelationRecord {
|
|
@@ -14,9 +15,34 @@ export interface RelationRecord {
|
|
|
14
15
|
to: string
|
|
15
16
|
relationType: "contains" | "creates_tension_with" | "advances_toward" | "documents"
|
|
16
17
|
metadata: Record<string, any>
|
|
18
|
+
[key: string]: any
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export type JSONLRecord = EntityRecord | RelationRecord
|
|
22
|
+
export type RawJSONLRecord = Record<string, any>
|
|
23
|
+
|
|
24
|
+
export interface MetadataWarning {
|
|
25
|
+
severity: "warning" | "error"
|
|
26
|
+
recordName?: string
|
|
27
|
+
recordType?: string
|
|
28
|
+
message: string
|
|
29
|
+
upstreamIssue?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RecordProjections {
|
|
33
|
+
chartRecords: EntityRecord[]
|
|
34
|
+
actionStepRecords: EntityRecord[]
|
|
35
|
+
narrativeBeatRecords: EntityRecord[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface RiseSpecProjection {
|
|
39
|
+
chartId: string
|
|
40
|
+
desiredOutcome: string
|
|
41
|
+
currentReality: string[]
|
|
42
|
+
naturalProgression: string[]
|
|
43
|
+
remainingBlockers: string[]
|
|
44
|
+
nextOperations: string[]
|
|
45
|
+
}
|
|
20
46
|
|
|
21
47
|
export interface Chart {
|
|
22
48
|
id: string
|
|
@@ -36,4 +62,8 @@ export interface ParsedData {
|
|
|
36
62
|
entities: Map<string, EntityRecord>
|
|
37
63
|
relations: RelationRecord[]
|
|
38
64
|
rootCharts: Chart[]
|
|
65
|
+
rawRecords?: RawJSONLRecord[]
|
|
66
|
+
projections?: RecordProjections
|
|
67
|
+
preservationWarnings?: MetadataWarning[]
|
|
68
|
+
riseSpecs?: RiseSpecProjection[]
|
|
39
69
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coaia-visualizer",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.tsx",
|
|
@@ -18,6 +18,35 @@
|
|
|
18
18
|
"bin": {
|
|
19
19
|
"coaia-visualizer": "dist/cli.js"
|
|
20
20
|
},
|
|
21
|
+
"files": [
|
|
22
|
+
"app/**/*",
|
|
23
|
+
"components/**/*",
|
|
24
|
+
"hooks/**/*",
|
|
25
|
+
"lib/**/*",
|
|
26
|
+
"styles/**/*",
|
|
27
|
+
"public/**/*",
|
|
28
|
+
"dist/**/*",
|
|
29
|
+
"mcp/dist/**/*",
|
|
30
|
+
"mcp/src/**/*",
|
|
31
|
+
"mcp/package.json",
|
|
32
|
+
"mcp/package-lock.json",
|
|
33
|
+
"mcp/README.md",
|
|
34
|
+
"mcp/Dockerfile",
|
|
35
|
+
"mcp/tsconfig.json",
|
|
36
|
+
"index.tsx",
|
|
37
|
+
"cli.ts",
|
|
38
|
+
"skill.ts",
|
|
39
|
+
"components.json",
|
|
40
|
+
"mcp-config.json",
|
|
41
|
+
"next-env.d.ts",
|
|
42
|
+
"next.config.mjs",
|
|
43
|
+
"postcss.config.mjs",
|
|
44
|
+
"tsconfig.json",
|
|
45
|
+
"README.md",
|
|
46
|
+
"README_TELESCOPED_NAVIGATION.md",
|
|
47
|
+
"KINSHIP.md",
|
|
48
|
+
"NAMING.md"
|
|
49
|
+
],
|
|
21
50
|
"scripts": {
|
|
22
51
|
"build": "next build",
|
|
23
52
|
"build:cli": "tsc cli.ts --outDir dist --module esnext --target es2022 --moduleResolution bundler --esModuleInterop --skipLibCheck",
|
|
@@ -26,6 +55,7 @@
|
|
|
26
55
|
"prepare": "npm run build:cli",
|
|
27
56
|
"start": "next start",
|
|
28
57
|
"test": "playwright test",
|
|
58
|
+
"test:rich-jsonl": "playwright test test-scripts/rich-jsonl-preservation.spec.ts",
|
|
29
59
|
"test:global-cli": "playwright test test-scripts/test-global-cli.spec.ts",
|
|
30
60
|
"docker:build": "docker build -t jgwill/coaia:visualizer .",
|
|
31
61
|
"docker:push": "docker push jgwill/coaia:visualizer",
|