@slycode/slycode 0.2.22 → 0.2.23
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/dist/bridge/api.d.ts +2 -1
- package/dist/bridge/api.js +114 -1
- package/dist/bridge/api.js.map +1 -1
- package/dist/bridge/git-utils.d.ts +9 -0
- package/dist/bridge/git-utils.js +49 -0
- package/dist/bridge/git-utils.js.map +1 -0
- package/dist/bridge/index.js +8 -2
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/response-store.d.ts +46 -0
- package/dist/bridge/response-store.js +95 -0
- package/dist/bridge/response-store.js.map +1 -0
- package/dist/bridge/session-manager.d.ts +33 -1
- package/dist/bridge/session-manager.js +185 -2
- package/dist/bridge/session-manager.js.map +1 -1
- package/dist/bridge/types.d.ts +37 -0
- package/dist/data/scaffold-templates/tutorial-project/documentation/kanban.json +1 -1
- package/dist/messaging/bridge-client.d.ts +4 -0
- package/dist/messaging/bridge-client.js +20 -1
- package/dist/messaging/bridge-client.js.map +1 -1
- package/dist/messaging/index.js +38 -10
- package/dist/messaging/index.js.map +1 -1
- package/dist/scripts/kanban.js +448 -2
- package/dist/store/actions/checkpoint.md +1 -1
- package/dist/store/actions/context.md +1 -1
- package/dist/store/actions/create-card.md +1 -1
- package/dist/store/actions/deep-design.md +13 -3
- package/dist/store/actions/design-requirements.md +11 -1
- package/dist/store/actions/explore.md +1 -1
- package/dist/store/actions/onboard.md +2 -4
- package/dist/store/actions/summarize.md +1 -1
- package/dist/store/skills/kanban/SKILL.md +77 -3
- package/dist/web/.next/BUILD_ID +1 -1
- package/dist/web/.next/app-path-routes-manifest.json +1 -0
- package/dist/web/.next/build-manifest.json +2 -2
- package/dist/web/.next/prerender-manifest.json +3 -3
- package/dist/web/.next/routes-manifest.json +6 -0
- package/dist/web/.next/server/app/_global-error.html +2 -2
- package/dist/web/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app/_not-found.html +1 -1
- package/dist/web/.next/server/app/_not-found.rsc +10 -10
- package/dist/web/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
- package/dist/web/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/dist/web/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- package/dist/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/dist/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/dist/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/.next/server/app/api/changelog/route/app-paths-manifest.json +3 -0
- package/dist/web/.next/server/app/api/changelog/route/build-manifest.json +11 -0
- package/dist/web/.next/server/app/api/changelog/route/server-reference-manifest.json +4 -0
- package/dist/web/.next/server/app/api/changelog/route.js +7 -0
- package/dist/web/.next/server/app/api/changelog/route.js.map +5 -0
- package/dist/web/.next/server/app/api/changelog/route.js.nft.json +1 -0
- package/dist/web/.next/server/app/api/changelog/route_client-reference-manifest.js +2 -0
- package/dist/web/.next/server/app/api/cli-assets/assistant/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/fix/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/import/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/preview/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/sync/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/updates/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/dashboard/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/file/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/git-status/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/kanban/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/kanban/stream/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/reorder/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/scheduler/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/search/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/invalidate/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/version-check/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app/project/[id]/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/project/[id]/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app-paths-manifest.json +1 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__a259539f._.js +3 -0
- package/dist/web/.next/server/chunks/_next-internal_server_app_api_changelog_route_actions_d6e239bf.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_18324462.js +1 -1
- package/dist/web/.next/server/chunks/src_lib_scheduler_ts_03988e3e._.js +1 -1
- package/dist/web/.next/server/chunks/src_lib_scheduler_ts_7120457c._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__1f5fc489._.js +4 -3
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__077f472c._.js → [root-of-the-server]__6183d28c._.js} +1 -1
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__bcbe4bf2._.js +4 -3
- package/dist/web/.next/server/chunks/ssr/src_components_Dashboard_tsx_efc4dc27._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/src_components_c4135402._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/src_contexts_VoiceContext_tsx_cfba7292._.js +1 -1
- package/dist/web/.next/server/pages/404.html +1 -1
- package/dist/web/.next/server/pages/500.html +2 -2
- package/dist/web/.next/server/server-reference-manifest.js +1 -1
- package/dist/web/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/.next/static/chunks/293449b828207656.css +1 -0
- package/dist/web/.next/static/chunks/{f55f3c8c1a52f80c.js → 3859477038c381ad.js} +1 -1
- package/dist/web/.next/static/chunks/{8415039c5941cf5c.js → 3a5721af09d1c753.js} +4 -3
- package/dist/web/.next/static/chunks/{8fb2a99c64580de7.js → 98311243e9a5a0ec.js} +1 -1
- package/dist/web/.next/static/chunks/{b8e0c1aeea4a14bc.js → a47f36b030917d1f.js} +1 -1
- package/dist/web/.next/static/chunks/d60c422421920130.js +5 -0
- package/dist/web/.next/static/chunks/{4049cceee6a49323.js → fa78afe3ceed998b.js} +1 -1
- package/dist/web/src/app/api/changelog/route.ts +45 -0
- package/dist/web/src/app/api/kanban/route.ts +52 -12
- package/dist/web/src/components/ActivityFeed.tsx +3 -0
- package/dist/web/src/components/BranchTab.tsx +115 -0
- package/dist/web/src/components/ChangelogModal.tsx +234 -0
- package/dist/web/src/components/Dashboard.tsx +11 -0
- package/dist/web/src/components/GlobalClaudePanel.tsx +6 -0
- package/dist/web/src/components/ProjectKanban.tsx +38 -8
- package/dist/web/src/components/VersionUpdateToast.tsx +6 -4
- package/dist/web/src/components/VoiceControlBar.tsx +1 -1
- package/dist/web/src/lib/scheduler.ts +2 -1
- package/dist/web/src/lib/types.ts +24 -0
- package/dist/web/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/templates/changelog.json +242 -0
- package/templates/kanban-seed.json +1 -1
- package/templates/store/actions/checkpoint.md +1 -1
- package/templates/store/actions/context.md +1 -1
- package/templates/store/actions/create-card.md +1 -1
- package/templates/store/actions/deep-design.md +13 -3
- package/templates/store/actions/design-requirements.md +11 -1
- package/templates/store/actions/explore.md +1 -1
- package/templates/store/actions/onboard.md +2 -4
- package/templates/store/actions/summarize.md +1 -1
- package/templates/store/skills/kanban/SKILL.md +77 -3
- package/templates/tutorial-project/documentation/kanban.json +1 -1
- package/templates/updates/actions/checkpoint.md +1 -1
- package/templates/updates/actions/context.md +1 -1
- package/templates/updates/actions/create-card.md +1 -1
- package/templates/updates/actions/deep-design.md +13 -3
- package/templates/updates/actions/design-requirements.md +11 -1
- package/templates/updates/actions/explore.md +1 -1
- package/templates/updates/actions/onboard.md +2 -4
- package/templates/updates/actions/summarize.md +1 -1
- package/templates/updates/skills/kanban/SKILL.md +77 -3
- package/dist/web/.next/static/chunks/18cfbdd7e977bb01.css +0 -1
- package/dist/web/.next/static/chunks/a0f5f9cdee8a22c1.js +0 -4
- /package/dist/web/.next/static/{b2V8jC3HBMi4vgm7Kie3H → aN-jqftQVvSm0qVskLybH}/_buildManifest.js +0 -0
- /package/dist/web/.next/static/{b2V8jC3HBMi4vgm7Kie3H → aN-jqftQVvSm0qVskLybH}/_clientMiddlewareManifest.json +0 -0
- /package/dist/web/.next/static/{b2V8jC3HBMi4vgm7Kie3H → aN-jqftQVvSm0qVskLybH}/_ssgManifest.js +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|
4
4
|
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
|
|
5
|
-
import type { ProjectWithBacklog, KanbanCard, KanbanStage, KanbanStages, BridgeStats, Priority } from '@/lib/types';
|
|
5
|
+
import type { ProjectWithBacklog, KanbanCard, KanbanStage, KanbanStages, BridgeStats, Priority, ChangedCard, CardChangeType } from '@/lib/types';
|
|
6
6
|
import { connectionManager } from '@/lib/connection-manager';
|
|
7
7
|
import { tabSync } from '@/lib/tab-sync';
|
|
8
8
|
import { usePolling } from '@/hooks/usePolling';
|
|
@@ -85,6 +85,8 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
85
85
|
const [activeCards, setActiveCards] = useState<Set<string>>(new Set());
|
|
86
86
|
const prevActiveCardsRef = useRef<Set<string>>(new Set());
|
|
87
87
|
const consumedCardParamRef = useRef<string | null>(null);
|
|
88
|
+
const editedCardIdsRef = useRef<Set<string>>(new Set());
|
|
89
|
+
const movedCardIdsRef = useRef<Set<string>>(new Set());
|
|
88
90
|
|
|
89
91
|
// Context menu state
|
|
90
92
|
const [contextMenu, setContextMenu] = useState<{ position: { x: number; y: number }; card: KanbanCard; stage: KanbanStage } | null>(null);
|
|
@@ -376,8 +378,8 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
376
378
|
setSaveStatus('saving');
|
|
377
379
|
isSavingRef.current = true;
|
|
378
380
|
try {
|
|
379
|
-
// Compute which cards actually changed vs the clean baseline
|
|
380
|
-
const
|
|
381
|
+
// Compute which cards actually changed vs the clean baseline, with typed changeset
|
|
382
|
+
const changedCards: ChangedCard[] = [];
|
|
381
383
|
const baselineCards = new Map<string, string>();
|
|
382
384
|
for (const stage of STAGE_ORDER) {
|
|
383
385
|
for (const card of cleanBaselineRef.current[stage] || []) {
|
|
@@ -389,29 +391,51 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
389
391
|
const baselineKey = baselineCards.get(card.id);
|
|
390
392
|
const currentKey = JSON.stringify(card) + '|' + stage;
|
|
391
393
|
if (baselineKey !== currentKey) {
|
|
392
|
-
|
|
394
|
+
if (editedCardIdsRef.current.has(card.id)) {
|
|
395
|
+
changedCards.push({ id: card.id, type: 'edit' }); // Edit wins over move
|
|
396
|
+
} else if (movedCardIdsRef.current.has(card.id)) {
|
|
397
|
+
changedCards.push({ id: card.id, type: 'move' });
|
|
398
|
+
}
|
|
399
|
+
// Untracked divergence (SSE timing, connection issues, normalizeOrder drift)
|
|
400
|
+
// — skip it. The server merge preserves disk truth for cards not in changedCards.
|
|
393
401
|
}
|
|
394
402
|
baselineCards.delete(card.id);
|
|
395
403
|
}
|
|
396
404
|
}
|
|
397
405
|
// Cards in baseline but not in current = deleted
|
|
398
406
|
for (const deletedId of baselineCards.keys()) {
|
|
399
|
-
|
|
407
|
+
changedCards.push({ id: deletedId, type: 'delete' });
|
|
400
408
|
}
|
|
401
409
|
|
|
410
|
+
// Clear tracking refs after building payload
|
|
411
|
+
editedCardIdsRef.current.clear();
|
|
412
|
+
movedCardIdsRef.current.clear();
|
|
413
|
+
|
|
402
414
|
const res = await fetch('/api/kanban', {
|
|
403
415
|
method: 'POST',
|
|
404
416
|
headers: { 'Content-Type': 'application/json' },
|
|
405
|
-
body: JSON.stringify({ projectId: project.id, stages: stagesToSave,
|
|
417
|
+
body: JSON.stringify({ projectId: project.id, stages: stagesToSave, changedCards }),
|
|
406
418
|
});
|
|
407
419
|
if (res.ok) {
|
|
408
420
|
const data = await res.json();
|
|
409
421
|
lastSaveTimestampRef.current = data.last_updated;
|
|
410
|
-
|
|
422
|
+
// Use server's merged+normalized stages as baseline (eliminates normalizeOrder drift)
|
|
423
|
+
const serverStages = data.stages;
|
|
424
|
+
if (serverStages) {
|
|
425
|
+
cleanBaselineRef.current = serverStages;
|
|
426
|
+
// Sync React state with server truth if no new user edits happened during save.
|
|
427
|
+
// Without this, baseline and stages diverge — cards the user never touched appear
|
|
428
|
+
// "changed" in the next save cycle and get reverted to stale frontend positions.
|
|
429
|
+
if (stagesEqual(stagesRef.current, stagesToSave)) {
|
|
430
|
+
setStages(serverStages);
|
|
431
|
+
}
|
|
432
|
+
} else {
|
|
433
|
+
cleanBaselineRef.current = stagesToSave;
|
|
434
|
+
}
|
|
411
435
|
// Only clear dirty if stages haven't changed during the save.
|
|
412
436
|
// If the user made edits while the save was in flight, stay dirty
|
|
413
437
|
// so SSE/polling won't overwrite their pending changes.
|
|
414
|
-
isDirtyRef.current = !stagesEqual(stagesRef.current,
|
|
438
|
+
isDirtyRef.current = !stagesEqual(stagesRef.current, cleanBaselineRef.current);
|
|
415
439
|
setSaveStatus('saved');
|
|
416
440
|
// Notify other tabs immediately
|
|
417
441
|
tabSync.broadcast('kanban-update', project.id);
|
|
@@ -544,6 +568,8 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
544
568
|
|
|
545
569
|
if (!selectedStage) return;
|
|
546
570
|
|
|
571
|
+
editedCardIdsRef.current.add(updatedCard.id);
|
|
572
|
+
|
|
547
573
|
// Update stages - selectedCard will be automatically derived from the updated stages
|
|
548
574
|
setStages((prev) => ({
|
|
549
575
|
...prev,
|
|
@@ -577,6 +603,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
577
603
|
};
|
|
578
604
|
|
|
579
605
|
const handleMoveCard = (cardId: string, newStage: KanbanStage, insertIndex?: number) => {
|
|
606
|
+
movedCardIdsRef.current.add(cardId);
|
|
580
607
|
setStages((prev) => {
|
|
581
608
|
// Find which stage the card is currently in
|
|
582
609
|
let sourceStage: KanbanStage | null = null;
|
|
@@ -695,6 +722,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
695
722
|
checked: p === card.priority,
|
|
696
723
|
disabled: p === card.priority,
|
|
697
724
|
onClick: () => {
|
|
725
|
+
editedCardIdsRef.current.add(card.id);
|
|
698
726
|
setStages((prev) => ({
|
|
699
727
|
...prev,
|
|
700
728
|
[stage]: prev[stage].map((c) =>
|
|
@@ -731,6 +759,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
731
759
|
disabled: !!card.automation,
|
|
732
760
|
onClick: () => {
|
|
733
761
|
if (card.automation) return;
|
|
762
|
+
editedCardIdsRef.current.add(card.id);
|
|
734
763
|
setStages((prev) => ({
|
|
735
764
|
...prev,
|
|
736
765
|
[stage]: prev[stage].map((c) =>
|
|
@@ -767,6 +796,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
767
796
|
checked: p === card.priority,
|
|
768
797
|
disabled: p === card.priority,
|
|
769
798
|
onClick: () => {
|
|
799
|
+
editedCardIdsRef.current.add(card.id);
|
|
770
800
|
setStages((prev) => ({
|
|
771
801
|
...prev,
|
|
772
802
|
[stage]: prev[stage].map((c) =>
|
|
@@ -53,12 +53,14 @@ export function VersionUpdateToast() {
|
|
|
53
53
|
/>
|
|
54
54
|
<span className="text-sm text-void-700 dark:text-void-300">
|
|
55
55
|
SlyCode <span className="font-medium text-neon-blue-500 dark:text-neon-blue-400">v{info.latest}</span> available
|
|
56
|
-
<span className="text-void-500 dark:text-void-400"> (current: v{info.current})</span>
|
|
57
56
|
</span>
|
|
58
57
|
</div>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
<div className="flex items-center gap-1.5">
|
|
59
|
+
<span className="text-xs text-void-500 dark:text-void-400">run in terminal:</span>
|
|
60
|
+
<code className="rounded bg-void-100 px-1.5 py-0.5 text-xs text-void-600 dark:bg-void-800 dark:text-void-400">
|
|
61
|
+
slycode update
|
|
62
|
+
</code>
|
|
63
|
+
</div>
|
|
62
64
|
<button
|
|
63
65
|
onClick={handleDismiss}
|
|
64
66
|
className="ml-1 rounded p-0.5 text-void-400 transition-colors hover:bg-void-200 hover:text-void-600 dark:text-void-500 dark:hover:bg-void-800 dark:hover:text-void-300"
|
|
@@ -45,7 +45,7 @@ export function VoiceControlBar({
|
|
|
45
45
|
onClick={onRecord}
|
|
46
46
|
disabled={disabled}
|
|
47
47
|
className="rounded-md border border-void-400/30 bg-void-200/50 p-1.5 text-void-500 transition-all hover:border-red-400/40 hover:bg-red-400/10 hover:text-red-400 disabled:opacity-50 dark:border-void-500/25 dark:bg-void-700/50 dark:text-void-400 dark:hover:border-red-400/40 dark:hover:bg-red-400/10 dark:hover:text-red-400"
|
|
48
|
-
title="Start recording
|
|
48
|
+
title="Start recording [Ctrl+.]"
|
|
49
49
|
>
|
|
50
50
|
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
51
51
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" />
|
|
@@ -666,7 +666,8 @@ async function checkAutomations(): Promise<void> {
|
|
|
666
666
|
result.error.includes('Session create failed') ||
|
|
667
667
|
result.error.includes('Session stopped') ||
|
|
668
668
|
result.error.includes('Input failed') ||
|
|
669
|
-
result.error.includes('No automation config')
|
|
669
|
+
result.error.includes('No automation config') ||
|
|
670
|
+
result.error.includes('No activity detected')
|
|
670
671
|
);
|
|
671
672
|
if (isHardFailure) {
|
|
672
673
|
await sendErrorNotification(card.title, result.error || 'Unknown error', result.sessionName);
|
|
@@ -128,6 +128,13 @@ export interface KanbanStages {
|
|
|
128
128
|
done: KanbanCard[];
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
export type CardChangeType = 'move' | 'edit' | 'create' | 'delete';
|
|
132
|
+
|
|
133
|
+
export interface ChangedCard {
|
|
134
|
+
id: string;
|
|
135
|
+
type: CardChangeType;
|
|
136
|
+
}
|
|
137
|
+
|
|
131
138
|
export interface KanbanBoard {
|
|
132
139
|
project_id: string;
|
|
133
140
|
stages: KanbanStages;
|
|
@@ -163,6 +170,23 @@ export interface FeatureEntry {
|
|
|
163
170
|
projectId?: string;
|
|
164
171
|
}
|
|
165
172
|
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Changelog Types
|
|
175
|
+
// ============================================================================
|
|
176
|
+
|
|
177
|
+
export type ChangelogChangeType = 'feature' | 'bugfix' | 'improvement' | 'chore';
|
|
178
|
+
|
|
179
|
+
export interface ChangelogChange {
|
|
180
|
+
type: ChangelogChangeType;
|
|
181
|
+
description: string;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ChangelogVersion {
|
|
185
|
+
version: string;
|
|
186
|
+
date: string; // YYYY-MM-DD
|
|
187
|
+
changes: ChangelogChange[];
|
|
188
|
+
}
|
|
189
|
+
|
|
166
190
|
// ============================================================================
|
|
167
191
|
// Questionnaire Types (per design doc section 3.3)
|
|
168
192
|
// ============================================================================
|