coaia-visualizer 1.6.3 → 1.6.5

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 (54) hide show
  1. package/Dockerfile +61 -0
  2. package/Dockerfile.app +50 -0
  3. package/README.md +2 -1
  4. package/cli.ts +11 -5
  5. package/components/asterion-foundation-card.tsx +175 -0
  6. package/components/asterion-session-context-badge.tsx +122 -0
  7. package/components/asterion-session-lineage-card.tsx +119 -0
  8. package/components/chart-detail-editable.tsx +2 -0
  9. package/components/chart-detail.tsx +9 -1
  10. package/components/edit-action-step.tsx +2 -0
  11. package/components/github-provenance.tsx +226 -0
  12. package/components/metadata-projections.tsx +50 -16
  13. package/components/narrative-beats.tsx +16 -3
  14. package/components/relation-graph.tsx +91 -27
  15. package/dist/cli.js +9 -5
  16. package/docker-build-push.sh +20 -0
  17. package/docker-entrypoint.sh +27 -0
  18. package/index.tsx +39 -2
  19. package/lib/asterion-metadata.ts +673 -0
  20. package/lib/chart-editor.ts +8 -3
  21. package/lib/github-provenance.ts +316 -0
  22. package/lib/jsonl-parser.ts +7 -2
  23. package/lib/types.ts +112 -2
  24. package/mcp/test_mcp/.gemini/settings.json +18 -0
  25. package/next-env.d.ts +1 -1
  26. package/package.json +14 -13
  27. package/rispecs/README.md +170 -0
  28. package/rispecs/accountability-responsibility.rispec.md +110 -0
  29. package/rispecs/api-mcp-interface.spec.md +287 -0
  30. package/rispecs/app.spec.md +364 -0
  31. package/rispecs/chart-editing-workflow.spec.md +297 -0
  32. package/rispecs/chart-visualization-hierarchy.spec.md +235 -0
  33. package/rispecs/cli-mode.spec.md +224 -0
  34. package/rispecs/github-project-runtime-memory-integration.spec.md +381 -0
  35. package/rispecs/jsonl-parsing-data-types.spec.md +243 -0
  36. package/rispecs/narrative-beats-display.spec.md +189 -0
  37. package/rispecs/pde-integration.spec.md +280 -0
  38. package/rispecs/planning-integration.spec.md +329 -0
  39. package/rispecs/relation-graph-visualization.spec.md +171 -0
  40. package/rispecs/relation-to-mcp-structural-thinking.kin.md +65 -0
  41. package/rispecs/ui-component-library.spec.md +258 -0
  42. package/mcp/dist/api-client.d.ts +0 -138
  43. package/mcp/dist/api-client.d.ts.map +0 -1
  44. package/mcp/dist/api-client.js +0 -115
  45. package/mcp/dist/api-client.js.map +0 -1
  46. package/mcp/dist/index.d.ts +0 -2
  47. package/mcp/dist/index.d.ts.map +0 -1
  48. package/mcp/dist/index.js +0 -286
  49. package/mcp/dist/index.js.map +0 -1
  50. package/mcp/dist/tools/index.d.ts +0 -18
  51. package/mcp/dist/tools/index.d.ts.map +0 -1
  52. package/mcp/dist/tools/index.js +0 -322
  53. package/mcp/dist/tools/index.js.map +0 -1
  54. package/mcp/package-lock.json +0 -210
@@ -0,0 +1,316 @@
1
+ import type { EntityRecord, RelationRecord } from "./types.ts"
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
+ }
@@ -1,5 +1,6 @@
1
- import type { Chart, EntityRecord, JSONLRecord, ParsedData, RawJSONLRecord, RelationRecord, RiseSpecProjection } from "./types"
2
- import { buildMetadataWarnings, buildRecordProjections, normalizeJsonlRecord } from "./jsonl-preservation"
1
+ import type { Chart, EntityRecord, JSONLRecord, ParsedData, RawJSONLRecord, RelationRecord, RiseSpecProjection } from "./types.ts"
2
+ import { extractAsterionMetadata } from "./asterion-metadata.ts"
3
+ import { buildMetadataWarnings, buildRecordProjections, normalizeJsonlRecord } from "./jsonl-preservation.ts"
3
4
 
4
5
  export function parseJSONL(content: string): RawJSONLRecord[] {
5
6
  const lines = content.trim().split("\n")
@@ -192,6 +193,10 @@ export function organizeData(records: RawJSONLRecord[]): ParsedData {
192
193
  }
193
194
  }
