coaia-visualizer 1.6.0 → 1.6.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.
- package/.dockerignore +9 -0
- package/COMPLETE_IMPLEMENTATION_REPORT.md +215 -0
- package/QUICK_START_MCP_TESTING.md +236 -0
- package/README.md +1 -1
- package/README_TELESCOPED_NAVIGATION.md +247 -0
- package/STC.md +24 -0
- package/STCGOAL.md +0 -0
- package/STCISSUE.md +48 -0
- package/STCKIN.md +0 -0
- package/STCMASTERY.md +0 -0
- package/STUDY_REPORT.md +510 -0
- package/app/page.tsx +4 -23
- package/cli.ts +8 -0
- package/components/chart-detail-editable.tsx +3 -2
- package/components/chart-detail.tsx +1 -6
- package/components/edit-action-step.tsx +0 -2
- package/components/metadata-projections.tsx +208 -0
- package/components/relation-graph.tsx +27 -91
- package/components.json +21 -0
- package/direct-test.sh +180 -0
- package/dist/cli.js +7 -0
- package/dist/skill.js +342 -0
- package/docker-compose.test.yml +69 -0
- package/index.tsx +0 -26
- package/jgwill.coaia-visualizer-8--496dca71-d476-4ac9-ba9f-376add118dd8--260208.txt +2612 -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 +32 -15
- package/mcp/dist/api-client.d.ts +138 -0
- package/mcp/dist/api-client.d.ts.map +1 -0
- package/mcp/dist/api-client.js +115 -0
- package/mcp/dist/api-client.js.map +1 -0
- package/mcp/dist/index.d.ts +2 -0
- package/mcp/dist/index.d.ts.map +1 -0
- package/mcp/dist/index.js +286 -0
- package/mcp/dist/index.js.map +1 -0
- package/mcp/dist/tools/index.d.ts +18 -0
- package/mcp/dist/tools/index.d.ts.map +1 -0
- package/mcp/dist/tools/index.js +322 -0
- package/mcp/dist/tools/index.js.map +1 -0
- package/mcp/package-lock.json +210 -0
- package/package.json +2 -27
- package/rispecs/github-project-runtime-memory-integration.spec.md +381 -0
- package/skill.ts +385 -0
- package/test-data/test-master.jsonl +11 -0
- package/test-results/.last-run.json +4 -0
- package/test-scripts/README.md +325 -0
- package/test-scripts/rich-jsonl-preservation.spec.ts +118 -0
- package/test-scripts/run-all-tests.sh +38 -0
- package/test-scripts/test-01-basic-operations.sh +87 -0
- package/test-scripts/test-02-telescope-creation.sh +91 -0
- package/test-scripts/test-03-navigation.sh +87 -0
- package/test-scripts/test-global-cli.spec.ts +220 -0
- package/test-scripts/verify-global-cli.sh +87 -0
- package/tsconfig.json +41 -0
- package/components/github-provenance.tsx +0 -226
- package/lib/github-provenance.ts +0 -316
package/lib/github-provenance.ts
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import type { EntityRecord, RelationRecord } from "./types"
|
|
2
|
-
|
|
3
|
-
export const GITHUB_SYNC_STATES = ["synced", "diverged", "conflict", "project-only", "chart-only"] as const
|
|
4
|
-
|
|
5
|
-
export type GithubSyncState = (typeof GITHUB_SYNC_STATES)[number]
|
|
6
|
-
|
|
7
|
-
export interface GithubIssueRef {
|
|
8
|
-
owner: string
|
|
9
|
-
repo: string
|
|
10
|
-
number: number
|
|
11
|
-
nodeId?: string
|
|
12
|
-
url?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface GithubProjectItemRef {
|
|
16
|
-
projectOwner?: string
|
|
17
|
-
projectNumber?: number
|
|
18
|
-
projectTitle?: string
|
|
19
|
-
itemId?: string
|
|
20
|
-
projectId?: string
|
|
21
|
-
url?: string
|
|
22
|
-
fields?: Record<string, unknown>
|
|
23
|
-
fieldValues?: Record<string, unknown>
|
|
24
|
-
projectFields?: Record<string, unknown>
|
|
25
|
-
[key: string]: unknown
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface GithubSourceProvenance {
|
|
29
|
-
system?: string
|
|
30
|
-
toolName?: string
|
|
31
|
-
sessionId?: string
|
|
32
|
-
createdAt?: string
|
|
33
|
-
version?: string
|
|
34
|
-
[key: string]: unknown
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface GithubEntityProvenance {
|
|
38
|
-
issue?: GithubIssueRef
|
|
39
|
-
projectItems: GithubProjectItemRef[]
|
|
40
|
-
syncState?: GithubSyncState
|
|
41
|
-
lastSyncedAt?: string
|
|
42
|
-
source?: GithubSourceProvenance
|
|
43
|
-
hasGithubMetadata: boolean
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface GithubProjectFieldEntry {
|
|
47
|
-
key: string
|
|
48
|
-
label: string
|
|
49
|
-
value: string
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export const GITHUB_PROJECT_FIELD_KEYS = [
|
|
53
|
-
"goal",
|
|
54
|
-
"current_reality",
|
|
55
|
-
"observations",
|
|
56
|
-
"question",
|
|
57
|
-
"Status",
|
|
58
|
-
"phase",
|
|
59
|
-
"session_id",
|
|
60
|
-
"four_dir_east",
|
|
61
|
-
"four_dir_south",
|
|
62
|
-
"four_dir_west",
|
|
63
|
-
"four_dir_north",
|
|
64
|
-
"relational_assessed",
|
|
65
|
-
"relational_principles",
|
|
66
|
-
] as const
|
|
67
|
-
|
|
68
|
-
export const GITHUB_BRIDGE_RELATION_TYPES = ["synced_to_github", "linked_to_issue", "project_lens_of"] as const
|
|
69
|
-
|
|
70
|
-
export type GithubBridgeRelationType = (typeof GITHUB_BRIDGE_RELATION_TYPES)[number]
|
|
71
|
-
|
|
72
|
-
const PROJECT_FIELD_LABELS: Record<string, string> = {
|
|
73
|
-
goal: "goal",
|
|
74
|
-
current_reality: "current reality",
|
|
75
|
-
observations: "observations",
|
|
76
|
-
question: "question",
|
|
77
|
-
Status: "Status",
|
|
78
|
-
phase: "phase",
|
|
79
|
-
session_id: "session",
|
|
80
|
-
four_dir_east: "East",
|
|
81
|
-
four_dir_south: "South",
|
|
82
|
-
four_dir_west: "West",
|
|
83
|
-
four_dir_north: "North",
|
|
84
|
-
relational_assessed: "relational assessed",
|
|
85
|
-
relational_principles: "relational principles",
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
89
|
-
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function firstString(...values: unknown[]): string | undefined {
|
|
93
|
-
for (const value of values) {
|
|
94
|
-
if (typeof value === "string" && value.trim()) {
|
|
95
|
-
return value.trim()
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function firstNumber(...values: unknown[]): number | undefined {
|
|
101
|
-
for (const value of values) {
|
|
102
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
103
|
-
return value
|
|
104
|
-
}
|
|
105
|
-
if (typeof value === "string" && value.trim()) {
|
|
106
|
-
const parsed = Number(value)
|
|
107
|
-
if (Number.isFinite(parsed)) {
|
|
108
|
-
return parsed
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function normalizeIssueCandidate(candidate: unknown): GithubIssueRef | undefined {
|
|
115
|
-
if (!isRecord(candidate)) return undefined
|
|
116
|
-
|
|
117
|
-
const owner = firstString(candidate.owner, candidate.ownerLogin, candidate.repositoryOwner)
|
|
118
|
-
const repo = firstString(candidate.repo, candidate.repository, candidate.repositoryName)
|
|
119
|
-
const number = firstNumber(candidate.number, candidate.issue_number, candidate.issueNumber, candidate.issue)
|
|
120
|
-
|
|
121
|
-
if (!owner || !repo || !number) return undefined
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
owner,
|
|
125
|
-
repo,
|
|
126
|
-
number,
|
|
127
|
-
nodeId: firstString(candidate.nodeId, candidate.node_id),
|
|
128
|
-
url: firstString(candidate.url, candidate.html_url) ?? `https://github.com/${owner}/${repo}/issues/${number}`,
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function normalizeProjectItemCandidate(candidate: unknown, fallbackOwner?: string): GithubProjectItemRef | undefined {
|
|
133
|
-
if (!isRecord(candidate)) return undefined
|
|
134
|
-
|
|
135
|
-
const projectOwner = firstString(candidate.projectOwner, candidate.owner, candidate.ownerLogin, fallbackOwner)
|
|
136
|
-
const projectNumber = firstNumber(candidate.projectNumber, candidate.project_number, candidate.number)
|
|
137
|
-
const itemId = firstString(candidate.itemId, candidate.item_id, candidate.projectItemId, candidate.project_id)
|
|
138
|
-
const projectId = firstString(candidate.projectId, candidate.project_id)
|
|
139
|
-
const projectTitle = firstString(candidate.projectTitle, candidate.title, candidate.project)
|
|
140
|
-
const url = firstString(candidate.url)
|
|
141
|
-
|
|
142
|
-
if (!projectOwner && !projectNumber && !itemId && !projectId && !projectTitle && !url) {
|
|
143
|
-
return undefined
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
...candidate,
|
|
148
|
-
projectOwner,
|
|
149
|
-
projectNumber,
|
|
150
|
-
projectTitle,
|
|
151
|
-
itemId,
|
|
152
|
-
projectId,
|
|
153
|
-
url,
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function getGithubIssueRef(entity?: EntityRecord): GithubIssueRef | undefined {
|
|
158
|
-
if (!entity) return undefined
|
|
159
|
-
|
|
160
|
-
const metadata = entity.metadata ?? {}
|
|
161
|
-
const github = isRecord(metadata.github) ? metadata.github : undefined
|
|
162
|
-
const syncTarget = isRecord(metadata.sync_target) ? metadata.sync_target : undefined
|
|
163
|
-
const githubRef = isRecord(metadata.github_ref) ? metadata.github_ref : undefined
|
|
164
|
-
|
|
165
|
-
return normalizeIssueCandidate(github?.issue) ?? normalizeIssueCandidate(syncTarget) ?? normalizeIssueCandidate(githubRef)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function getGithubProjectItems(entity?: EntityRecord): GithubProjectItemRef[] {
|
|
169
|
-
if (!entity) return []
|
|
170
|
-
|
|
171
|
-
const metadata = entity.metadata ?? {}
|
|
172
|
-
const github = isRecord(metadata.github) ? metadata.github : undefined
|
|
173
|
-
const syncTarget = isRecord(metadata.sync_target) ? metadata.sync_target : undefined
|
|
174
|
-
const fallbackOwner = getGithubIssueRef(entity)?.owner
|
|
175
|
-
|
|
176
|
-
if (Array.isArray(github?.projectItems)) {
|
|
177
|
-
return github.projectItems
|
|
178
|
-
.map((item) => normalizeProjectItemCandidate(item, fallbackOwner))
|
|
179
|
-
.filter((item): item is GithubProjectItemRef => Boolean(item))
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const canonicalProjectItem = normalizeProjectItemCandidate(github?.projectItem, fallbackOwner)
|
|
183
|
-
if (canonicalProjectItem) {
|
|
184
|
-
return [canonicalProjectItem]
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const legacyProjectItem = normalizeProjectItemCandidate(syncTarget, fallbackOwner)
|
|
188
|
-
return legacyProjectItem ? [legacyProjectItem] : []
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export function getGithubSyncState(entityOrMetadata?: EntityRecord | Record<string, unknown>): GithubSyncState | undefined {
|
|
192
|
-
const metadata =
|
|
193
|
-
entityOrMetadata && "metadata" in entityOrMetadata && isRecord(entityOrMetadata.metadata)
|
|
194
|
-
? entityOrMetadata.metadata
|
|
195
|
-
: entityOrMetadata
|
|
196
|
-
|
|
197
|
-
if (!isRecord(metadata)) return undefined
|
|
198
|
-
|
|
199
|
-
const github = isRecord(metadata.github) ? metadata.github : undefined
|
|
200
|
-
const syncState = github?.syncState ?? metadata.syncState
|
|
201
|
-
|
|
202
|
-
return typeof syncState === "string" && GITHUB_SYNC_STATES.includes(syncState as GithubSyncState)
|
|
203
|
-
? (syncState as GithubSyncState)
|
|
204
|
-
: undefined
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export function getGithubSource(entity?: EntityRecord): GithubSourceProvenance | undefined {
|
|
208
|
-
if (!entity) return undefined
|
|
209
|
-
|
|
210
|
-
const source = entity.metadata?.source
|
|
211
|
-
return isRecord(source) ? (source as GithubSourceProvenance) : undefined
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export function getGithubEntityProvenance(entity?: EntityRecord): GithubEntityProvenance {
|
|
215
|
-
const metadata = entity?.metadata ?? {}
|
|
216
|
-
const github = isRecord(metadata.github) ? metadata.github : undefined
|
|
217
|
-
const issue = getGithubIssueRef(entity)
|
|
218
|
-
const projectItems = getGithubProjectItems(entity)
|
|
219
|
-
const syncTarget = isRecord(metadata.sync_target) ? metadata.sync_target : undefined
|
|
220
|
-
const githubRef = isRecord(metadata.github_ref) ? metadata.github_ref : undefined
|
|
221
|
-
const source = getGithubSource(entity)
|
|
222
|
-
|
|
223
|
-
return {
|
|
224
|
-
issue,
|
|
225
|
-
projectItems,
|
|
226
|
-
syncState: getGithubSyncState(entity),
|
|
227
|
-
lastSyncedAt: firstString(github?.lastSyncedAt, metadata.lastSyncedAt),
|
|
228
|
-
source,
|
|
229
|
-
hasGithubMetadata:
|
|
230
|
-
Boolean(github) ||
|
|
231
|
-
Boolean(syncTarget) ||
|
|
232
|
-
Boolean(githubRef) ||
|
|
233
|
-
source?.system === "coaia-github" ||
|
|
234
|
-
Boolean(issue) ||
|
|
235
|
-
projectItems.length > 0,
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export function formatGithubIssueRef(issue?: GithubIssueRef): string | undefined {
|
|
240
|
-
if (!issue) return undefined
|
|
241
|
-
return `${issue.owner}/${issue.repo}#${issue.number}`
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export function formatProjectItemRef(projectItem?: GithubProjectItemRef): string | undefined {
|
|
245
|
-
if (!projectItem) return undefined
|
|
246
|
-
|
|
247
|
-
if (projectItem.projectOwner && projectItem.projectNumber) {
|
|
248
|
-
return `${projectItem.projectOwner}/${projectItem.projectNumber}`
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return projectItem.projectTitle || projectItem.itemId || projectItem.projectId || projectItem.url
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export function getProjectFieldEntries(
|
|
255
|
-
entity: EntityRecord | undefined,
|
|
256
|
-
projectItem?: GithubProjectItemRef,
|
|
257
|
-
): GithubProjectFieldEntry[] {
|
|
258
|
-
const metadata = entity?.metadata ?? {}
|
|
259
|
-
const github = isRecord(metadata.github) ? metadata.github : undefined
|
|
260
|
-
const sources = [
|
|
261
|
-
projectItem?.fields,
|
|
262
|
-
projectItem?.fieldValues,
|
|
263
|
-
projectItem?.projectFields,
|
|
264
|
-
github?.fields,
|
|
265
|
-
github?.fieldValues,
|
|
266
|
-
github?.projectFields,
|
|
267
|
-
metadata,
|
|
268
|
-
github,
|
|
269
|
-
].filter(isRecord)
|
|
270
|
-
|
|
271
|
-
return GITHUB_PROJECT_FIELD_KEYS.flatMap((key) => {
|
|
272
|
-
for (const source of sources) {
|
|
273
|
-
if (!(key in source)) continue
|
|
274
|
-
const value = stringifyFieldValue(source[key])
|
|
275
|
-
if (value) {
|
|
276
|
-
return [{ key, label: PROJECT_FIELD_LABELS[key], value }]
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return []
|
|
280
|
-
})
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export function getGithubBridgeRelationType(relation: RelationRecord): GithubBridgeRelationType | undefined {
|
|
284
|
-
const relationType = relation.relationType
|
|
285
|
-
if (GITHUB_BRIDGE_RELATION_TYPES.includes(relationType as GithubBridgeRelationType)) {
|
|
286
|
-
return relationType as GithubBridgeRelationType
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const metadata = relation.metadata ?? {}
|
|
290
|
-
const github = isRecord(metadata.github) ? metadata.github : undefined
|
|
291
|
-
const context = firstString(
|
|
292
|
-
metadata.context,
|
|
293
|
-
metadata.relation,
|
|
294
|
-
metadata.relationName,
|
|
295
|
-
metadata.semanticType,
|
|
296
|
-
github?.context,
|
|
297
|
-
github?.relation,
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
return GITHUB_BRIDGE_RELATION_TYPES.includes(context as GithubBridgeRelationType)
|
|
301
|
-
? (context as GithubBridgeRelationType)
|
|
302
|
-
: undefined
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function stringifyFieldValue(value: unknown): string | undefined {
|
|
306
|
-
if (value === null || value === undefined) return undefined
|
|
307
|
-
if (typeof value === "string") return value.trim() || undefined
|
|
308
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value)
|
|
309
|
-
if (Array.isArray(value)) {
|
|
310
|
-
const rendered = value.map(stringifyFieldValue).filter(Boolean).join(", ")
|
|
311
|
-
return rendered || undefined
|
|
312
|
-
}
|
|
313
|
-
if (isRecord(value)) {
|
|
314
|
-
return firstString(value.name, value.text, value.value, value.title, value.label) ?? JSON.stringify(value)
|
|
315
|
-
}
|
|
316
|
-
}
|