@pennyfarthing/core 11.1.0 → 11.2.0
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 +8 -8
- package/package.json +16 -14
- package/packages/core/dist/cli/utils/constants.d.ts +1 -1
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/constants.js +2 -1
- package/packages/core/dist/cli/utils/constants.js.map +1 -1
- package/packages/core/dist/consultation/dialogue-manager.d.ts +75 -0
- package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.js +334 -0
- package/packages/core/dist/consultation/dialogue-manager.js.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.test.d.ts +19 -0
- package/packages/core/dist/consultation/dialogue-manager.test.d.ts.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.test.js +444 -0
- package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -0
- package/packages/core/dist/server/api/git.d.ts +13 -1
- package/packages/core/dist/server/api/git.d.ts.map +1 -1
- package/packages/core/dist/server/api/git.js +53 -34
- package/packages/core/dist/server/api/git.js.map +1 -1
- package/packages/core/dist/server/otlp-receiver.d.ts +16 -11
- package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
- package/packages/core/dist/server/otlp-receiver.js +185 -24
- package/packages/core/dist/server/otlp-receiver.js.map +1 -1
- package/packages/core/dist/server/otlp-receiver.test.d.ts +21 -0
- package/packages/core/dist/server/otlp-receiver.test.d.ts.map +1 -0
- package/packages/core/dist/server/otlp-receiver.test.js +446 -0
- package/packages/core/dist/server/otlp-receiver.test.js.map +1 -0
- package/packages/core/dist/shared/portrait-resolver.d.ts +9 -0
- package/packages/core/dist/shared/portrait-resolver.d.ts.map +1 -1
- package/packages/core/dist/shared/portrait-resolver.js +27 -0
- package/packages/core/dist/shared/portrait-resolver.js.map +1 -1
- package/packages/core/dist/shared/portrait-resolver.test.js +47 -1
- package/packages/core/dist/shared/portrait-resolver.test.js.map +1 -1
- package/packages/core/dist/shared/skill-search.test.js +2 -2
- package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts +13 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts.map +1 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.js +126 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.js.map +1 -0
- package/pennyfarthing-dist/agents/dev.md +1 -1
- package/pennyfarthing-dist/agents/reviewer.md +1 -1
- package/pennyfarthing-dist/agents/sm-setup.md +1 -1
- package/pennyfarthing-dist/agents/sm.md +2 -2
- package/pennyfarthing-dist/agents/tea.md +1 -1
- package/pennyfarthing-dist/agents/testing-runner.md +2 -1
- package/pennyfarthing-dist/commands/pf-chore.md +2 -2
- package/pennyfarthing-dist/commands/pf-standalone.md +7 -2
- package/pennyfarthing-dist/guides/agent-behavior.md +1 -1
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +1 -1
- package/pennyfarthing-dist/guides/bikerack.md +3 -3
- package/pennyfarthing-dist/guides/hooks.md +1 -1
- package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
- package/pennyfarthing-dist/guides/xml-tags.md +2 -2
- package/pennyfarthing-dist/scripts/README.md +1 -1
- package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
- package/pennyfarthing-dist/scripts/core/check-context.sh +1 -1
- package/pennyfarthing-dist/scripts/core/dialogue-manager.sh +322 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
- package/pennyfarthing-dist/scripts/git/README.md +24 -14
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +5 -266
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +5 -151
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +6 -144
- package/pennyfarthing-dist/scripts/git/release.sh +0 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +5 -496
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/README.md +1 -1
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +1 -1
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/dispatcher-template.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +9 -11
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +1 -1
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
- package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-tandem-portraits.sh +76 -0
- package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +4 -221
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +5 -13
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +4 -123
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +4 -33
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +4 -156
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +4 -131
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +4 -249
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +4 -160
- package/pennyfarthing-dist/skills/pf-bc/usage.md +1 -1
- package/pennyfarthing-dist/skills/pf-jira/examples.md +5 -2
- package/pennyfarthing-dist/skills/pf-story/scripts/create-story.sh +0 -0
- package/pennyfarthing-dist/skills/pf-story/scripts/size-story.sh +0 -0
- package/pennyfarthing-dist/skills/pf-story/scripts/story-template.sh +0 -0
- package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -16
- package/pennyfarthing-dist/skills/pf-workflow/skill.md +9 -12
- package/pennyfarthing-dist/skills/pf-workflow/usage.md +33 -8
- package/pennyfarthing-dist/workflows/bdd-tandem.yaml +18 -6
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
- package/pennyfarthing-dist/workflows/review-tandem.yaml +65 -0
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +16 -8
- package/pennyfarthing_scripts/CLAUDE.md +26 -4
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/cli.py +3 -5
- package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/portrait.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/background_panel.py +86 -5
- package/pennyfarthing_scripts/bikerack/base_panel.py +62 -0
- package/pennyfarthing_scripts/bikerack/changed_panel.py +32 -28
- package/pennyfarthing_scripts/bikerack/cli.py +10 -11
- package/pennyfarthing_scripts/bikerack/debug_panel.py +31 -1
- package/pennyfarthing_scripts/bikerack/diffs_panel.py +74 -17
- package/pennyfarthing_scripts/bikerack/git_panel.py +103 -33
- package/pennyfarthing_scripts/bikerack/launcher.py +15 -15
- package/pennyfarthing_scripts/bikerack/progress_panel.py +315 -0
- package/pennyfarthing_scripts/bikerack/sprint_panel.py +158 -26
- package/pennyfarthing_scripts/bikerack/tui.py +336 -30
- package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
- package/pennyfarthing_scripts/cli.py +37 -65
- package/pennyfarthing_scripts/consultation/__init__.py +1 -0
- package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/cli.py +149 -0
- package/pennyfarthing_scripts/consultation/dialogue_manager.py +417 -0
- package/pennyfarthing_scripts/context.py +3 -3
- package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__init__.py +12 -1
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/hooks_installer.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/worktree.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/create_branches.py +3 -4
- package/pennyfarthing_scripts/git/hooks_installer.py +152 -0
- package/pennyfarthing_scripts/git/repos.py +196 -0
- package/pennyfarthing_scripts/git/status_all.py +27 -11
- package/pennyfarthing_scripts/git/worktree.py +302 -0
- package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git_group/cli.py +143 -40
- package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/complete_phase.py +12 -0
- package/pennyfarthing_scripts/handoff/resolve_gate.py +5 -14
- package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing_scripts/hooks.py +3 -17
- package/pennyfarthing_scripts/pretooluse_hook.py +1 -1
- package/pennyfarthing_scripts/prime/__pycache__/heatmap.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/heatmap.py +655 -0
- package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/session_start_hook.py +1 -1
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/loader.py +15 -1
- package/pennyfarthing_scripts/sprint/story_finish.py +14 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/test_bikerack.py +51 -51
- package/pennyfarthing_scripts/tests/test_dialogue_manager.py +811 -0
- package/pennyfarthing_scripts/tests/test_handoff_cli.py +16 -11
- package/pennyfarthing_scripts/tests/test_workflow_check.py +2 -3
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/tandem_awareness.py +254 -0
- package/pennyfarthing_scripts/validate/cli.py +17 -5
- package/pennyfarthing_scripts/workflow/__init__.py +40 -0
- package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/cli.py +1099 -0
- package/pennyfarthing_scripts/workflow/helpers.py +241 -0
- package/pennyfarthing_scripts/{workflow.py → workflow/scale.py} +0 -104
- package/pennyfarthing_scripts/workflow/state.py +112 -0
- package/scripts/README.md +41 -0
- package/pennyfarthing-dist/skills/pf-workflow/scripts/list-workflows.sh +0 -91
- package/pennyfarthing-dist/skills/pf-workflow/scripts/resume-workflow.sh +0 -163
- package/pennyfarthing-dist/skills/pf-workflow/scripts/show-workflow.sh +0 -138
- package/pennyfarthing-dist/skills/pf-workflow/scripts/start-workflow.sh +0 -273
- package/pennyfarthing-dist/skills/pf-workflow/scripts/workflow-status.sh +0 -167
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 86-3: Dialogue File Management
|
|
3
|
+
*
|
|
4
|
+
* RED state tests for the dialogue file persistence layer.
|
|
5
|
+
* Dialogue files record all consultation exchanges between tandem agents,
|
|
6
|
+
* following the format defined in ADR-0012 (lines 156-195).
|
|
7
|
+
*
|
|
8
|
+
* ACs covered:
|
|
9
|
+
* AC1: Dialogue file created at .session/{story-id}-dialogue.md on first consultation
|
|
10
|
+
* AC2: Each exchange appended with: timestamp, agents, question, response, outcome
|
|
11
|
+
* AC3: Outcome tracked: applied / deferred / rejected
|
|
12
|
+
* AC4: Summary section auto-generated: total exchanges, key decisions, time in tandem
|
|
13
|
+
* AC5: Dialogue file archived alongside session file on story completion
|
|
14
|
+
* AC6: Dialogue file readable by Reviewer for audit
|
|
15
|
+
*
|
|
16
|
+
* Run with: npm test
|
|
17
|
+
*/
|
|
18
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
19
|
+
import assert from 'node:assert';
|
|
20
|
+
import fs from 'node:fs';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import os from 'node:os';
|
|
23
|
+
import { createDialogueContent, formatExchange, parseDialogueExchanges, generateSummary, appendExchangeToFile, updateOutcomeInFile, refreshSummary, archiveDialogue, } from './dialogue-manager.js';
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Test Fixtures
|
|
26
|
+
// =============================================================================
|
|
27
|
+
const VALID_HEADER = {
|
|
28
|
+
storyId: '86-3',
|
|
29
|
+
workflow: 'tdd-tandem',
|
|
30
|
+
leader: 'dev',
|
|
31
|
+
leaderCharacter: 'Jack Torrance',
|
|
32
|
+
partner: 'architect',
|
|
33
|
+
partnerCharacter: 'Andy Dufresne',
|
|
34
|
+
startedAt: '2026-02-16T10:00:00Z',
|
|
35
|
+
};
|
|
36
|
+
const VALID_EXCHANGE = {
|
|
37
|
+
number: 1,
|
|
38
|
+
timestamp: '10:05',
|
|
39
|
+
leader: 'dev',
|
|
40
|
+
partner: 'architect',
|
|
41
|
+
question: 'Should we use a class or functional approach for the dialogue manager?',
|
|
42
|
+
recommendation: 'Use pure functions — they are easier to test and align with the existing consultation-protocol.ts pattern',
|
|
43
|
+
confidence: 'high',
|
|
44
|
+
};
|
|
45
|
+
const SECOND_EXCHANGE = {
|
|
46
|
+
number: 2,
|
|
47
|
+
timestamp: '10:20',
|
|
48
|
+
leader: 'dev',
|
|
49
|
+
partner: 'architect',
|
|
50
|
+
question: 'Should the shell wrapper call Node.js or use pure bash?',
|
|
51
|
+
recommendation: 'Pure bash for the shell wrapper — keeps it dependency-free and consistent with other core scripts',
|
|
52
|
+
confidence: 'medium',
|
|
53
|
+
outcome: 'applied',
|
|
54
|
+
outcomeNote: 'Implemented with sed/awk',
|
|
55
|
+
};
|
|
56
|
+
// =============================================================================
|
|
57
|
+
// Test Helpers
|
|
58
|
+
// =============================================================================
|
|
59
|
+
let tmpDir;
|
|
60
|
+
function setupTmpDir() {
|
|
61
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'dialogue-test-'));
|
|
62
|
+
return dir;
|
|
63
|
+
}
|
|
64
|
+
function cleanupTmpDir(dir) {
|
|
65
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
66
|
+
}
|
|
67
|
+
// =============================================================================
|
|
68
|
+
// AC1: Dialogue file created at .session/{story-id}-dialogue.md
|
|
69
|
+
// =============================================================================
|
|
70
|
+
describe('86-3: Dialogue File Management', () => {
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
tmpDir = setupTmpDir();
|
|
73
|
+
});
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
cleanupTmpDir(tmpDir);
|
|
76
|
+
});
|
|
77
|
+
describe('AC1: Dialogue file creation on first consultation', () => {
|
|
78
|
+
it('should create initial dialogue content with correct header', () => {
|
|
79
|
+
const content = createDialogueContent(VALID_HEADER);
|
|
80
|
+
assert.ok(content.includes('# Tandem Dialogue: 86-3'), 'Must include story ID in title');
|
|
81
|
+
assert.ok(content.includes('**Workflow:** tdd-tandem'), 'Must include workflow');
|
|
82
|
+
assert.ok(content.includes('**Leader:** dev'), 'Must include leader agent');
|
|
83
|
+
assert.ok(content.includes('**Partner:** architect'), 'Must include partner agent');
|
|
84
|
+
assert.ok(content.includes('**Started:** 2026-02-16T10:00:00Z'), 'Must include start timestamp');
|
|
85
|
+
});
|
|
86
|
+
it('should include character names when provided', () => {
|
|
87
|
+
const content = createDialogueContent(VALID_HEADER);
|
|
88
|
+
assert.ok(content.includes('Jack Torrance'), 'Must include leader character');
|
|
89
|
+
assert.ok(content.includes('Andy Dufresne'), 'Must include partner character');
|
|
90
|
+
});
|
|
91
|
+
it('should handle missing character names gracefully', () => {
|
|
92
|
+
const headerNoChars = {
|
|
93
|
+
...VALID_HEADER,
|
|
94
|
+
leaderCharacter: undefined,
|
|
95
|
+
partnerCharacter: undefined,
|
|
96
|
+
};
|
|
97
|
+
const content = createDialogueContent(headerNoChars);
|
|
98
|
+
assert.ok(content.includes('**Leader:** dev'), 'Must include leader without character');
|
|
99
|
+
assert.ok(content.includes('**Partner:** architect'), 'Must include partner without character');
|
|
100
|
+
});
|
|
101
|
+
it('should include empty summary section placeholder', () => {
|
|
102
|
+
const content = createDialogueContent(VALID_HEADER);
|
|
103
|
+
assert.ok(content.includes('## Summary'), 'Must include Summary section');
|
|
104
|
+
assert.ok(content.includes('**Total exchanges:** 0'), 'Must include zero count initially');
|
|
105
|
+
});
|
|
106
|
+
it('should create file on first appendExchangeToFile when file missing', async () => {
|
|
107
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
108
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
109
|
+
assert.ok(fs.existsSync(dialoguePath), 'File must be created automatically on first append');
|
|
110
|
+
});
|
|
111
|
+
it('should create file with header and first exchange', async () => {
|
|
112
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
113
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
114
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
115
|
+
assert.ok(content.includes('# Tandem Dialogue: 86-3'), 'Must include header');
|
|
116
|
+
assert.ok(content.includes('## Exchange 1'), 'Must include first exchange');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// AC2: Each exchange appended with timestamp, agents, question, response, outcome
|
|
121
|
+
// =============================================================================
|
|
122
|
+
describe('AC2: Exchange format and appending', () => {
|
|
123
|
+
it('should format exchange with timestamp and agent direction', () => {
|
|
124
|
+
const formatted = formatExchange(VALID_EXCHANGE);
|
|
125
|
+
assert.ok(formatted.includes('## Exchange 1'), 'Must include exchange number');
|
|
126
|
+
assert.ok(formatted.includes('**[10:05] dev → architect**'), 'Must include timestamp and agent direction');
|
|
127
|
+
});
|
|
128
|
+
it('should include question as blockquote', () => {
|
|
129
|
+
const formatted = formatExchange(VALID_EXCHANGE);
|
|
130
|
+
assert.ok(formatted.includes('> Should we use a class or functional approach'), 'Must include question as blockquote');
|
|
131
|
+
});
|
|
132
|
+
it('should include response from partner', () => {
|
|
133
|
+
const formatted = formatExchange(VALID_EXCHANGE);
|
|
134
|
+
assert.ok(formatted.includes('**[10:05] architect:**'), 'Must include partner response header');
|
|
135
|
+
assert.ok(formatted.includes('Use pure functions'), 'Must include recommendation text');
|
|
136
|
+
});
|
|
137
|
+
it('should include confidence level', () => {
|
|
138
|
+
const formatted = formatExchange(VALID_EXCHANGE);
|
|
139
|
+
assert.ok(formatted.includes('high'), 'Must include confidence level');
|
|
140
|
+
});
|
|
141
|
+
it('should include outcome when present', () => {
|
|
142
|
+
const formatted = formatExchange(SECOND_EXCHANGE);
|
|
143
|
+
assert.ok(formatted.includes('**Outcome:** applied'), 'Must include outcome');
|
|
144
|
+
assert.ok(formatted.includes('Implemented with sed/awk'), 'Must include outcome note');
|
|
145
|
+
});
|
|
146
|
+
it('should show pending outcome when not yet decided', () => {
|
|
147
|
+
const formatted = formatExchange(VALID_EXCHANGE);
|
|
148
|
+
assert.ok(formatted.includes('**Outcome:** _pending_'), 'Must show pending when no outcome set');
|
|
149
|
+
});
|
|
150
|
+
it('should append multiple exchanges sequentially', async () => {
|
|
151
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
152
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
153
|
+
await appendExchangeToFile(dialoguePath, SECOND_EXCHANGE);
|
|
154
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
155
|
+
assert.ok(content.includes('## Exchange 1'), 'Must have exchange 1');
|
|
156
|
+
assert.ok(content.includes('## Exchange 2'), 'Must have exchange 2');
|
|
157
|
+
});
|
|
158
|
+
it('should place exchanges before summary section', async () => {
|
|
159
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
160
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
161
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
162
|
+
const exchangeIdx = content.indexOf('## Exchange 1');
|
|
163
|
+
const summaryIdx = content.indexOf('## Summary');
|
|
164
|
+
assert.ok(exchangeIdx < summaryIdx, 'Exchanges must appear before summary');
|
|
165
|
+
});
|
|
166
|
+
it('should separate exchanges with horizontal rules', () => {
|
|
167
|
+
const formatted = formatExchange(VALID_EXCHANGE);
|
|
168
|
+
assert.ok(formatted.includes('---'), 'Must include separator');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
// =============================================================================
|
|
172
|
+
// AC3: Outcome tracked: applied / deferred / rejected
|
|
173
|
+
// =============================================================================
|
|
174
|
+
describe('AC3: Outcome tracking', () => {
|
|
175
|
+
it('should update outcome to applied', async () => {
|
|
176
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
177
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
178
|
+
const result = await updateOutcomeInFile(dialoguePath, 1, 'applied', 'Used pure functions');
|
|
179
|
+
assert.strictEqual(result.success, true, 'Update should succeed');
|
|
180
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
181
|
+
assert.ok(content.includes('**Outcome:** applied'), 'Must update outcome to applied');
|
|
182
|
+
assert.ok(content.includes('Used pure functions'), 'Must include outcome note');
|
|
183
|
+
});
|
|
184
|
+
it('should update outcome to deferred', async () => {
|
|
185
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
186
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
187
|
+
await updateOutcomeInFile(dialoguePath, 1, 'deferred', 'Revisit in next phase');
|
|
188
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
189
|
+
assert.ok(content.includes('**Outcome:** deferred'), 'Must update outcome to deferred');
|
|
190
|
+
});
|
|
191
|
+
it('should update outcome to rejected', async () => {
|
|
192
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
193
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
194
|
+
await updateOutcomeInFile(dialoguePath, 1, 'rejected', 'Went with class approach instead');
|
|
195
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
196
|
+
assert.ok(content.includes('**Outcome:** rejected'), 'Must update outcome to rejected');
|
|
197
|
+
});
|
|
198
|
+
it('should update outcome without note', async () => {
|
|
199
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
200
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
201
|
+
const result = await updateOutcomeInFile(dialoguePath, 1, 'applied');
|
|
202
|
+
assert.strictEqual(result.success, true);
|
|
203
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
204
|
+
assert.ok(content.includes('**Outcome:** applied'), 'Must update outcome without note');
|
|
205
|
+
});
|
|
206
|
+
it('should fail for non-existent exchange number', async () => {
|
|
207
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
208
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
209
|
+
const result = await updateOutcomeInFile(dialoguePath, 99, 'applied');
|
|
210
|
+
assert.strictEqual(result.success, false, 'Should fail for missing exchange');
|
|
211
|
+
assert.ok(result.error?.includes('99'), 'Error must mention exchange number');
|
|
212
|
+
});
|
|
213
|
+
it('should fail for non-existent file', async () => {
|
|
214
|
+
const dialoguePath = path.join(tmpDir, 'nonexistent-dialogue.md');
|
|
215
|
+
const result = await updateOutcomeInFile(dialoguePath, 1, 'applied');
|
|
216
|
+
assert.strictEqual(result.success, false, 'Should fail for missing file');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
// =============================================================================
|
|
220
|
+
// AC4: Summary auto-generated with total exchanges, key decisions, time
|
|
221
|
+
// =============================================================================
|
|
222
|
+
describe('AC4: Summary generation', () => {
|
|
223
|
+
it('should generate summary with total exchange count', () => {
|
|
224
|
+
const exchanges = [VALID_EXCHANGE, SECOND_EXCHANGE];
|
|
225
|
+
const summary = generateSummary(exchanges, '2026-02-16T10:00:00Z');
|
|
226
|
+
assert.ok(summary.includes('**Total exchanges:** 2'), 'Must include exchange count');
|
|
227
|
+
});
|
|
228
|
+
it('should generate summary with key decisions from applied outcomes', () => {
|
|
229
|
+
const exchanges = [
|
|
230
|
+
{ ...VALID_EXCHANGE, outcome: 'applied', outcomeNote: 'Went with pure functions' },
|
|
231
|
+
{ ...SECOND_EXCHANGE, outcome: 'applied', outcomeNote: 'Implemented with sed/awk' },
|
|
232
|
+
];
|
|
233
|
+
const summary = generateSummary(exchanges, '2026-02-16T10:00:00Z');
|
|
234
|
+
assert.ok(summary.includes('Went with pure functions'), 'Must include first applied decision');
|
|
235
|
+
assert.ok(summary.includes('Implemented with sed/awk'), 'Must include second applied decision');
|
|
236
|
+
});
|
|
237
|
+
it('should not include rejected outcomes in key decisions', () => {
|
|
238
|
+
const exchanges = [
|
|
239
|
+
{ ...VALID_EXCHANGE, outcome: 'rejected', outcomeNote: 'Did not adopt this' },
|
|
240
|
+
{ ...SECOND_EXCHANGE, outcome: 'applied', outcomeNote: 'Adopted this one' },
|
|
241
|
+
];
|
|
242
|
+
const summary = generateSummary(exchanges, '2026-02-16T10:00:00Z');
|
|
243
|
+
assert.ok(!summary.includes('Did not adopt this'), 'Must not include rejected decisions');
|
|
244
|
+
assert.ok(summary.includes('Adopted this one'), 'Must include applied decisions');
|
|
245
|
+
});
|
|
246
|
+
it('should calculate time in tandem from exchanges', () => {
|
|
247
|
+
const exchanges = [
|
|
248
|
+
{ ...VALID_EXCHANGE, timestamp: '10:05' },
|
|
249
|
+
{ ...SECOND_EXCHANGE, timestamp: '10:35' },
|
|
250
|
+
];
|
|
251
|
+
const summary = generateSummary(exchanges, '2026-02-16T10:00:00Z');
|
|
252
|
+
assert.ok(summary.includes('**Time in tandem:**'), 'Must include time in tandem');
|
|
253
|
+
// Time should span from first to last exchange: 30 min
|
|
254
|
+
assert.ok(summary.includes('30m'), 'Must calculate duration from exchange timestamps');
|
|
255
|
+
});
|
|
256
|
+
it('should handle single exchange for time calculation', () => {
|
|
257
|
+
const exchanges = [VALID_EXCHANGE];
|
|
258
|
+
const summary = generateSummary(exchanges, '2026-02-16T10:00:00Z');
|
|
259
|
+
assert.ok(summary.includes('**Time in tandem:**'), 'Must include time even for single exchange');
|
|
260
|
+
});
|
|
261
|
+
it('should handle exchanges with no applied outcomes', () => {
|
|
262
|
+
const exchanges = [
|
|
263
|
+
{ ...VALID_EXCHANGE, outcome: 'deferred' },
|
|
264
|
+
];
|
|
265
|
+
const summary = generateSummary(exchanges, '2026-02-16T10:00:00Z');
|
|
266
|
+
assert.ok(summary.includes('**Key decisions:**'), 'Must include key decisions heading');
|
|
267
|
+
assert.ok(summary.includes('None'), 'Must show None when no decisions applied');
|
|
268
|
+
});
|
|
269
|
+
it('should refresh summary in existing file', async () => {
|
|
270
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
271
|
+
// Create file with exchange that has outcome
|
|
272
|
+
const exchangeWithOutcome = {
|
|
273
|
+
...VALID_EXCHANGE,
|
|
274
|
+
outcome: 'applied',
|
|
275
|
+
outcomeNote: 'Adopted functional approach',
|
|
276
|
+
};
|
|
277
|
+
await appendExchangeToFile(dialoguePath, exchangeWithOutcome, VALID_HEADER);
|
|
278
|
+
const result = await refreshSummary(dialoguePath);
|
|
279
|
+
assert.strictEqual(result.success, true, 'Refresh should succeed');
|
|
280
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
281
|
+
assert.ok(content.includes('**Total exchanges:** 1'), 'Summary must show updated count');
|
|
282
|
+
assert.ok(content.includes('Adopted functional approach'), 'Summary must include applied decision');
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
// =============================================================================
|
|
286
|
+
// AC5: Dialogue file archived alongside session file on story completion
|
|
287
|
+
// =============================================================================
|
|
288
|
+
describe('AC5: Dialogue archival', () => {
|
|
289
|
+
it('should copy dialogue to archive directory', async () => {
|
|
290
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
291
|
+
const archiveDir = path.join(tmpDir, 'archive');
|
|
292
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
293
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
294
|
+
const result = await archiveDialogue({
|
|
295
|
+
dialoguePath,
|
|
296
|
+
archiveDir,
|
|
297
|
+
jiraKey: 'MSSCI-15200',
|
|
298
|
+
});
|
|
299
|
+
assert.strictEqual(result.success, true, 'Archive should succeed');
|
|
300
|
+
const archivePath = path.join(archiveDir, 'MSSCI-15200-dialogue.md');
|
|
301
|
+
assert.ok(fs.existsSync(archivePath), 'Archived file must exist with Jira key prefix');
|
|
302
|
+
});
|
|
303
|
+
it('should use story ID when no Jira key provided', async () => {
|
|
304
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
305
|
+
const archiveDir = path.join(tmpDir, 'archive');
|
|
306
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
307
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
308
|
+
const result = await archiveDialogue({
|
|
309
|
+
dialoguePath,
|
|
310
|
+
archiveDir,
|
|
311
|
+
storyId: '86-3',
|
|
312
|
+
});
|
|
313
|
+
assert.strictEqual(result.success, true);
|
|
314
|
+
const archivePath = path.join(archiveDir, '86-3-dialogue.md');
|
|
315
|
+
assert.ok(fs.existsSync(archivePath), 'Archived file must exist with story ID prefix');
|
|
316
|
+
});
|
|
317
|
+
it('should preserve file content in archive', async () => {
|
|
318
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
319
|
+
const archiveDir = path.join(tmpDir, 'archive');
|
|
320
|
+
fs.mkdirSync(archiveDir, { recursive: true });
|
|
321
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
322
|
+
const original = fs.readFileSync(dialoguePath, 'utf-8');
|
|
323
|
+
await archiveDialogue({ dialoguePath, archiveDir, jiraKey: 'MSSCI-15200' });
|
|
324
|
+
const archived = fs.readFileSync(path.join(archiveDir, 'MSSCI-15200-dialogue.md'), 'utf-8');
|
|
325
|
+
assert.strictEqual(archived, original, 'Archived content must match original');
|
|
326
|
+
});
|
|
327
|
+
it('should create archive directory if it does not exist', async () => {
|
|
328
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
329
|
+
const archiveDir = path.join(tmpDir, 'new-archive');
|
|
330
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
331
|
+
const result = await archiveDialogue({
|
|
332
|
+
dialoguePath,
|
|
333
|
+
archiveDir,
|
|
334
|
+
jiraKey: 'MSSCI-15200',
|
|
335
|
+
});
|
|
336
|
+
assert.strictEqual(result.success, true);
|
|
337
|
+
assert.ok(fs.existsSync(archiveDir), 'Archive dir must be created');
|
|
338
|
+
});
|
|
339
|
+
it('should fail gracefully when source file does not exist', async () => {
|
|
340
|
+
const dialoguePath = path.join(tmpDir, 'nonexistent-dialogue.md');
|
|
341
|
+
const archiveDir = path.join(tmpDir, 'archive');
|
|
342
|
+
const result = await archiveDialogue({
|
|
343
|
+
dialoguePath,
|
|
344
|
+
archiveDir,
|
|
345
|
+
jiraKey: 'MSSCI-15200',
|
|
346
|
+
});
|
|
347
|
+
assert.strictEqual(result.success, false, 'Should fail for missing source');
|
|
348
|
+
assert.ok(result.error, 'Must include error message');
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
// =============================================================================
|
|
352
|
+
// AC6: Dialogue file readable by Reviewer for audit
|
|
353
|
+
// =============================================================================
|
|
354
|
+
describe('AC6: Readable format for audit', () => {
|
|
355
|
+
it('should produce well-formed markdown', () => {
|
|
356
|
+
const content = createDialogueContent(VALID_HEADER);
|
|
357
|
+
// Check basic markdown structure
|
|
358
|
+
assert.ok(content.startsWith('# Tandem Dialogue:'), 'Must start with H1');
|
|
359
|
+
assert.ok(content.includes('---'), 'Must include horizontal rules');
|
|
360
|
+
assert.ok(content.includes('## Summary'), 'Must include H2 Summary');
|
|
361
|
+
});
|
|
362
|
+
it('should parse exchanges back from generated content', async () => {
|
|
363
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
364
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
365
|
+
await appendExchangeToFile(dialoguePath, SECOND_EXCHANGE);
|
|
366
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
367
|
+
const parsed = parseDialogueExchanges(content);
|
|
368
|
+
assert.strictEqual(parsed.length, 2, 'Must parse both exchanges');
|
|
369
|
+
assert.strictEqual(parsed[0].number, 1);
|
|
370
|
+
assert.strictEqual(parsed[1].number, 2);
|
|
371
|
+
});
|
|
372
|
+
it('should parse exchange fields correctly', async () => {
|
|
373
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
374
|
+
await appendExchangeToFile(dialoguePath, SECOND_EXCHANGE, VALID_HEADER);
|
|
375
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
376
|
+
const parsed = parseDialogueExchanges(content);
|
|
377
|
+
assert.strictEqual(parsed.length, 1);
|
|
378
|
+
assert.strictEqual(parsed[0].leader, 'dev');
|
|
379
|
+
assert.strictEqual(parsed[0].partner, 'architect');
|
|
380
|
+
assert.strictEqual(parsed[0].timestamp, '10:20');
|
|
381
|
+
assert.strictEqual(parsed[0].outcome, 'applied');
|
|
382
|
+
});
|
|
383
|
+
it('should parse exchanges with pending outcome', async () => {
|
|
384
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
385
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
386
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
387
|
+
const parsed = parseDialogueExchanges(content);
|
|
388
|
+
assert.strictEqual(parsed[0].outcome, undefined, 'Pending outcome should parse as undefined');
|
|
389
|
+
});
|
|
390
|
+
it('should produce content that round-trips through parse', async () => {
|
|
391
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
392
|
+
const exchangeWithOutcome = {
|
|
393
|
+
...VALID_EXCHANGE,
|
|
394
|
+
outcome: 'applied',
|
|
395
|
+
outcomeNote: 'Adopted this approach',
|
|
396
|
+
};
|
|
397
|
+
await appendExchangeToFile(dialoguePath, exchangeWithOutcome, VALID_HEADER);
|
|
398
|
+
const content = fs.readFileSync(dialoguePath, 'utf-8');
|
|
399
|
+
const parsed = parseDialogueExchanges(content);
|
|
400
|
+
assert.strictEqual(parsed[0].question, VALID_EXCHANGE.question);
|
|
401
|
+
assert.strictEqual(parsed[0].recommendation, VALID_EXCHANGE.recommendation);
|
|
402
|
+
assert.strictEqual(parsed[0].outcome, 'applied');
|
|
403
|
+
assert.strictEqual(parsed[0].outcomeNote, 'Adopted this approach');
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
// =============================================================================
|
|
407
|
+
// Result format compliance (framework pattern)
|
|
408
|
+
// =============================================================================
|
|
409
|
+
describe('Result format compliance', () => {
|
|
410
|
+
it('should return {success, data?, error?} from appendExchangeToFile', async () => {
|
|
411
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
412
|
+
const result = await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
413
|
+
assert.ok('success' in result, 'Must have success field');
|
|
414
|
+
assert.strictEqual(typeof result.success, 'boolean');
|
|
415
|
+
});
|
|
416
|
+
it('should return {success, data?, error?} from updateOutcomeInFile', async () => {
|
|
417
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
418
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
419
|
+
const result = await updateOutcomeInFile(dialoguePath, 1, 'applied');
|
|
420
|
+
assert.ok('success' in result, 'Must have success field');
|
|
421
|
+
assert.strictEqual(typeof result.success, 'boolean');
|
|
422
|
+
});
|
|
423
|
+
it('should return {success, data?, error?} from refreshSummary', async () => {
|
|
424
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
425
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
426
|
+
const result = await refreshSummary(dialoguePath);
|
|
427
|
+
assert.ok('success' in result, 'Must have success field');
|
|
428
|
+
assert.strictEqual(typeof result.success, 'boolean');
|
|
429
|
+
});
|
|
430
|
+
it('should return {success, data?, error?} from archiveDialogue', async () => {
|
|
431
|
+
const dialoguePath = path.join(tmpDir, '86-3-dialogue.md');
|
|
432
|
+
const archiveDir = path.join(tmpDir, 'archive');
|
|
433
|
+
await appendExchangeToFile(dialoguePath, VALID_EXCHANGE, VALID_HEADER);
|
|
434
|
+
const result = await archiveDialogue({
|
|
435
|
+
dialoguePath,
|
|
436
|
+
archiveDir,
|
|
437
|
+
jiraKey: 'MSSCI-15200',
|
|
438
|
+
});
|
|
439
|
+
assert.ok('success' in result, 'Must have success field');
|
|
440
|
+
assert.strictEqual(typeof result.success, 'boolean');
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
//# sourceMappingURL=dialogue-manager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogue-manager.test.js","sourceRoot":"","sources":["../../src/consultation/dialogue-manager.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAQ/B,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,MAAM,YAAY,GAAmB;IACnC,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,KAAK;IACb,eAAe,EAAE,eAAe;IAChC,OAAO,EAAE,WAAW;IACpB,gBAAgB,EAAE,eAAe;IACjC,SAAS,EAAE,sBAAsB;CAClC,CAAC;AAEF,MAAM,cAAc,GAAqB;IACvC,MAAM,EAAE,CAAC;IACT,SAAS,EAAE,OAAO;IAClB,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,wEAAwE;IAClF,cAAc,EAAE,2GAA2G;IAC3H,UAAU,EAAE,MAAM;CACnB,CAAC;AAEF,MAAM,eAAe,GAAqB;IACxC,MAAM,EAAE,CAAC;IACT,SAAS,EAAE,OAAO;IAClB,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,yDAAyD;IACnE,cAAc,EAAE,mGAAmG;IACnH,UAAU,EAAE,QAAQ;IACpB,OAAO,EAAE,SAAS;IAClB,WAAW,EAAE,0BAA0B;CACxC,CAAC;AAEF,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,IAAI,MAAc,CAAC;AAEnB,SAAS,WAAW;IAClB,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACrE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,gFAAgF;AAChF,gEAAgE;AAChE,gFAAgF;AAEhF,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAE9C,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,WAAW,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAEjE,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;YACpE,MAAM,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;YAEpD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EACnD,gCAAgC,CAAC,CAAC;YACpC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EACpD,uBAAuB,CAAC,CAAC;YAC3B,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAC3C,2BAA2B,CAAC,CAAC;YAC/B,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAClD,4BAA4B,CAAC,CAAC;YAChC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,mCAAmC,CAAC,EAC7D,8BAA8B,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;YAEpD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EACzC,+BAA+B,CAAC,CAAC;YACnC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EACzC,gCAAgC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,aAAa,GAAmB;gBACpC,GAAG,YAAY;gBACf,eAAe,EAAE,SAAS;gBAC1B,gBAAgB,EAAE,SAAS;aAC5B,CAAC;YAEF,MAAM,OAAO,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;YAErD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAC3C,uCAAuC,CAAC,CAAC;YAC3C,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAClD,wCAAwC,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;YAEpD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EACtC,8BAA8B,CAAC,CAAC;YAClC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAClD,mCAAmC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;YAClF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAE3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EACnC,oDAAoD,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAE3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EACnD,qBAAqB,CAAC,CAAC;YACzB,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EACzC,6BAA6B,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,kFAAkF;IAClF,gFAAgF;IAEhF,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAElD,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YAEjD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,EAC3C,8BAA8B,CAAC,CAAC;YAClC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EACzD,4CAA4C,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YAEjD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,gDAAgD,CAAC,EAC5E,qCAAqC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YAEjD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EACpD,sCAAsC,CAAC,CAAC;YAC1C,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAChD,kCAAkC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YAEjD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAClC,+BAA+B,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,SAAS,GAAG,cAAc,CAAC,eAAe,CAAC,CAAC;YAElD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAClD,sBAAsB,CAAC,CAAC;YAC1B,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EACtD,2BAA2B,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YAEjD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EACpD,uCAAuC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAE3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YACvE,MAAM,oBAAoB,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;YAE1D,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,sBAAsB,CAAC,CAAC;YACrE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,sBAAsB,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAE3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACjD,MAAM,CAAC,EAAE,CAAC,WAAW,GAAG,UAAU,EAChC,sCAAsC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YAEjD,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EACjC,wBAAwB,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,sDAAsD;IACtD,gFAAgF;IAEhF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAErC,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;YAE5F,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,uBAAuB,CAAC,CAAC;YAElE,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAChD,gCAAgC,CAAC,CAAC;YACpC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC/C,2BAA2B,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,mBAAmB,CAAC,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC;YAEhF,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EACjD,iCAAiC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,mBAAmB,CAAC,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,kCAAkC,CAAC,CAAC;YAE3F,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EACjD,iCAAiC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;YAErE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAChD,kCAAkC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;YAEtE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,kCAAkC,CAAC,CAAC;YAC9E,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,oCAAoC,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAElE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;YAErE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,8BAA8B,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,wEAAwE;IACxE,gFAAgF;IAEhF,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;QAEvC,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,SAAS,GAAuB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;YACxE,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;YAEnE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAClD,6BAA6B,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;YAC1E,MAAM,SAAS,GAAuB;gBACpC,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,0BAA0B,EAAE;gBAClF,EAAE,GAAG,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,0BAA0B,EAAE;aACpF,CAAC;YACF,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;YAEnE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EACpD,qCAAqC,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EACpD,sCAAsC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,SAAS,GAAuB;gBACpC,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,oBAAoB,EAAE;gBAC7E,EAAE,GAAG,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE;aAC5E,CAAC;YACF,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;YAEnE,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAC/C,qCAAqC,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAC5C,gCAAgC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,SAAS,GAAuB;gBACpC,EAAE,GAAG,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE;gBACzC,EAAE,GAAG,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE;aAC3C,CAAC;YACF,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;YAEnE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC/C,6BAA6B,CAAC,CAAC;YACjC,uDAAuD;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAC/B,kDAAkD,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,SAAS,GAAuB,CAAC,cAAc,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;YAEnE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAC/C,4CAA4C,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,SAAS,GAAuB;gBACpC,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE;aAC3C,CAAC;YACF,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;YAEnE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAC9C,oCAAoC,CAAC,CAAC;YACxC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAChC,0CAA0C,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAE3D,6CAA6C;YAC7C,MAAM,mBAAmB,GAAqB;gBAC5C,GAAG,cAAc;gBACjB,OAAO,EAAE,SAAS;gBAClB,WAAW,EAAE,6BAA6B;aAC3C,CAAC;YACF,MAAM,oBAAoB,CAAC,YAAY,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAAC;YAE5E,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,CAAC;YAElD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;YAEnE,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAClD,iCAAiC,CAAC,CAAC;YACrC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EACvD,uCAAuC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,yEAAyE;IACzE,gFAAgF;IAEhF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAEtC,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAChD,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9C,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,YAAY;gBACZ,UAAU;gBACV,OAAO,EAAE,aAAa;aACvB,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,wBAAwB,CAAC,CAAC;YACnE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,yBAAyB,CAAC,CAAC;YACrE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAClC,+CAA+C,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAChD,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9C,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,YAAY;gBACZ,UAAU;gBACV,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;YAC9D,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAClC,+CAA+C,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAChD,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9C,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YACvE,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YAExD,MAAM,eAAe,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;YAE5E,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAC9B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,yBAAyB,CAAC,EAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,EACnC,sCAAsC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;YACpE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;YAEpD,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,YAAY;gBACZ,UAAU;gBACV,OAAO,EAAE,aAAa;aACvB,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,6BAA6B,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;YACtE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAClE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAEhD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,YAAY;gBACZ,UAAU;gBACV,OAAO,EAAE,aAAa;aACvB,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,gCAAgC,CAAC,CAAC;YAC5E,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,4BAA4B,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,oDAAoD;IACpD,gFAAgF;IAEhF,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAE9C,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;YAEpD,iCAAiC;YACjC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAChD,oBAAoB,CAAC,CAAC;YACxB,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAC/B,+BAA+B,CAAC,CAAC;YACnC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EACtC,yBAAyB,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YACvE,MAAM,oBAAoB,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;YAE1D,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE/C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,2BAA2B,CAAC,CAAC;YAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACxC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC;YAExE,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE/C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACrC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACnD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE/C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAC7C,2CAA2C,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,mBAAmB,GAAqB;gBAC5C,GAAG,cAAc;gBACjB,OAAO,EAAE,SAAS;gBAClB,WAAW,EAAE,uBAAuB;aACrC,CAAC;YACF,MAAM,oBAAoB,CAAC,YAAY,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAAC;YAE5E,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE/C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;YAChE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;YAC5E,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,+CAA+C;IAC/C,gFAAgF;IAEhF,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAExC,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;YAChF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAE3D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEtF,MAAM,CAAC,EAAE,CAAC,SAAS,IAAI,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAC1D,MAAM,CAAC,WAAW,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;YAC/E,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;YAErE,MAAM,CAAC,EAAE,CAAC,SAAS,IAAI,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAC1D,MAAM,CAAC,WAAW,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;YAC1E,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,CAAC;YAElD,MAAM,CAAC,EAAE,CAAC,SAAS,IAAI,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAC1D,MAAM,CAAC,WAAW,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAChD,MAAM,oBAAoB,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,YAAY;gBACZ,UAAU;gBACV,OAAO,EAAE,aAAa;aACvB,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,SAAS,IAAI,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAC1D,MAAM,CAAC,WAAW,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -40,9 +40,21 @@ export declare function getGitInfo(projectDir: string): GitInfo | null;
|
|
|
40
40
|
/**
|
|
41
41
|
* Get git status for project (async - does not block event loop)
|
|
42
42
|
* This should be preferred over getGitInfo for WebSocket broadcasts and polling
|
|
43
|
-
* Uses
|
|
43
|
+
* Uses --no-optional-locks so reads never conflict with concurrent git operations.
|
|
44
|
+
* Does NOT fetch from remote — use fetchRepoAsync() separately for that.
|
|
44
45
|
*/
|
|
45
46
|
export declare function getGitInfoAsync(projectDir: string): Promise<GitInfo | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Fetch latest refs from remote for a single repo.
|
|
49
|
+
* Uses per-repo mutex to prevent concurrent fetch operations.
|
|
50
|
+
* Throttled: only fetches once per GIT_FETCH_COOLDOWN_MS per repo (Story 103-21).
|
|
51
|
+
* Returns true if fetch was performed, false if skipped (cooldown) or failed.
|
|
52
|
+
*/
|
|
53
|
+
export declare function fetchRepoAsync(projectDir: string): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Fetch all configured repos. Returns true if any repo was fetched.
|
|
56
|
+
*/
|
|
57
|
+
export declare function fetchAllReposAsync(projectDir: string): Promise<boolean>;
|
|
46
58
|
/**
|
|
47
59
|
* Reset the fetch cooldown for a repo, allowing the next getGitInfoAsync call
|
|
48
60
|
* to perform a git fetch immediately. Used by force-refresh paths.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/server/api/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAuBjC,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAgC5C,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,oFAAoF;IACpF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAGD,MAAM,WAAW,WAAY,SAAQ,OAAO;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAqCnE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAkBpE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAoBxF;AAGD,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/server/api/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAuBjC,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAgC5C,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,oFAAoF;IACpF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAGD,MAAM,WAAW,WAAY,SAAQ,OAAO;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAqCnE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAkBpE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAoBxF;AAGD,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAuF7D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAqFjF;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBzE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM7E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAM5D;AAKD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAE7F;AAGD,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,MAAM,GAAG,MAAM,CAsDnE"}
|