194
195
 
196
+ for (const chart of charts.values()) {
197
+ Object.assign(chart, extractAsterionMetadata(chart))
198
+ }
199
+
195
200
  // Identify root charts (level 0 or no parent)
196
201
  const rootCharts = Array.from(charts.values()).filter((chart) => chart.level === 0 || !chart.parentChart)
197
202
 
package/lib/types.ts CHANGED
@@ -3,7 +3,14 @@
3
3
  export interface EntityRecord {
4
4
  type: "entity"
5
5
  name: string
6
- entityType: "structural_tension_chart" | "desired_outcome" | "current_reality" | "action_step" | "narrative_beat"
6
+ entityType:
7
+ | "structural_tension_chart"
8
+ | "desired_outcome"
9
+ | "current_reality"
10
+ | "action_step"
11
+ | "narrative_beat"
12
+ | "custom"
13
+ | (string & {})
7
14
  observations: string[]
8
15
  metadata: Record<string, any>
9
16
  [key: string]: any
@@ -13,7 +20,13 @@ export interface RelationRecord {
13
20
  type: "relation"
14
21
  from: string
15
22
  to: string
16
- relationType: "contains" | "creates_tension_with" | "advances_toward" | "documents"
23
+ relationType:
24
+ | "contains"
25
+ | "creates_tension_with"
26
+ | "advances_toward"
27
+ | "documents"
28
+ | "custom"
29
+ | (string & {})
17
30
  metadata: Record<string, any>
18
31
  [key: string]: any
19
32
  }
@@ -44,6 +57,101 @@ export interface RiseSpecProjection {
44
57
  nextOperations: string[]
45
58
  }
46
59
 
60
+ export interface FoundationMetadata {
61
+ packetRoot: string
62
+ foundationType: string
63
+ parentIssue: string
64
+ baselineIssue: string
65
+ inquiryIssue: string
66
+ protocolIssue: string
67
+ schemaIssue: string
68
+ visualizerIssue: string
69
+ expectedArtifacts: string[]
70
+ producedArtifacts: string[]
71
+ evaluationStatus: "expected" | "delegated" | "produced" | "evaluated"
72
+ privacyClass: "public-safe" | "private" | "mixed"
73
+ publicationStatus: "planned" | "draft" | "reviewed" | "published"
74
+ commitHandles: string[]
75
+ }
76
+
77
+ export interface SessionLineageMetadata {
78
+ platform: string
79
+ parentChartId: string
80
+ sourceBeat: string
81
+ originalSessionId: string
82
+ branchSessionId: string
83
+ branchIndex: number
84
+ copiedMessageCount: number
85
+ branchPurpose: string
86
+ relatedIssues: string[]
87
+ handoffState: "requirements-created" | "implementation-ready" | "returned-to-parent"
88
+ }
89
+
90
+ export interface SessionContextMetadata {
91
+ mode: string
92
+ setting: string
93
+ captureQuality: "complete" | "partial" | "noisy" | "transcript-only"
94
+ continuationKind: "new" | "resumption" | "branch-return" | "daily-chronicle"
95
+ privateChroniclePath?: string
96
+ handle?: string
97
+ publicSummaryAllowed: boolean
98
+ }
99
+
100
+ export interface ParsedIssueReference {
101
+ key: string
102
+ raw: string
103
+ label: string
104
+ href?: string
105
+ owner?: string
106
+ repo?: string
107
+ number?: number
108
+ }
109
+
110
+ export interface ArtifactDiffEntry {
111
+ artifact: string
112
+ expected: boolean
113
+ produced: boolean
114
+ status: "matched" | "missing" | "unexpected"
115
+ }
116
+
117
+ export interface FoundationProjection {
118
+ foundation: Partial<FoundationMetadata>
119
+ warnings: MetadataWarning[]
120
+ issueRefs: ParsedIssueReference[]
121
+ artifactDiff: ArtifactDiffEntry[]
122
+ sourceRecords: string[]
123
+ }
124
+
125
+ export interface SessionLineageBranchProjection {
126
+ metadata: Partial<SessionLineageMetadata>
127
+ sourceRecordName?: string
128
+ sourceRecordType?: string
129
+ warnings: MetadataWarning[]
130
+ relatedIssueRefs: ParsedIssueReference[]
131
+ sourceBeatAnchor?: string
132
+ sourceBeatExistsInChart: boolean
133
+ }
134
+
135
+ export interface SessionLineageGroupProjection {
136
+ sourceBeat: string
137
+ sourceBeatAnchor?: string
138
+ sourceBeatExistsInChart: boolean
139
+ branches: SessionLineageBranchProjection[]
140
+ }
141
+
142
+ export interface SessionLineageProjection {
143
+ branches: SessionLineageBranchProjection[]
144
+ groupedBranches: SessionLineageGroupProjection[]
145
+ warnings: MetadataWarning[]
146
+ }
147
+
148
+ export interface SessionContextProjection {
149
+ context: Partial<SessionContextMetadata>
150
+ warnings: MetadataWarning[]
151
+ beatName: string
152
+ beatIndex: number
153
+ }
154
+
47
155
  export interface Chart {
48
156
  id: string
49
157
  chartEntity: EntityRecord
@@ -55,6 +163,8 @@ export interface Chart {
55
163
  level: number
56
164
  parentChart?: string
57
165
  relations: RelationRecord[]
166
+ foundationProjection?: FoundationProjection
167
+ sessionLineageProjection?: SessionLineageProjection
58
168
  }
59
169
 
60
170
  export interface ParsedData {
@@ -0,0 +1,18 @@
1
+ {
2
+ "mcpServers": {
3
+ "chart-coaia-narrative-legacy-mcp": {
4
+ "command": "npx",
5
+ "args": ["-y", "${CNCV}", "--memory-path", "${memories}/trading-chart.coaia-narrative.jsonl" ]
6
+ },
7
+ "charts-mcp": {
8
+ "command": "node",
9
+ "args": [
10
+ "/workspace/repos/jgwill/coaia-visualizer-feat-4/mcp/dist/index.js"
11
+ ],
12
+ "env": {
13
+ "COAIAN_API_TOKEN":"123",
14
+ "COAIAV_API_URL":"http://localhost:4321"
15
+ }
16
+ }
17
+ }
18
+ }
package/next-env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
3
+ import "./.next/dev/types/routes.d.ts";
4
4
 
5
5
  // NOTE: This file should not be edited
6
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coaia-visualizer",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./index.tsx",
@@ -9,6 +9,7 @@
9
9
  ".": "./index.tsx",
10
10
  "./lib/types": "./lib/types.ts",
11
11
  "./lib/jsonl-parser": "./lib/jsonl-parser.ts",
12
+ "./lib/github-provenance": "./lib/github-provenance.ts",
12
13
  "./lib/utils": "./lib/utils.ts",
13
14
  "./hooks/*": "./hooks/*.ts",
14
15
  "./components/*": "./components/*.tsx",
@@ -23,25 +24,24 @@
23
24
  "components/**/*",
24
25
  "hooks/**/*",
25
26
  "lib/**/*",
26
- "styles/**/*",
27
- "public/**/*",
28
27
  "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",
28
+ "mcp/**/*",
29
+ "public/**/*",
30
+ "rispecs/**/*",
31
+ "styles/**/*",
37
32
  "cli.ts",
33
+ "index.tsx",
38
34
  "skill.ts",
39
- "components.json",
40
- "mcp-config.json",
41
35
  "next-env.d.ts",
42
36
  "next.config.mjs",
43
37
  "postcss.config.mjs",
44
38
  "tsconfig.json",
39
+ "Dockerfile",
40
+ "Dockerfile.app",
41
+ "docker-build-push.sh",
42
+ "docker-entrypoint.sh",
43
+ "components.json",
44
+ "mcp-config.json",
45
45
  "README.md",
46
46
  "README_TELESCOPED_NAVIGATION.md",
47
47
  "KINSHIP.md",
@@ -57,6 +57,7 @@
57
57
  "test": "playwright test",
58
58
  "test:rich-jsonl": "playwright test test-scripts/rich-jsonl-preservation.spec.ts",
59
59
  "test:global-cli": "playwright test test-scripts/test-global-cli.spec.ts",
60
+ "verify:github-provenance": "node --experimental-strip-types --experimental-specifier-resolution=node test-scripts/verify-github-provenance.mjs",
60
61
  "docker:build": "docker build -t jgwill/coaia:visualizer .",
61
62
  "docker:push": "docker push jgwill/coaia:visualizer",
62
63
  "docker:build-push": "npm run docker:build && npm run docker:push",