edsger 0.50.0 → 0.52.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/.claude/settings.local.json +23 -3
- package/.env.local +12 -0
- package/README.md +25 -25
- package/dist/api/chat.d.ts +7 -7
- package/dist/api/chat.js +13 -13
- package/dist/api/cross-product.d.ts +10 -10
- package/dist/api/cross-product.js +30 -30
- package/dist/api/github.d.ts +5 -5
- package/dist/api/github.js +10 -10
- package/dist/api/intelligence.d.ts +3 -3
- package/dist/api/issues/approval-checker.d.ts +20 -0
- package/dist/api/{features → issues}/approval-checker.js +16 -16
- package/dist/api/issues/get-issue.d.ts +5 -0
- package/dist/api/issues/get-issue.js +21 -0
- package/dist/api/issues/index.d.ts +8 -0
- package/dist/api/issues/index.js +10 -0
- package/dist/api/issues/issue-utils.d.ts +23 -0
- package/dist/api/issues/issue-utils.js +80 -0
- package/dist/api/issues/status-updater.d.ts +41 -0
- package/dist/api/{features → issues}/status-updater.js +23 -23
- package/dist/api/{features → issues}/test-cases.d.ts +7 -7
- package/dist/api/{features → issues}/test-cases.js +12 -12
- package/dist/api/issues/update-issue.d.ts +20 -0
- package/dist/api/{features/update-feature.js → issues/update-issue.js} +22 -22
- package/dist/api/{features → issues}/user-stories.d.ts +5 -5
- package/dist/api/{features → issues}/user-stories.js +8 -8
- package/dist/api/products.d.ts +1 -1
- package/dist/api/tasks.d.ts +1 -1
- package/dist/api/test-reports.d.ts +2 -2
- package/dist/api/test-reports.js +4 -4
- package/dist/auth/login.js +1 -1
- package/dist/commands/agent-workflow/chat-worker.d.ts +7 -7
- package/dist/commands/agent-workflow/chat-worker.js +50 -50
- package/dist/commands/agent-workflow/index.d.ts +2 -2
- package/dist/commands/agent-workflow/index.js +3 -3
- package/dist/commands/agent-workflow/{feature-worker.d.ts → issue-worker.d.ts} +4 -4
- package/dist/commands/agent-workflow/{feature-worker.js → issue-worker.js} +12 -12
- package/dist/commands/agent-workflow/processor.d.ts +9 -9
- package/dist/commands/agent-workflow/processor.js +90 -90
- package/dist/commands/build/index.js +2 -2
- package/dist/commands/find-bugs/index.d.ts +11 -0
- package/dist/commands/find-bugs/index.js +39 -0
- package/dist/commands/find-features/index.d.ts +14 -0
- package/dist/commands/find-features/index.js +42 -0
- package/dist/commands/find-smells/index.d.ts +21 -0
- package/dist/commands/find-smells/index.js +65 -0
- package/dist/commands/init/prompts.js +1 -1
- package/dist/commands/init/templates.d.ts +1 -1
- package/dist/commands/init/templates.js +4 -4
- package/dist/commands/workflow/config/phase-configs.js +17 -17
- package/dist/commands/workflow/core/index.d.ts +1 -1
- package/dist/commands/workflow/core/index.js +2 -2
- package/dist/commands/workflow/core/issue-filter.d.ts +16 -0
- package/dist/commands/workflow/core/issue-filter.js +47 -0
- package/dist/commands/workflow/core/state-manager.d.ts +10 -10
- package/dist/commands/workflow/core/state-manager.js +10 -10
- package/dist/commands/workflow/core/workflow-logger.d.ts +9 -9
- package/dist/commands/workflow/core/workflow-logger.js +21 -21
- package/dist/commands/workflow/executors/phase-executor.d.ts +2 -2
- package/dist/commands/workflow/executors/phase-executor.js +32 -32
- package/dist/commands/workflow/issue-coordinator.d.ts +18 -0
- package/dist/commands/workflow/{feature-coordinator.js → issue-coordinator.js} +29 -29
- package/dist/commands/workflow/phase-orchestrator.d.ts +2 -2
- package/dist/commands/workflow/phase-orchestrator.js +82 -82
- package/dist/commands/workflow/processor.d.ts +7 -7
- package/dist/commands/workflow/processor.js +44 -44
- package/dist/config/{feature-status.d.ts → issue-status.d.ts} +14 -14
- package/dist/config/{feature-status.js → issue-status.js} +14 -14
- package/dist/errors/index.d.ts +6 -6
- package/dist/errors/index.js +11 -11
- package/dist/index.js +90 -1
- package/dist/phases/app-store-generation/context.js +6 -6
- package/dist/phases/app-store-generation/index.js +2 -2
- package/dist/phases/app-store-generation/prompts.js +2 -2
- package/dist/phases/autonomous/index.d.ts +3 -3
- package/dist/phases/autonomous/index.js +37 -37
- package/dist/phases/autonomous/prompts.d.ts +2 -2
- package/dist/phases/autonomous/prompts.js +4 -4
- package/dist/phases/branch-planning/context.d.ts +3 -3
- package/dist/phases/branch-planning/context.js +12 -12
- package/dist/phases/branch-planning/index.d.ts +3 -3
- package/dist/phases/branch-planning/index.js +32 -32
- package/dist/phases/branch-planning/outcome.d.ts +5 -5
- package/dist/phases/branch-planning/outcome.js +12 -12
- package/dist/phases/branch-planning/prompts.d.ts +3 -3
- package/dist/phases/branch-planning/prompts.js +13 -13
- package/dist/phases/bug-fixing/analyzer.d.ts +2 -2
- package/dist/phases/bug-fixing/analyzer.js +13 -13
- package/dist/phases/bug-fixing/context-fetcher.d.ts +3 -3
- package/dist/phases/bug-fixing/context-fetcher.js +18 -18
- package/dist/phases/bug-fixing/mcp-server.js +17 -18
- package/dist/phases/chat-processor/context.d.ts +5 -5
- package/dist/phases/chat-processor/context.js +17 -17
- package/dist/phases/chat-processor/index.d.ts +4 -4
- package/dist/phases/chat-processor/index.js +17 -17
- package/dist/phases/chat-processor/product-context.d.ts +3 -3
- package/dist/phases/chat-processor/product-context.js +16 -16
- package/dist/phases/chat-processor/product-prompts.d.ts +1 -1
- package/dist/phases/chat-processor/product-prompts.js +10 -10
- package/dist/phases/chat-processor/product-tools.d.ts +2 -2
- package/dist/phases/chat-processor/product-tools.js +33 -33
- package/dist/phases/chat-processor/prompts.d.ts +3 -3
- package/dist/phases/chat-processor/prompts.js +22 -22
- package/dist/phases/chat-processor/tools.js +46 -46
- package/dist/phases/code-implementation/branch-pr-creator.d.ts +3 -3
- package/dist/phases/code-implementation/branch-pr-creator.js +5 -5
- package/dist/phases/code-implementation/context.d.ts +3 -3
- package/dist/phases/code-implementation/context.js +18 -18
- package/dist/phases/code-implementation/index.d.ts +4 -4
- package/dist/phases/code-implementation/index.js +88 -88
- package/dist/phases/code-implementation/outcome.d.ts +3 -3
- package/dist/phases/code-implementation/outcome.js +6 -6
- package/dist/phases/code-implementation/prompts.d.ts +1 -1
- package/dist/phases/code-implementation/prompts.js +6 -6
- package/dist/phases/code-implementation-verification/agent.d.ts +3 -3
- package/dist/phases/code-implementation-verification/agent.js +5 -5
- package/dist/phases/code-implementation-verification/index.d.ts +3 -3
- package/dist/phases/code-implementation-verification/index.js +11 -11
- package/dist/phases/code-implementation-verification/prompts.d.ts +3 -3
- package/dist/phases/code-implementation-verification/prompts.js +7 -7
- package/dist/phases/code-refine/context.d.ts +8 -8
- package/dist/phases/code-refine/context.js +29 -29
- package/dist/phases/code-refine/index.d.ts +2 -2
- package/dist/phases/code-refine/index.js +20 -20
- package/dist/phases/code-refine/prompts.d.ts +1 -1
- package/dist/phases/code-refine/prompts.js +3 -3
- package/dist/phases/code-refine/refine-iteration.d.ts +1 -1
- package/dist/phases/code-refine/refine-iteration.js +4 -4
- package/dist/phases/code-refine/retry-handler.js +2 -2
- package/dist/phases/code-refine-verification/index.js +10 -10
- package/dist/phases/code-refine-verification/types.d.ts +2 -2
- package/dist/phases/code-review/context.d.ts +8 -8
- package/dist/phases/code-review/context.js +25 -25
- package/dist/phases/code-review/diff-utils.d.ts +1 -1
- package/dist/phases/code-review/diff-utils.js +1 -1
- package/dist/phases/code-review/index.d.ts +2 -2
- package/dist/phases/code-review/index.js +26 -26
- package/dist/phases/code-testing/analyzer.d.ts +2 -2
- package/dist/phases/code-testing/analyzer.js +18 -18
- package/dist/phases/code-testing/context-fetcher.d.ts +3 -3
- package/dist/phases/code-testing/context-fetcher.js +16 -16
- package/dist/phases/code-testing/prompts.d.ts +1 -1
- package/dist/phases/code-testing/prompts.js +5 -5
- package/dist/phases/find-bugs/index.d.ts +30 -0
- package/dist/phases/find-bugs/index.js +216 -0
- package/dist/phases/find-bugs/prompts.d.ts +22 -0
- package/dist/phases/find-bugs/prompts.js +101 -0
- package/dist/phases/find-bugs/state.d.ts +19 -0
- package/dist/phases/find-bugs/state.js +13 -0
- package/dist/phases/find-bugs/types.d.ts +21 -0
- package/dist/phases/find-bugs/types.js +16 -0
- package/dist/phases/find-features/index.d.ts +40 -0
- package/dist/phases/find-features/index.js +279 -0
- package/dist/phases/find-features/prompts.d.ts +43 -0
- package/dist/phases/find-features/prompts.js +138 -0
- package/dist/phases/find-features/state.d.ts +25 -0
- package/dist/phases/find-features/state.js +22 -0
- package/dist/phases/find-features/types.d.ts +27 -0
- package/dist/phases/find-features/types.js +16 -0
- package/dist/phases/find-shared/git.d.ts +24 -0
- package/dist/phases/find-shared/git.js +60 -0
- package/dist/phases/find-shared/mcp.d.ts +33 -0
- package/dist/phases/find-shared/mcp.js +69 -0
- package/dist/phases/find-shared/scan-state.d.ts +33 -0
- package/dist/phases/find-shared/scan-state.js +112 -0
- package/dist/phases/find-smells/index.d.ts +47 -0
- package/dist/phases/find-smells/index.js +278 -0
- package/dist/phases/find-smells/prompts.d.ts +30 -0
- package/dist/phases/find-smells/prompts.js +129 -0
- package/dist/phases/find-smells/state.d.ts +21 -0
- package/dist/phases/find-smells/state.js +17 -0
- package/dist/phases/find-smells/types.d.ts +51 -0
- package/dist/phases/find-smells/types.js +64 -0
- package/dist/phases/functional-testing/analyzer.d.ts +2 -2
- package/dist/phases/functional-testing/analyzer.js +40 -40
- package/dist/phases/functional-testing/context-fetcher.d.ts +3 -3
- package/dist/phases/functional-testing/context-fetcher.js +16 -16
- package/dist/phases/functional-testing/http-fallback.d.ts +2 -2
- package/dist/phases/functional-testing/http-fallback.js +9 -9
- package/dist/phases/functional-testing/mcp-server.js +23 -24
- package/dist/phases/functional-testing/prompts.d.ts +1 -1
- package/dist/phases/functional-testing/prompts.js +4 -4
- package/dist/phases/functional-testing/test-report-creator.d.ts +2 -2
- package/dist/phases/functional-testing/test-report-creator.js +10 -10
- package/dist/phases/functional-testing/test-retry-handler.js +3 -3
- package/dist/phases/growth-analysis/context.js +6 -6
- package/dist/phases/growth-analysis/index.js +2 -2
- package/dist/phases/growth-analysis/prompts.js +2 -2
- package/dist/phases/intelligence-analysis/context.js +7 -7
- package/dist/phases/intelligence-analysis/index.js +3 -3
- package/dist/phases/{feature-analysis → issue-analysis}/agent.js +1 -1
- package/dist/phases/issue-analysis/context.d.ts +24 -0
- package/dist/phases/{feature-analysis → issue-analysis}/context.js +30 -30
- package/dist/phases/issue-analysis/index.d.ts +8 -0
- package/dist/phases/{feature-analysis → issue-analysis}/index.js +29 -29
- package/dist/phases/issue-analysis/outcome.d.ts +40 -0
- package/dist/phases/{feature-analysis → issue-analysis}/outcome.js +17 -17
- package/dist/phases/{feature-analysis → issue-analysis}/prompts.d.ts +3 -3
- package/dist/phases/{feature-analysis → issue-analysis}/prompts.js +12 -12
- package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/agent.d.ts +2 -2
- package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/agent.js +1 -1
- package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/index.d.ts +5 -5
- package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/index.js +9 -9
- package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/prompts.d.ts +2 -2
- package/dist/phases/{feature-analysis-verification → issue-analysis-verification}/prompts.js +7 -7
- package/dist/phases/output-contracts.js +37 -37
- package/dist/phases/pr-execution/context.d.ts +3 -3
- package/dist/phases/pr-execution/context.js +14 -14
- package/dist/phases/pr-execution/index.d.ts +2 -2
- package/dist/phases/pr-execution/index.js +22 -22
- package/dist/phases/pr-execution/outcome.d.ts +4 -4
- package/dist/phases/pr-execution/outcome.js +6 -6
- package/dist/phases/pr-execution/prompts.d.ts +4 -4
- package/dist/phases/pr-execution/prompts.js +6 -6
- package/dist/phases/pr-resolve/checklist-learner.js +2 -2
- package/dist/phases/pr-review/index.d.ts +1 -1
- package/dist/phases/pr-review/index.js +1 -1
- package/dist/phases/pr-review/prompts.d.ts +1 -1
- package/dist/phases/pr-review/prompts.js +1 -1
- package/dist/phases/pr-shared/context.d.ts +3 -3
- package/dist/phases/pr-shared/context.js +3 -3
- package/dist/phases/pr-splitting/context.d.ts +3 -3
- package/dist/phases/pr-splitting/context.js +16 -16
- package/dist/phases/pr-splitting/index.d.ts +4 -4
- package/dist/phases/pr-splitting/index.js +29 -29
- package/dist/phases/pr-splitting/outcome.d.ts +3 -3
- package/dist/phases/pr-splitting/outcome.js +7 -7
- package/dist/phases/pr-splitting/prompts.d.ts +3 -3
- package/dist/phases/pr-splitting/prompts.js +11 -11
- package/dist/phases/pull-request/creator.d.ts +4 -4
- package/dist/phases/pull-request/creator.js +25 -25
- package/dist/phases/pull-request/handler.d.ts +3 -3
- package/dist/phases/pull-request/handler.js +16 -16
- package/dist/phases/release-sync/index.js +2 -2
- package/dist/phases/run-sheet/agent.js +1 -2
- package/dist/phases/run-sheet/index.js +3 -3
- package/dist/phases/smoke-test/index.js +2 -2
- package/dist/phases/technical-design/context.d.ts +3 -3
- package/dist/phases/technical-design/context.js +11 -11
- package/dist/phases/technical-design/index.d.ts +2 -2
- package/dist/phases/technical-design/index.js +27 -27
- package/dist/phases/technical-design/outcome.d.ts +4 -4
- package/dist/phases/technical-design/outcome.js +6 -6
- package/dist/phases/technical-design/prompts.d.ts +2 -2
- package/dist/phases/technical-design/prompts.js +10 -10
- package/dist/phases/technical-design-verification/agent.d.ts +3 -3
- package/dist/phases/technical-design-verification/agent.js +4 -4
- package/dist/phases/technical-design-verification/index.d.ts +4 -4
- package/dist/phases/technical-design-verification/index.js +12 -12
- package/dist/phases/technical-design-verification/prompts.d.ts +3 -3
- package/dist/phases/technical-design-verification/prompts.js +6 -6
- package/dist/phases/test-cases-analysis/context.d.ts +5 -5
- package/dist/phases/test-cases-analysis/context.js +18 -18
- package/dist/phases/test-cases-analysis/formatters.js +7 -7
- package/dist/phases/test-cases-analysis/index.d.ts +1 -1
- package/dist/phases/test-cases-analysis/index.js +21 -21
- package/dist/phases/test-cases-analysis/outcome.d.ts +7 -7
- package/dist/phases/test-cases-analysis/outcome.js +13 -13
- package/dist/phases/test-cases-analysis/prompts.d.ts +3 -3
- package/dist/phases/test-cases-analysis/prompts.js +6 -6
- package/dist/phases/user-stories-analysis/context.d.ts +5 -5
- package/dist/phases/user-stories-analysis/context.js +18 -18
- package/dist/phases/user-stories-analysis/formatters.js +7 -7
- package/dist/phases/user-stories-analysis/index.d.ts +1 -1
- package/dist/phases/user-stories-analysis/index.js +21 -21
- package/dist/phases/user-stories-analysis/outcome.d.ts +7 -7
- package/dist/phases/user-stories-analysis/outcome.js +13 -13
- package/dist/phases/user-stories-analysis/prompts.d.ts +3 -3
- package/dist/phases/user-stories-analysis/prompts.js +10 -10
- package/dist/services/audit-logs.d.ts +10 -10
- package/dist/services/audit-logs.js +12 -12
- package/dist/services/branches.d.ts +6 -6
- package/dist/services/branches.js +16 -16
- package/dist/services/checklist.d.ts +3 -3
- package/dist/services/checklist.js +11 -11
- package/dist/services/coaching/coaching-agent.js +2 -2
- package/dist/services/coaching/coaching-loop.d.ts +1 -1
- package/dist/services/coaching/coaching-loop.js +2 -2
- package/dist/services/coaching/phase-coaching.d.ts +2 -2
- package/dist/services/coaching/phase-coaching.js +3 -3
- package/dist/services/coaching/self-rating.js +1 -1
- package/dist/services/feedbacks.d.ts +4 -4
- package/dist/services/feedbacks.js +8 -8
- package/dist/services/phase-hooks/bindings-fetcher.d.ts +4 -4
- package/dist/services/phase-hooks/bindings-fetcher.js +8 -8
- package/dist/services/phase-hooks/hook-executor.js +1 -1
- package/dist/services/phase-hooks/hook-logging.d.ts +2 -2
- package/dist/services/phase-hooks/hook-logging.js +4 -4
- package/dist/services/phase-hooks/hook-runner.d.ts +1 -1
- package/dist/services/phase-hooks/hook-runner.js +4 -4
- package/dist/services/phase-hooks/types.d.ts +3 -3
- package/dist/services/phase-ratings.d.ts +7 -7
- package/dist/services/phase-ratings.js +8 -8
- package/dist/services/pull-requests.d.ts +4 -4
- package/dist/services/pull-requests.js +11 -11
- package/dist/services/skill-resolver.d.ts +1 -1
- package/dist/services/skill-resolver.js +1 -1
- package/dist/skills/phase/app-store-generation/SKILL.md +9 -9
- package/dist/skills/phase/autonomous/SKILL.md +2 -2
- package/dist/skills/phase/branch-planning/SKILL.md +12 -12
- package/dist/skills/phase/bug-fixing/SKILL.md +1 -1
- package/dist/skills/phase/code-implementation/SKILL.md +6 -6
- package/dist/skills/phase/code-implementation-verification/SKILL.md +3 -3
- package/dist/skills/phase/code-testing/SKILL.md +5 -5
- package/dist/skills/phase/functional-testing/SKILL.md +3 -3
- package/dist/skills/phase/growth-analysis/SKILL.md +8 -8
- package/dist/skills/phase/incremental-sync/SKILL.md +6 -6
- package/dist/skills/phase/intelligence-analysis/SKILL.md +7 -7
- package/dist/skills/phase/{feature-analysis → issue-analysis}/SKILL.md +8 -8
- package/dist/skills/phase/pr-execution/SKILL.md +7 -7
- package/dist/skills/phase/pr-splitting/SKILL.md +14 -14
- package/dist/skills/phase/smoke-test/SKILL.md +1 -1
- package/dist/skills/phase/technical-design/SKILL.md +5 -5
- package/dist/skills/phase/test-cases-analysis/SKILL.md +4 -4
- package/dist/skills/phase/user-stories-analysis/SKILL.md +13 -13
- package/dist/system/session-manager.d.ts +3 -3
- package/dist/system/session-manager.js +3 -3
- package/dist/system/sleep-notification.js +2 -2
- package/dist/system/sleep-prevention.js +1 -1
- package/dist/types/index.d.ts +21 -21
- package/dist/types/{features.d.ts → issues.d.ts} +3 -3
- package/dist/types/pipeline.d.ts +4 -4
- package/dist/updater/auto-updater.d.ts +2 -2
- package/dist/updater/auto-updater.js +3 -3
- package/dist/utils/conflict-resolver.d.ts +1 -1
- package/dist/utils/conflict-resolver.js +5 -5
- package/dist/utils/formatters.d.ts +4 -4
- package/dist/utils/formatters.js +29 -29
- package/dist/utils/git-branch-manager-async.d.ts +6 -6
- package/dist/utils/git-branch-manager-async.js +41 -41
- package/dist/utils/git-branch-manager.d.ts +11 -11
- package/dist/utils/git-branch-manager.js +42 -42
- package/dist/utils/image-downloader.d.ts +4 -4
- package/dist/utils/image-downloader.js +17 -17
- package/dist/utils/pipeline-logger.d.ts +1 -1
- package/dist/utils/pipeline-logger.js +5 -5
- package/dist/workspace/workspace-manager.d.ts +17 -17
- package/dist/workspace/workspace-manager.js +21 -21
- package/package.json +1 -1
- package/vitest.config.ts +4 -0
- package/dist/api/__tests__/app-store.test.d.ts +0 -7
- package/dist/api/__tests__/app-store.test.js +0 -60
- package/dist/api/__tests__/intelligence.test.d.ts +0 -11
- package/dist/api/__tests__/intelligence.test.js +0 -315
- package/dist/api/features/__tests__/feature-utils.test.d.ts +0 -4
- package/dist/api/features/__tests__/feature-utils.test.js +0 -370
- package/dist/api/features/__tests__/status-updater.test.d.ts +0 -4
- package/dist/api/features/__tests__/status-updater.test.js +0 -88
- package/dist/api/features/approval-checker.d.ts +0 -20
- package/dist/api/features/feature-utils.d.ts +0 -23
- package/dist/api/features/feature-utils.js +0 -80
- package/dist/api/features/get-feature.d.ts +0 -5
- package/dist/api/features/get-feature.js +0 -21
- package/dist/api/features/index.d.ts +0 -8
- package/dist/api/features/index.js +0 -10
- package/dist/api/features/status-updater.d.ts +0 -41
- package/dist/api/features/update-feature.d.ts +0 -20
- package/dist/commands/build/__tests__/build.test.d.ts +0 -5
- package/dist/commands/build/__tests__/build.test.js +0 -206
- package/dist/commands/build/__tests__/detect-project.test.d.ts +0 -6
- package/dist/commands/build/__tests__/detect-project.test.js +0 -160
- package/dist/commands/build/__tests__/run-build.test.d.ts +0 -6
- package/dist/commands/build/__tests__/run-build.test.js +0 -433
- package/dist/commands/intelligence/__tests__/command.test.d.ts +0 -4
- package/dist/commands/intelligence/__tests__/command.test.js +0 -48
- package/dist/commands/workflow/core/__tests__/feature-filter.test.d.ts +0 -5
- package/dist/commands/workflow/core/__tests__/feature-filter.test.js +0 -316
- package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.d.ts +0 -4
- package/dist/commands/workflow/core/__tests__/pipeline-evaluator.test.js +0 -397
- package/dist/commands/workflow/core/__tests__/state-manager.test.d.ts +0 -4
- package/dist/commands/workflow/core/__tests__/state-manager.test.js +0 -384
- package/dist/commands/workflow/core/feature-filter.d.ts +0 -16
- package/dist/commands/workflow/core/feature-filter.js +0 -47
- package/dist/commands/workflow/feature-coordinator.d.ts +0 -18
- package/dist/config/__tests__/config.test.d.ts +0 -4
- package/dist/config/__tests__/config.test.js +0 -286
- package/dist/config/__tests__/feature-status.test.d.ts +0 -4
- package/dist/config/__tests__/feature-status.test.js +0 -111
- package/dist/errors/__tests__/index.test.d.ts +0 -4
- package/dist/errors/__tests__/index.test.js +0 -349
- package/dist/phases/app-store-generation/__tests__/agent.test.d.ts +0 -5
- package/dist/phases/app-store-generation/__tests__/agent.test.js +0 -142
- package/dist/phases/app-store-generation/__tests__/context.test.d.ts +0 -4
- package/dist/phases/app-store-generation/__tests__/context.test.js +0 -284
- package/dist/phases/app-store-generation/__tests__/prompts.test.d.ts +0 -4
- package/dist/phases/app-store-generation/__tests__/prompts.test.js +0 -122
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.d.ts +0 -5
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.js +0 -826
- package/dist/phases/code-review/__tests__/diff-utils.test.js +0 -101
- package/dist/phases/feature-analysis/context.d.ts +0 -24
- package/dist/phases/feature-analysis/index.d.ts +0 -8
- package/dist/phases/feature-analysis/outcome.d.ts +0 -40
- package/dist/phases/intelligence-analysis/__tests__/context.test.d.ts +0 -4
- package/dist/phases/intelligence-analysis/__tests__/context.test.js +0 -192
- package/dist/phases/intelligence-analysis/__tests__/matching.test.d.ts +0 -13
- package/dist/phases/intelligence-analysis/__tests__/matching.test.js +0 -154
- package/dist/phases/intelligence-analysis/__tests__/orchestration.test.d.ts +0 -5
- package/dist/phases/intelligence-analysis/__tests__/orchestration.test.js +0 -378
- package/dist/phases/intelligence-analysis/__tests__/prompts.test.d.ts +0 -4
- package/dist/phases/intelligence-analysis/__tests__/prompts.test.js +0 -33
- package/dist/phases/pr-execution/__tests__/file-assigner.test.d.ts +0 -1
- package/dist/phases/pr-execution/__tests__/file-assigner.test.js +0 -303
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/checklist-learner.test.js +0 -157
- package/dist/phases/pr-resolve/__tests__/prompts.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/prompts.test.js +0 -116
- package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/resolve-mapping.test.js +0 -138
- package/dist/phases/pr-resolve/__tests__/types.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/types.test.js +0 -43
- package/dist/phases/pr-resolve/__tests__/workspace.test.d.ts +0 -1
- package/dist/phases/pr-resolve/__tests__/workspace.test.js +0 -111
- package/dist/phases/pr-review/__tests__/prompts.test.d.ts +0 -1
- package/dist/phases/pr-review/__tests__/prompts.test.js +0 -49
- package/dist/phases/pr-review/__tests__/review-comments.test.d.ts +0 -1
- package/dist/phases/pr-review/__tests__/review-comments.test.js +0 -110
- package/dist/phases/pr-shared/__tests__/agent-utils.test.d.ts +0 -1
- package/dist/phases/pr-shared/__tests__/agent-utils.test.js +0 -91
- package/dist/phases/pr-shared/__tests__/context.test.d.ts +0 -1
- package/dist/phases/pr-shared/__tests__/context.test.js +0 -94
- package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.d.ts +0 -1
- package/dist/phases/pr-splitting/__tests__/import-dep-validator.test.js +0 -331
- package/dist/phases/run-sheet/render.d.ts +0 -60
- package/dist/phases/run-sheet/render.js +0 -297
- package/dist/phases/smoke-test/__tests__/agent.test.d.ts +0 -4
- package/dist/phases/smoke-test/__tests__/agent.test.js +0 -84
- package/dist/phases/smoke-test/__tests__/github.test.d.ts +0 -9
- package/dist/phases/smoke-test/__tests__/github.test.js +0 -120
- package/dist/phases/smoke-test/__tests__/snapshot.test.d.ts +0 -8
- package/dist/phases/smoke-test/__tests__/snapshot.test.js +0 -93
- package/dist/phases/smoke-test/github.d.ts +0 -54
- package/dist/phases/smoke-test/github.js +0 -101
- package/dist/phases/smoke-test/snapshot.d.ts +0 -27
- package/dist/phases/smoke-test/snapshot.js +0 -157
- package/dist/services/coaching/__tests__/coaching-agent.test.d.ts +0 -1
- package/dist/services/coaching/__tests__/coaching-agent.test.js +0 -74
- package/dist/services/coaching/__tests__/coaching-loop.test.d.ts +0 -1
- package/dist/services/coaching/__tests__/coaching-loop.test.js +0 -59
- package/dist/services/coaching/__tests__/self-rating.test.d.ts +0 -1
- package/dist/services/coaching/__tests__/self-rating.test.js +0 -188
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- package/dist/services/lifecycle-agent/types.js +0 -12
- package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/bindings-fetcher.test.js +0 -122
- package/dist/services/phase-hooks/__tests__/hook-executor.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/hook-executor.test.js +0 -321
- package/dist/services/phase-hooks/__tests__/hook-runner.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/hook-runner.test.js +0 -261
- package/dist/services/phase-hooks/__tests__/plugin-loader.test.d.ts +0 -1
- package/dist/services/phase-hooks/__tests__/plugin-loader.test.js +0 -158
- package/dist/services/video/__tests__/video-pipeline.test.d.ts +0 -6
- package/dist/services/video/__tests__/video-pipeline.test.js +0 -249
- package/dist/types/features.js +0 -1
- package/dist/workspace/__tests__/workspace-manager.test.d.ts +0 -7
- package/dist/workspace/__tests__/workspace-manager.test.js +0 -52
- /package/dist/api/{features → issues}/batch-operations.d.ts +0 -0
- /package/dist/api/{features → issues}/batch-operations.js +0 -0
- /package/dist/phases/{feature-analysis → issue-analysis}/agent.d.ts +0 -0
- /package/dist/skills/phase/{feature-analysis-verification → issue-analysis-verification}/SKILL.md +0 -0
- /package/dist/{phases/code-review/__tests__/diff-utils.test.d.ts → types/issues.js} +0 -0
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { describe, it } from 'node:test';
|
|
3
|
-
import { autoFixPROrdering, getTransitiveDependencies, parseImportSpecifiers, resolveImportToChangedFile, } from '../import-dep-validator.js';
|
|
4
|
-
// ============================================================
|
|
5
|
-
// parseImportSpecifiers
|
|
6
|
-
// ============================================================
|
|
7
|
-
void describe('parseImportSpecifiers', () => {
|
|
8
|
-
void it('parses named imports', () => {
|
|
9
|
-
const result = parseImportSpecifiers(`import { foo } from './utils'`);
|
|
10
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
11
|
-
});
|
|
12
|
-
void it('parses default imports', () => {
|
|
13
|
-
const result = parseImportSpecifiers(`import foo from './utils'`);
|
|
14
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
15
|
-
});
|
|
16
|
-
void it('parses namespace imports', () => {
|
|
17
|
-
const result = parseImportSpecifiers(`import * as foo from './utils'`);
|
|
18
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
19
|
-
});
|
|
20
|
-
void it('parses side-effect imports', () => {
|
|
21
|
-
const result = parseImportSpecifiers(`import './polyfill'`);
|
|
22
|
-
assert.deepStrictEqual(result, ['./polyfill']);
|
|
23
|
-
});
|
|
24
|
-
void it('parses type-only imports', () => {
|
|
25
|
-
const result = parseImportSpecifiers(`import type { Foo } from './types'`);
|
|
26
|
-
assert.deepStrictEqual(result, ['./types']);
|
|
27
|
-
});
|
|
28
|
-
void it('parses re-exports', () => {
|
|
29
|
-
const result = parseImportSpecifiers(`export { foo } from './utils'`);
|
|
30
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
31
|
-
});
|
|
32
|
-
void it('parses star re-exports', () => {
|
|
33
|
-
const result = parseImportSpecifiers(`export * from './utils'`);
|
|
34
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
35
|
-
});
|
|
36
|
-
void it('parses dynamic imports', () => {
|
|
37
|
-
const result = parseImportSpecifiers(`const m = import('./lazy')`);
|
|
38
|
-
assert.deepStrictEqual(result, ['./lazy']);
|
|
39
|
-
});
|
|
40
|
-
void it('parses multiple imports', () => {
|
|
41
|
-
const source = `
|
|
42
|
-
import { foo } from './utils'
|
|
43
|
-
import Bar from '../components/Bar'
|
|
44
|
-
import type { Baz } from './types'
|
|
45
|
-
`;
|
|
46
|
-
const result = parseImportSpecifiers(source);
|
|
47
|
-
assert.deepStrictEqual(result, ['./utils', '../components/Bar', './types']);
|
|
48
|
-
});
|
|
49
|
-
void it('filters out non-relative imports', () => {
|
|
50
|
-
const source = `
|
|
51
|
-
import { X } from 'lodash'
|
|
52
|
-
import React from 'react'
|
|
53
|
-
import { Y } from './local'
|
|
54
|
-
import { Z } from '@scope/package'
|
|
55
|
-
`;
|
|
56
|
-
const result = parseImportSpecifiers(source);
|
|
57
|
-
assert.deepStrictEqual(result, ['./local']);
|
|
58
|
-
});
|
|
59
|
-
void it('parses multiline imports', () => {
|
|
60
|
-
const source = `import {
|
|
61
|
-
foo,
|
|
62
|
-
bar,
|
|
63
|
-
baz
|
|
64
|
-
} from './utils'`;
|
|
65
|
-
const result = parseImportSpecifiers(source);
|
|
66
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
67
|
-
});
|
|
68
|
-
void it('deduplicates specifiers', () => {
|
|
69
|
-
const source = `
|
|
70
|
-
import { foo } from './utils'
|
|
71
|
-
import { bar } from './utils'
|
|
72
|
-
`;
|
|
73
|
-
const result = parseImportSpecifiers(source);
|
|
74
|
-
assert.deepStrictEqual(result, ['./utils']);
|
|
75
|
-
});
|
|
76
|
-
void it('handles .js extension in specifier', () => {
|
|
77
|
-
const result = parseImportSpecifiers(`import { X } from './utils.js'`);
|
|
78
|
-
assert.deepStrictEqual(result, ['./utils.js']);
|
|
79
|
-
});
|
|
80
|
-
void it('returns empty for empty source', () => {
|
|
81
|
-
assert.deepStrictEqual(parseImportSpecifiers(''), []);
|
|
82
|
-
});
|
|
83
|
-
void it('returns empty for non-relative only', () => {
|
|
84
|
-
const source = `import express from 'express'`;
|
|
85
|
-
assert.deepStrictEqual(parseImportSpecifiers(source), []);
|
|
86
|
-
});
|
|
87
|
-
void it('parses export default from', () => {
|
|
88
|
-
const result = parseImportSpecifiers(`export { default as X } from './module'`);
|
|
89
|
-
assert.deepStrictEqual(result, ['./module']);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
// ============================================================
|
|
93
|
-
// resolveImportToChangedFile
|
|
94
|
-
// ============================================================
|
|
95
|
-
void describe('resolveImportToChangedFile', () => {
|
|
96
|
-
void it('resolves exact match with extension', () => {
|
|
97
|
-
const changed = new Set(['src/utils.ts']);
|
|
98
|
-
const result = resolveImportToChangedFile('./utils.ts', 'src/app.ts', changed);
|
|
99
|
-
assert.strictEqual(result, 'src/utils.ts');
|
|
100
|
-
});
|
|
101
|
-
void it('infers .ts extension', () => {
|
|
102
|
-
const changed = new Set(['src/utils.ts']);
|
|
103
|
-
const result = resolveImportToChangedFile('./utils', 'src/app.ts', changed);
|
|
104
|
-
assert.strictEqual(result, 'src/utils.ts');
|
|
105
|
-
});
|
|
106
|
-
void it('infers .tsx extension', () => {
|
|
107
|
-
const changed = new Set(['src/Component.tsx']);
|
|
108
|
-
const result = resolveImportToChangedFile('./Component', 'src/app.ts', changed);
|
|
109
|
-
assert.strictEqual(result, 'src/Component.tsx');
|
|
110
|
-
});
|
|
111
|
-
void it('resolves index file', () => {
|
|
112
|
-
const changed = new Set(['src/types/index.ts']);
|
|
113
|
-
const result = resolveImportToChangedFile('./types', 'src/app.ts', changed);
|
|
114
|
-
assert.strictEqual(result, 'src/types/index.ts');
|
|
115
|
-
});
|
|
116
|
-
void it('resolves .js to .ts (ESM convention)', () => {
|
|
117
|
-
const changed = new Set(['src/utils.ts']);
|
|
118
|
-
const result = resolveImportToChangedFile('./utils.js', 'src/app.ts', changed);
|
|
119
|
-
assert.strictEqual(result, 'src/utils.ts');
|
|
120
|
-
});
|
|
121
|
-
void it('resolves parent directory traversal', () => {
|
|
122
|
-
const changed = new Set(['src/shared/helpers.ts']);
|
|
123
|
-
const result = resolveImportToChangedFile('../shared/helpers', 'src/components/Button.ts', changed);
|
|
124
|
-
assert.strictEqual(result, 'src/shared/helpers.ts');
|
|
125
|
-
});
|
|
126
|
-
void it('resolves double parent traversal', () => {
|
|
127
|
-
const changed = new Set(['src/utils.ts']);
|
|
128
|
-
const result = resolveImportToChangedFile('../../utils', 'src/features/explore/App.ts', changed);
|
|
129
|
-
assert.strictEqual(result, 'src/utils.ts');
|
|
130
|
-
});
|
|
131
|
-
void it('returns null for non-changed file', () => {
|
|
132
|
-
const changed = new Set(['src/other.ts']);
|
|
133
|
-
const result = resolveImportToChangedFile('./utils', 'src/app.ts', changed);
|
|
134
|
-
assert.strictEqual(result, null);
|
|
135
|
-
});
|
|
136
|
-
void it('returns null for external package import path', () => {
|
|
137
|
-
// This shouldn't happen since parseImportSpecifiers filters these,
|
|
138
|
-
// but test defensive behavior
|
|
139
|
-
const changed = new Set(['src/utils.ts']);
|
|
140
|
-
const result = resolveImportToChangedFile('./nonexistent', 'src/app.ts', changed);
|
|
141
|
-
assert.strictEqual(result, null);
|
|
142
|
-
});
|
|
143
|
-
void it('prefers .ts over .tsx when both exist', () => {
|
|
144
|
-
const changed = new Set(['src/utils.ts', 'src/utils.tsx']);
|
|
145
|
-
const result = resolveImportToChangedFile('./utils', 'src/app.ts', changed);
|
|
146
|
-
assert.strictEqual(result, 'src/utils.ts');
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
// ============================================================
|
|
150
|
-
// getTransitiveDependencies
|
|
151
|
-
// ============================================================
|
|
152
|
-
void describe('getTransitiveDependencies', () => {
|
|
153
|
-
void it('returns direct dependency', () => {
|
|
154
|
-
const graph = new Map([
|
|
155
|
-
['A', new Set(['B'])],
|
|
156
|
-
['B', new Set()],
|
|
157
|
-
]);
|
|
158
|
-
const result = getTransitiveDependencies('A', graph);
|
|
159
|
-
assert.deepStrictEqual(result, new Set(['B']));
|
|
160
|
-
});
|
|
161
|
-
void it('returns transitive dependencies', () => {
|
|
162
|
-
const graph = new Map([
|
|
163
|
-
['A', new Set(['B'])],
|
|
164
|
-
['B', new Set(['C'])],
|
|
165
|
-
['C', new Set()],
|
|
166
|
-
]);
|
|
167
|
-
const result = getTransitiveDependencies('A', graph);
|
|
168
|
-
assert.deepStrictEqual(result, new Set(['B', 'C']));
|
|
169
|
-
});
|
|
170
|
-
void it('handles diamond dependency', () => {
|
|
171
|
-
const graph = new Map([
|
|
172
|
-
['A', new Set(['B', 'C'])],
|
|
173
|
-
['B', new Set(['D'])],
|
|
174
|
-
['C', new Set(['D'])],
|
|
175
|
-
['D', new Set()],
|
|
176
|
-
]);
|
|
177
|
-
const result = getTransitiveDependencies('A', graph);
|
|
178
|
-
assert.deepStrictEqual(result, new Set(['B', 'C', 'D']));
|
|
179
|
-
});
|
|
180
|
-
void it('handles cycles without infinite loop', () => {
|
|
181
|
-
const graph = new Map([
|
|
182
|
-
['A', new Set(['B'])],
|
|
183
|
-
['B', new Set(['A'])],
|
|
184
|
-
]);
|
|
185
|
-
const result = getTransitiveDependencies('A', graph);
|
|
186
|
-
assert.deepStrictEqual(result, new Set(['B', 'A']));
|
|
187
|
-
});
|
|
188
|
-
void it('returns empty set for no dependencies', () => {
|
|
189
|
-
const graph = new Map([['A', new Set()]]);
|
|
190
|
-
const result = getTransitiveDependencies('A', graph);
|
|
191
|
-
assert.deepStrictEqual(result, new Set());
|
|
192
|
-
});
|
|
193
|
-
void it('returns empty set for unknown file', () => {
|
|
194
|
-
const graph = new Map();
|
|
195
|
-
const result = getTransitiveDependencies('unknown', graph);
|
|
196
|
-
assert.deepStrictEqual(result, new Set());
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
// ============================================================
|
|
200
|
-
// autoFixPROrdering
|
|
201
|
-
// ============================================================
|
|
202
|
-
function makePR(sequence, name, files, dependsOn) {
|
|
203
|
-
return {
|
|
204
|
-
sequence,
|
|
205
|
-
name,
|
|
206
|
-
description: name,
|
|
207
|
-
branch_name: `pr/feat/${sequence}-${name.toLowerCase().replace(/\s/g, '-')}`,
|
|
208
|
-
depends_on_branch_name: dependsOn ?? null,
|
|
209
|
-
files: files.map((f) => ({ path: f, change_type: 'modified' })),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
void describe('autoFixPROrdering', () => {
|
|
213
|
-
void it('returns unchanged when no violations', () => {
|
|
214
|
-
const prs = [
|
|
215
|
-
makePR(1, 'Foundation', ['src/utils.ts']),
|
|
216
|
-
makePR(2, 'Components', ['src/app.ts'], 'pr/feat/1-foundation'),
|
|
217
|
-
];
|
|
218
|
-
// app.ts depends on utils.ts, and utils.ts is in PR 1 (earlier) — OK
|
|
219
|
-
const graph = new Map([
|
|
220
|
-
['src/app.ts', new Set(['src/utils.ts'])],
|
|
221
|
-
['src/utils.ts', new Set()],
|
|
222
|
-
]);
|
|
223
|
-
const result = autoFixPROrdering(prs, graph);
|
|
224
|
-
assert.strictEqual(result.movedFiles.length, 0);
|
|
225
|
-
assert.strictEqual(result.pullRequests[0].files?.length, 1);
|
|
226
|
-
assert.strictEqual(result.pullRequests[1].files?.length, 1);
|
|
227
|
-
});
|
|
228
|
-
void it('moves dependency from later PR to earlier PR', () => {
|
|
229
|
-
const prs = [
|
|
230
|
-
makePR(1, 'Components', ['src/app.ts']),
|
|
231
|
-
makePR(2, 'Utils', ['src/utils.ts'], 'pr/feat/1-components'),
|
|
232
|
-
];
|
|
233
|
-
// app.ts (PR 1) depends on utils.ts (PR 2) — violation!
|
|
234
|
-
const graph = new Map([
|
|
235
|
-
['src/app.ts', new Set(['src/utils.ts'])],
|
|
236
|
-
['src/utils.ts', new Set()],
|
|
237
|
-
]);
|
|
238
|
-
const result = autoFixPROrdering(prs, graph);
|
|
239
|
-
assert.strictEqual(result.movedFiles.length, 1);
|
|
240
|
-
assert.strictEqual(result.movedFiles[0].file, 'src/utils.ts');
|
|
241
|
-
// utils.ts should now be in PR 1
|
|
242
|
-
const pr1Files = result.pullRequests[0].files?.map((f) => f.path) ?? [];
|
|
243
|
-
assert.ok(pr1Files.includes('src/utils.ts'));
|
|
244
|
-
assert.ok(pr1Files.includes('src/app.ts'));
|
|
245
|
-
// PR 2 should be empty
|
|
246
|
-
assert.strictEqual(result.pullRequests[1].files?.length, 0);
|
|
247
|
-
});
|
|
248
|
-
void it('handles transitive dependency moves', () => {
|
|
249
|
-
const prs = [
|
|
250
|
-
makePR(1, 'App', ['src/app.ts']),
|
|
251
|
-
makePR(2, 'Service', ['src/service.ts'], 'pr/feat/1-app'),
|
|
252
|
-
makePR(3, 'Utils', ['src/utils.ts'], 'pr/feat/2-service'),
|
|
253
|
-
];
|
|
254
|
-
// app.ts → service.ts → utils.ts (chain across 3 PRs)
|
|
255
|
-
const graph = new Map([
|
|
256
|
-
['src/app.ts', new Set(['src/service.ts'])],
|
|
257
|
-
['src/service.ts', new Set(['src/utils.ts'])],
|
|
258
|
-
['src/utils.ts', new Set()],
|
|
259
|
-
]);
|
|
260
|
-
const result = autoFixPROrdering(prs, graph);
|
|
261
|
-
// Both service.ts and utils.ts should move to PR 1
|
|
262
|
-
const pr1Files = result.pullRequests[0].files?.map((f) => f.path) ?? [];
|
|
263
|
-
assert.ok(pr1Files.includes('src/app.ts'));
|
|
264
|
-
assert.ok(pr1Files.includes('src/service.ts'));
|
|
265
|
-
assert.ok(pr1Files.includes('src/utils.ts'));
|
|
266
|
-
});
|
|
267
|
-
void it('moves dep to earliest PR that needs it', () => {
|
|
268
|
-
const prs = [
|
|
269
|
-
makePR(1, 'PR1', ['src/a.ts']),
|
|
270
|
-
makePR(2, 'PR2', ['src/b.ts'], 'pr/feat/1-pr1'),
|
|
271
|
-
makePR(3, 'PR3', ['src/utils.ts'], 'pr/feat/2-pr2'),
|
|
272
|
-
];
|
|
273
|
-
// Both a.ts (PR 1) and b.ts (PR 2) import utils.ts (PR 3)
|
|
274
|
-
const graph = new Map([
|
|
275
|
-
['src/a.ts', new Set(['src/utils.ts'])],
|
|
276
|
-
['src/b.ts', new Set(['src/utils.ts'])],
|
|
277
|
-
['src/utils.ts', new Set()],
|
|
278
|
-
]);
|
|
279
|
-
const result = autoFixPROrdering(prs, graph);
|
|
280
|
-
// utils.ts should move to PR 1 (earliest needer)
|
|
281
|
-
const pr1Files = result.pullRequests[0].files?.map((f) => f.path) ?? [];
|
|
282
|
-
assert.ok(pr1Files.includes('src/utils.ts'));
|
|
283
|
-
});
|
|
284
|
-
void it('handles no dependencies at all', () => {
|
|
285
|
-
const prs = [
|
|
286
|
-
makePR(1, 'PR1', ['src/a.ts']),
|
|
287
|
-
makePR(2, 'PR2', ['src/b.ts'], 'pr/feat/1-pr1'),
|
|
288
|
-
];
|
|
289
|
-
const graph = new Map([
|
|
290
|
-
['src/a.ts', new Set()],
|
|
291
|
-
['src/b.ts', new Set()],
|
|
292
|
-
]);
|
|
293
|
-
const result = autoFixPROrdering(prs, graph);
|
|
294
|
-
assert.strictEqual(result.movedFiles.length, 0);
|
|
295
|
-
});
|
|
296
|
-
void it('handles single PR with all files', () => {
|
|
297
|
-
const prs = [makePR(1, 'Everything', ['src/a.ts', 'src/b.ts', 'src/c.ts'])];
|
|
298
|
-
const graph = new Map([
|
|
299
|
-
['src/a.ts', new Set(['src/b.ts'])],
|
|
300
|
-
['src/b.ts', new Set(['src/c.ts'])],
|
|
301
|
-
['src/c.ts', new Set()],
|
|
302
|
-
]);
|
|
303
|
-
const result = autoFixPROrdering(prs, graph);
|
|
304
|
-
assert.strictEqual(result.movedFiles.length, 0);
|
|
305
|
-
});
|
|
306
|
-
void it('does not mutate original PR files arrays', () => {
|
|
307
|
-
const originalFiles = [{ path: 'src/app.ts', change_type: 'modified' }];
|
|
308
|
-
const prs = [
|
|
309
|
-
{
|
|
310
|
-
sequence: 1,
|
|
311
|
-
name: 'PR1',
|
|
312
|
-
description: 'PR1',
|
|
313
|
-
files: originalFiles,
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
sequence: 2,
|
|
317
|
-
name: 'PR2',
|
|
318
|
-
description: 'PR2',
|
|
319
|
-
files: [{ path: 'src/utils.ts', change_type: 'modified' }],
|
|
320
|
-
},
|
|
321
|
-
];
|
|
322
|
-
const graph = new Map([
|
|
323
|
-
['src/app.ts', new Set(['src/utils.ts'])],
|
|
324
|
-
['src/utils.ts', new Set()],
|
|
325
|
-
]);
|
|
326
|
-
autoFixPROrdering(prs, graph);
|
|
327
|
-
// Original files array should not be modified
|
|
328
|
-
assert.strictEqual(originalFiles.length, 1);
|
|
329
|
-
assert.strictEqual(originalFiles[0].path, 'src/app.ts');
|
|
330
|
-
});
|
|
331
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure template-rendering logic for run sheets.
|
|
3
|
-
*
|
|
4
|
-
* The CLI is the sole authoritative renderer today — if the web app
|
|
5
|
-
* ever grows its own run-sheet generation path, it should call into
|
|
6
|
-
* this module (or a published copy of it) rather than forking.
|
|
7
|
-
*/
|
|
8
|
-
export declare const MAX_FILE_INCLUDE_BYTES: number;
|
|
9
|
-
export declare const MAX_TOTAL_FILE_BYTES: number;
|
|
10
|
-
export interface TemplateProduct {
|
|
11
|
-
name: string;
|
|
12
|
-
github_repository_full_name: string | null;
|
|
13
|
-
}
|
|
14
|
-
export interface TemplateRelease {
|
|
15
|
-
tag: string;
|
|
16
|
-
name: string | null;
|
|
17
|
-
body: string | null;
|
|
18
|
-
url: string | null;
|
|
19
|
-
published_at: string | null;
|
|
20
|
-
previous_tag: string | null;
|
|
21
|
-
previous_published_at: string | null;
|
|
22
|
-
diff_summary: string | null;
|
|
23
|
-
diff_stats: Record<string, unknown>;
|
|
24
|
-
}
|
|
25
|
-
export declare function isSafeGitRef(ref: string): boolean;
|
|
26
|
-
export interface FileReadResult {
|
|
27
|
-
content: string | null;
|
|
28
|
-
bytes: number;
|
|
29
|
-
reason?: string;
|
|
30
|
-
}
|
|
31
|
-
export declare function safeReadRepoFile(repoDir: string, relPath: string, remainingBudget: number): Promise<FileReadResult>;
|
|
32
|
-
export interface RenderResult {
|
|
33
|
-
rendered: string;
|
|
34
|
-
missing: string[];
|
|
35
|
-
filesRead: {
|
|
36
|
-
path: string;
|
|
37
|
-
bytes: number;
|
|
38
|
-
}[];
|
|
39
|
-
}
|
|
40
|
-
export interface TemplateCommit {
|
|
41
|
-
sha: string;
|
|
42
|
-
short_sha: string;
|
|
43
|
-
summary: string;
|
|
44
|
-
message: string;
|
|
45
|
-
author: string;
|
|
46
|
-
url: string;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Strip Markdown-style backslash escapes inside `{{ ... }}` spans so the
|
|
50
|
-
* Rich-text editor roundtrip doesn't break placeholder matching.
|
|
51
|
-
*/
|
|
52
|
-
export declare function normalizeTemplate(template: string): string;
|
|
53
|
-
/**
|
|
54
|
-
* Escape CommonMark-significant characters so untrusted strings
|
|
55
|
-
* (commit messages, author names, release bodies) can be safely
|
|
56
|
-
* dropped into a markdown run sheet without injecting headings,
|
|
57
|
-
* blockquotes, links, images, or HTML.
|
|
58
|
-
*/
|
|
59
|
-
export declare function escapeMarkdown(raw: string): string;
|
|
60
|
-
export declare function renderTemplate(template: string, product: TemplateProduct, release: TemplateRelease, repoDir: string | null, commits: string, draftNotice?: string, commitsList?: TemplateCommit[]): Promise<RenderResult>;
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure template-rendering logic for run sheets.
|
|
3
|
-
*
|
|
4
|
-
* The CLI is the sole authoritative renderer today — if the web app
|
|
5
|
-
* ever grows its own run-sheet generation path, it should call into
|
|
6
|
-
* this module (or a published copy of it) rather than forking.
|
|
7
|
-
*/
|
|
8
|
-
import { lstatSync, realpathSync, statSync } from 'fs';
|
|
9
|
-
import { readFile } from 'fs/promises';
|
|
10
|
-
import { join, resolve } from 'path';
|
|
11
|
-
export const MAX_FILE_INCLUDE_BYTES = 256 * 1024;
|
|
12
|
-
export const MAX_TOTAL_FILE_BYTES = 1024 * 1024;
|
|
13
|
-
export function isSafeGitRef(ref) {
|
|
14
|
-
if (typeof ref !== 'string' || ref.length === 0 || ref.length > 200) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
if (/\s/.test(ref) || /^[-.]/.test(ref)) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
if (ref.includes('..') || ref.includes('@{')) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return /^[A-Za-z0-9._\-+/@]+$/.test(ref);
|
|
24
|
-
}
|
|
25
|
-
export async function safeReadRepoFile(repoDir, relPath, remainingBudget) {
|
|
26
|
-
if (!relPath || relPath.startsWith('/') || relPath.includes('\0')) {
|
|
27
|
-
return { content: null, bytes: 0, reason: 'invalid path' };
|
|
28
|
-
}
|
|
29
|
-
const repoDirResolved = resolve(repoDir);
|
|
30
|
-
const abs = resolve(join(repoDirResolved, relPath));
|
|
31
|
-
if (abs !== repoDirResolved && !abs.startsWith(`${repoDirResolved}/`)) {
|
|
32
|
-
return { content: null, bytes: 0, reason: 'path escape' };
|
|
33
|
-
}
|
|
34
|
-
// Refuse symlinks at the leaf. `resolve()` only collapses `..`; it does
|
|
35
|
-
// not follow symlinks, so a symlink *inside* the repo pointing at
|
|
36
|
-
// `/etc/passwd` would otherwise be readable.
|
|
37
|
-
try {
|
|
38
|
-
if (lstatSync(abs).isSymbolicLink()) {
|
|
39
|
-
return { content: null, bytes: 0, reason: 'symlink refused' };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return { content: null, bytes: 0, reason: 'not found' };
|
|
44
|
-
}
|
|
45
|
-
// Also verify the fully-resolved real path still lives inside the repo
|
|
46
|
-
// root — catches symlinked parent directories.
|
|
47
|
-
try {
|
|
48
|
-
const realAbs = realpathSync(abs);
|
|
49
|
-
const realRoot = realpathSync(repoDirResolved);
|
|
50
|
-
if (realAbs !== realRoot && !realAbs.startsWith(`${realRoot}/`)) {
|
|
51
|
-
return { content: null, bytes: 0, reason: 'symlink escapes repo' };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
return { content: null, bytes: 0, reason: 'not found' };
|
|
56
|
-
}
|
|
57
|
-
let size;
|
|
58
|
-
try {
|
|
59
|
-
const stat = statSync(abs);
|
|
60
|
-
if (!stat.isFile()) {
|
|
61
|
-
return { content: null, bytes: 0, reason: 'not a file' };
|
|
62
|
-
}
|
|
63
|
-
;
|
|
64
|
-
({ size } = stat);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
return { content: null, bytes: 0, reason: 'not found' };
|
|
68
|
-
}
|
|
69
|
-
if (size > MAX_FILE_INCLUDE_BYTES) {
|
|
70
|
-
return {
|
|
71
|
-
content: null,
|
|
72
|
-
bytes: 0,
|
|
73
|
-
reason: `too large (${size} > ${MAX_FILE_INCLUDE_BYTES} bytes)`,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
if (size > remainingBudget) {
|
|
77
|
-
return {
|
|
78
|
-
content: null,
|
|
79
|
-
bytes: 0,
|
|
80
|
-
reason: 'total file-inclusion budget exhausted',
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
try {
|
|
84
|
-
const content = await readFile(abs, 'utf-8');
|
|
85
|
-
return { content, bytes: size };
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
return { content: null, bytes: 0, reason: 'read failed' };
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Strip Markdown-style backslash escapes inside `{{ ... }}` spans so the
|
|
93
|
-
* Rich-text editor roundtrip doesn't break placeholder matching.
|
|
94
|
-
*/
|
|
95
|
-
export function normalizeTemplate(template) {
|
|
96
|
-
return template.replace(/\{\{([^}]*)\}\}/g, (_match, inner) => `{{${inner.replace(/\\([_.\-\\/])/g, '$1')}}}`);
|
|
97
|
-
}
|
|
98
|
-
function isTruthy(value) {
|
|
99
|
-
if (!value) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
const v = value.trim();
|
|
103
|
-
return v !== '' && v !== 'false' && v !== '0';
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Split a block body on a top-level `{{else}}` so `{{#if}}A{{else}}B{{/if}}`
|
|
107
|
-
* resolves. Because we don't support nested same-keyword blocks, a naive
|
|
108
|
-
* first-occurrence split is safe enough.
|
|
109
|
-
*/
|
|
110
|
-
function splitOnElse(body) {
|
|
111
|
-
const m = body.match(/\{\{\s*else\s*\}\}/);
|
|
112
|
-
if (!m || m.index === undefined) {
|
|
113
|
-
return { main: body, alt: '' };
|
|
114
|
-
}
|
|
115
|
-
return {
|
|
116
|
-
main: body.slice(0, m.index),
|
|
117
|
-
alt: body.slice(m.index + m[0].length),
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Replace `{{#if key}}...{{else}}...{{/if}}` and
|
|
122
|
-
* `{{#unless key}}...{{else}}...{{/unless}}` blocks. Runs repeatedly
|
|
123
|
-
* until a fixed point so two sibling (non-nested) blocks both resolve.
|
|
124
|
-
* Nested blocks of the *same* keyword aren't supported; that's an
|
|
125
|
-
* intentional simplicity/safety choice.
|
|
126
|
-
*/
|
|
127
|
-
function substituteConditionals(template, ctx) {
|
|
128
|
-
const IF_RE = /\{\{\s*#if\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}([\s\S]*?)\{\{\s*\/if\s*\}\}/g;
|
|
129
|
-
const UNLESS_RE = /\{\{\s*#unless\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}([\s\S]*?)\{\{\s*\/unless\s*\}\}/g;
|
|
130
|
-
let out = template;
|
|
131
|
-
for (let i = 0; i < 5; i++) {
|
|
132
|
-
const before = out;
|
|
133
|
-
out = out.replace(IF_RE, (_, key, body) => {
|
|
134
|
-
const { main, alt } = splitOnElse(body);
|
|
135
|
-
return isTruthy(ctx[key] ?? '') ? main : alt;
|
|
136
|
-
});
|
|
137
|
-
out = out.replace(UNLESS_RE, (_, key, body) => {
|
|
138
|
-
const { main, alt } = splitOnElse(body);
|
|
139
|
-
return isTruthy(ctx[key] ?? '') ? alt : main;
|
|
140
|
-
});
|
|
141
|
-
if (out === before) {
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return out;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Expand `{{#each commits}}...{{/each}}`. Each iteration renders the body
|
|
149
|
-
* with a merged ctx of (outer vars + commit fields), running the full
|
|
150
|
-
* conditional + variable substitution on the body so `{{#if url}}` /
|
|
151
|
-
* `{{formatDate ...}}` / outer vars all work per-commit.
|
|
152
|
-
*/
|
|
153
|
-
function substituteEachCommits(template, commits, outerCtx) {
|
|
154
|
-
const EACH_RE = /\{\{\s*#each\s+commits\s*\}\}([\s\S]*?)\{\{\s*\/each\s*\}\}/g;
|
|
155
|
-
return template.replace(EACH_RE, (_match, body) => commits
|
|
156
|
-
.map((c) => {
|
|
157
|
-
const localCtx = {
|
|
158
|
-
...outerCtx,
|
|
159
|
-
sha: c.sha,
|
|
160
|
-
short_sha: c.short_sha,
|
|
161
|
-
summary: c.summary,
|
|
162
|
-
message: c.message,
|
|
163
|
-
author: c.author,
|
|
164
|
-
url: c.url,
|
|
165
|
-
};
|
|
166
|
-
let rendered = substituteConditionals(body, localCtx);
|
|
167
|
-
rendered = substituteDateHelper(rendered, localCtx);
|
|
168
|
-
rendered = substituteEscapeHelper(rendered, localCtx);
|
|
169
|
-
rendered = rendered.replace(/\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g, (match, key) => (key in localCtx ? localCtx[key] : match));
|
|
170
|
-
return rendered;
|
|
171
|
-
})
|
|
172
|
-
.join(''));
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Escape CommonMark-significant characters so untrusted strings
|
|
176
|
-
* (commit messages, author names, release bodies) can be safely
|
|
177
|
-
* dropped into a markdown run sheet without injecting headings,
|
|
178
|
-
* blockquotes, links, images, or HTML.
|
|
179
|
-
*/
|
|
180
|
-
export function escapeMarkdown(raw) {
|
|
181
|
-
if (!raw) {
|
|
182
|
-
return '';
|
|
183
|
-
}
|
|
184
|
-
// Backslash-escape every CommonMark-significant punctuation character.
|
|
185
|
-
// This also neutralises line-start markers (`#`, `>`, `-`, `+`, `*`,
|
|
186
|
-
// `1.`) because their first char always ends up escaped.
|
|
187
|
-
return raw.replace(/([\\`*_{}\[\]()#+\-.!|<>~])/g, '\\$1');
|
|
188
|
-
}
|
|
189
|
-
function substituteEscapeHelper(template, ctx) {
|
|
190
|
-
const RE = /\{\{\s*escape\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
191
|
-
return template.replace(RE, (_match, key) => escapeMarkdown(ctx[key] ?? ''));
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* `{{formatDate key 'YYYY-MM-DD HH:mm'}}` — resolves `key` from ctx (must
|
|
195
|
-
* be a parseable date), formats with a tiny token set. Invalid dates or
|
|
196
|
-
* empty values render as empty string (matches the "degrade gracefully"
|
|
197
|
-
* convention the rest of the template follows).
|
|
198
|
-
*/
|
|
199
|
-
function substituteDateHelper(template, ctx) {
|
|
200
|
-
const RE = /\{\{\s*formatDate\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+['"]([^'"]+)['"]\s*\}\}/g;
|
|
201
|
-
return template.replace(RE, (_match, key, format) => {
|
|
202
|
-
const raw = ctx[key];
|
|
203
|
-
if (!raw) {
|
|
204
|
-
return '';
|
|
205
|
-
}
|
|
206
|
-
const d = new Date(raw);
|
|
207
|
-
if (Number.isNaN(d.getTime())) {
|
|
208
|
-
return '';
|
|
209
|
-
}
|
|
210
|
-
const pad = (n) => n.toString().padStart(2, '0');
|
|
211
|
-
return format
|
|
212
|
-
.replace(/YYYY/g, String(d.getUTCFullYear()))
|
|
213
|
-
.replace(/MM/g, pad(d.getUTCMonth() + 1))
|
|
214
|
-
.replace(/DD/g, pad(d.getUTCDate()))
|
|
215
|
-
.replace(/HH/g, pad(d.getUTCHours()))
|
|
216
|
-
.replace(/mm/g, pad(d.getUTCMinutes()))
|
|
217
|
-
.replace(/ss/g, pad(d.getUTCSeconds()));
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
async function expandFileIncludes(template, repoDir) {
|
|
221
|
-
const missing = [];
|
|
222
|
-
const filesRead = [];
|
|
223
|
-
const fileRegex = /\{\{\s*file:([^}]+?)\s*\}\}/g;
|
|
224
|
-
const fileMatches = [];
|
|
225
|
-
for (const m of template.matchAll(fileRegex)) {
|
|
226
|
-
fileMatches.push({ match: m[0], path: m[1].trim() });
|
|
227
|
-
}
|
|
228
|
-
let remainingBudget = MAX_TOTAL_FILE_BYTES;
|
|
229
|
-
const fileResults = new Map();
|
|
230
|
-
for (const { match, path } of fileMatches) {
|
|
231
|
-
if (fileResults.has(match)) {
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (!repoDir) {
|
|
235
|
-
missing.push(`file:${path} (no repo)`);
|
|
236
|
-
fileResults.set(match, `<!-- file ${path} unavailable: repo not cloned -->`);
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
const res = await safeReadRepoFile(repoDir, path, remainingBudget);
|
|
240
|
-
if (res.content === null) {
|
|
241
|
-
missing.push(`file:${path} (${res.reason ?? 'unavailable'})`);
|
|
242
|
-
fileResults.set(match, `<!-- file ${path} unavailable: ${res.reason ?? 'unknown'} -->`);
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
remainingBudget -= res.bytes;
|
|
246
|
-
filesRead.push({ path, bytes: res.bytes });
|
|
247
|
-
fileResults.set(match, res.content);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
const rendered = template.replace(fileRegex, (match) => fileResults.get(match) ?? match);
|
|
251
|
-
return { rendered, missing, filesRead };
|
|
252
|
-
}
|
|
253
|
-
function buildSimpleVars(product, release, commits, draftNotice) {
|
|
254
|
-
const stats = release.diff_stats ?? {};
|
|
255
|
-
return {
|
|
256
|
-
product_name: product.name,
|
|
257
|
-
release_tag: release.tag,
|
|
258
|
-
release_name: release.name ?? release.tag,
|
|
259
|
-
release_body: release.body ?? '',
|
|
260
|
-
release_url: release.url ?? '',
|
|
261
|
-
previous_tag: release.previous_tag ?? '',
|
|
262
|
-
published_at: release.published_at ?? '',
|
|
263
|
-
previous_published_at: release.previous_published_at ?? '',
|
|
264
|
-
diff_summary: release.diff_summary ?? '',
|
|
265
|
-
files_changed: String(stats.files_changed ?? ''),
|
|
266
|
-
additions: String(stats.additions ?? ''),
|
|
267
|
-
deletions: String(stats.deletions ?? ''),
|
|
268
|
-
commits_count: String(stats.commits_count ?? stats.total_commits ?? ''),
|
|
269
|
-
repository: product.github_repository_full_name ?? '',
|
|
270
|
-
generated_at: new Date().toISOString(),
|
|
271
|
-
commits,
|
|
272
|
-
draft_notice: draftNotice,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
export async function renderTemplate(template, product, release, repoDir, commits, draftNotice = '', commitsList = []) {
|
|
276
|
-
const missing = [];
|
|
277
|
-
const simpleVars = buildSimpleVars(product, release, commits, draftNotice);
|
|
278
|
-
// Pipeline: normalize → file includes → #each (self-contained, renders
|
|
279
|
-
// its body with per-commit ctx) → outer #if/#unless → date helper →
|
|
280
|
-
// variable substitution. Running `#each` first lets it fully resolve
|
|
281
|
-
// per-commit `{{#if url}}` without bleeding into outer-scope `{{#if}}`.
|
|
282
|
-
const normalized = normalizeTemplate(template);
|
|
283
|
-
const fileExpansion = await expandFileIncludes(normalized, repoDir);
|
|
284
|
-
missing.push(...fileExpansion.missing);
|
|
285
|
-
let rendered = substituteEachCommits(fileExpansion.rendered, commitsList, simpleVars);
|
|
286
|
-
rendered = substituteConditionals(rendered, simpleVars);
|
|
287
|
-
rendered = substituteDateHelper(rendered, simpleVars);
|
|
288
|
-
rendered = substituteEscapeHelper(rendered, simpleVars);
|
|
289
|
-
rendered = rendered.replace(/\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g, (match, key) => {
|
|
290
|
-
if (key in simpleVars) {
|
|
291
|
-
return simpleVars[key];
|
|
292
|
-
}
|
|
293
|
-
missing.push(key);
|
|
294
|
-
return match;
|
|
295
|
-
});
|
|
296
|
-
return { rendered, missing, filesRead: fileExpansion.filesRead };
|
|
297
|
-
}
|