@joshuafolkken/kit 1.1010.0 → 1.1035.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.json +1 -5
- package/.claude/skills/dependency-update/SKILL.md +6 -3
- package/.claude/skills/epic-commands/SKILL.md +46 -17
- package/.claude/skills/workflow-commands/SKILL.md +8 -23
- package/.claude/skills/workflow-commands/backlogrun-child.md +4 -2
- package/.claude/skills/workflow-commands/backlogrun.md +3 -12
- package/.claude/skills/workflow-commands/fullrun-steps.md +4 -3
- package/.claude/skills/workflow-commands/fullrun.md +1 -1
- package/.claude/skills/workflow-commands/halfrun.md +2 -1
- package/.claude/skills/workflow-commands/into-target.md +1 -1
- package/.claude/skills/workflow-commands/observation-filing.md +42 -43
- package/.claude/skills/workflow-commands/prerequisite.md +1 -1
- package/.codex/hooks.json +1 -5
- package/.github/workflows/sonar-qube.yml +1 -1
- package/AGENTS.md +4 -25
- package/CLAUDE.md +24 -38
- package/GEMINI.md +4 -24
- package/README.md +22 -56
- package/dist/CLAUDE.md +24 -38
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-WMIR5SNX.js → chunk-D67KVGGY.js} +3 -3
- package/dist/hooks/{chunk-EZLHXKJ6.js → chunk-EIFCAJRB.js} +70 -27
- package/dist/hooks/{chunk-KPZN42RT.js → chunk-GJT4BNVE.js} +3 -3
- package/dist/hooks/{chunk-PAXMLGSS.js → chunk-GLBDBJOK.js} +44 -24
- package/dist/hooks/{chunk-GBJUERYK.js → chunk-HOYJU5RM.js} +1 -1
- package/dist/hooks/{chunk-6PSTVOLH.js → chunk-HU66PWWL.js} +33 -57
- package/dist/hooks/{chunk-A2H5I2VD.js → chunk-KG6PZD72.js} +2 -2
- package/dist/hooks/{chunk-AWTFKKFW.js → chunk-XPLP27WA.js} +3 -8
- package/dist/hooks/{chunk-4GDR2YTV.js → chunk-Y27M6A7X.js} +4 -4
- package/dist/hooks/{chunk-56LGMJJV.js → chunk-ZXNE6NY3.js} +2 -2
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +9 -9
- package/dist/hooks/stop-guard.js +11 -15
- package/dist/josh.js +38 -19
- package/dist/version/index.js +93 -41
- package/eslint/base.js +2 -11
- package/package.json +31 -5
- package/prompts/coding-standards.md +15 -290
- package/prompts/collaboration-workflow/cross-repo-epic.md +2 -51
- package/prompts/collaboration-workflow/epic-audit.md +2 -53
- package/prompts/collaboration-workflow/epic-bundle.md +2 -106
- package/prompts/collaboration-workflow/issue-template.md +4 -4
- package/prompts/collaboration-workflow/operating-rules.md +18 -75
- package/prompts/collaboration-workflow/principles.md +74 -0
- package/prompts/collaboration-workflow/residency.md +54 -14
- package/prompts/collaboration-workflow/rule-delivery.md +1 -11
- package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
- package/prompts/collaboration-workflow.md +22 -28
- package/scripts/adopt/adopt-logic.ts +2 -2
- package/scripts/adopt/adopt-toolkits.ts +1 -1
- package/scripts/adopt/adopt.ts +2 -2
- package/scripts/agent/agent-event.ts +2 -9
- package/scripts/agent/agent-exit-record.ts +2 -9
- package/scripts/backlog/backlog-budget-cli.ts +2 -6
- package/scripts/backlog/backlog-drive-cli.ts +20 -10
- package/scripts/backlog/backlog-drive.ts +50 -16
- package/scripts/backlog/backlog-offer-cli.ts +6 -5
- package/scripts/backlog/backlog-plan.ts +1 -1
- package/scripts/build/build-bin.ts +2 -1
- package/scripts/build/build-config-merge.ts +2 -1
- package/scripts/build/build-hooks.ts +24 -4
- package/scripts/build/build-managed-marker.ts +2 -1
- package/scripts/build/build-self-sync-guard.ts +2 -1
- package/scripts/build/build-version.ts +2 -1
- package/scripts/cases/cases-logic.ts +2 -6
- package/scripts/ci/pr-classification.ts +13 -11
- package/scripts/cost-runtime/cost-transcript.ts +4 -11
- package/scripts/doctor/doctor-consumer.ts +5 -12
- package/scripts/doctor/doctor-ports.ts +2 -2
- package/scripts/document/document-byte-budget.ts +8 -16
- package/scripts/document/document-section.ts +2 -6
- package/scripts/document/entry-read-budget.ts +1 -1
- package/scripts/{git/git-epic-add-body.ts → epic/epic-add-body.ts} +23 -23
- package/scripts/{git/git-epic-add-plan.ts → epic/epic-add-plan.ts} +23 -26
- package/scripts/{git/git-epic-add.ts → epic/epic-add.ts} +17 -17
- package/scripts/epic/epic-audit-cli.ts +4 -4
- package/scripts/epic/epic-audit-orphans.ts +2 -2
- package/scripts/epic/epic-audit-rationale.ts +1 -1
- package/scripts/epic/epic-audit.ts +1 -1
- package/scripts/{git/git-epic-body.ts → epic/epic-body.ts} +6 -6
- package/scripts/epic/epic-bundle-cli.ts +1 -1
- package/scripts/epic/epic-bundle.ts +2 -2
- package/scripts/epic/epic-candidate-confirm.ts +2 -1
- package/scripts/{git/git-epic-chains.ts → epic/epic-chains.ts} +4 -4
- package/{scripts-ai → scripts/epic}/epic-check.ts +5 -4
- package/{scripts-ai → scripts/epic}/epic-cli.ts +4 -4
- package/scripts/{git/git-epic-close-comment.ts → epic/epic-close-comment.ts} +9 -9
- package/scripts/{git/git-epic-close.ts → epic/epic-close.ts} +23 -19
- package/scripts/epic/epic-cross-repo.ts +21 -38
- package/scripts/{git/git-epic-decision.ts → epic/epic-decision.ts} +12 -14
- package/scripts/epic/epic-fetch.ts +3 -3
- package/scripts/epic/epic-graph.ts +3 -3
- package/scripts/epic/epic-index.ts +2 -2
- package/scripts/epic/epic-issue.ts +1 -1
- package/scripts/epic/epic-next.ts +3 -3
- package/scripts/{git/git-epic-parse.ts → epic/epic-parse.ts} +3 -3
- package/scripts/{git/git-epic-promote.ts → epic/epic-promote.ts} +10 -10
- package/scripts/{git/git-epic-read.ts → epic/epic-read.ts} +9 -9
- package/scripts/{git/git-epic-reconcile.ts → epic/epic-reconcile.ts} +18 -20
- package/scripts/{git/git-epic-reference.ts → epic/epic-reference.ts} +4 -23
- package/scripts/epic/epic-relation-recheck.ts +4 -3
- package/scripts/{git/git-epic-relations.ts → epic/epic-relations.ts} +5 -5
- package/scripts/{git/git-epic-remove-plan.ts → epic/epic-remove-plan.ts} +17 -19
- package/scripts/{git/git-epic-remove.ts → epic/epic-remove.ts} +13 -13
- package/scripts/{git/git-epic-run.ts → epic/epic-run.ts} +27 -27
- package/scripts/{git/git-epic-sections.ts → epic/epic-sections.ts} +6 -6
- package/scripts/{git/git-epic-shape.ts → epic/epic-shape.ts} +7 -7
- package/scripts/{git/git-epic-validate.ts → epic/epic-validate.ts} +13 -13
- package/{scripts-ai → scripts/epic}/epic.ts +17 -16
- package/scripts/gh/fix-gh-packages.ts +2 -1
- package/scripts/gh/gh-spawn.ts +12 -10
- package/scripts/git/constants.ts +1 -1
- package/scripts/git/git-branch.ts +10 -1
- package/scripts/git/git-command.ts +1 -1
- package/scripts/git/git-error.ts +2 -5
- package/{scripts-ai → scripts/git}/git-followup-finish.ts +7 -7
- package/scripts/git/git-followup-flush.ts +74 -48
- package/scripts/git/git-followup-issue-close.ts +2 -2
- package/scripts/git/git-followup-label.ts +1 -1
- package/scripts/git/git-followup-pending.ts +1 -1
- package/{scripts-ai → scripts/git}/git-followup-workflow.ts +23 -11
- package/scripts/git/git-gh-exec.ts +85 -26
- package/scripts/git/git-gh-issue-read.ts +2 -2
- package/scripts/git/git-gh-issue-rest.ts +2 -2
- package/scripts/git/git-gh-issue-write.ts +6 -6
- package/scripts/git/git-gh-pr-read.ts +0 -21
- package/scripts/git/git-gh-pr.ts +2 -23
- package/scripts/git/git-pr-followup-wrapup.ts +2 -6
- package/scripts/git/git-preflight.ts +3 -6
- package/scripts/git/git-staging.ts +21 -9
- package/{scripts-ai → scripts/git}/git-workflow.ts +11 -11
- package/scripts/git/github-issue-url.ts +1 -1
- package/scripts/git/issue-labels.ts +1 -1
- package/scripts/git/issue-reference.ts +19 -0
- package/scripts/git/main-merge.ts +2 -1
- package/scripts/git/main-sync.ts +3 -2
- package/scripts/git/schemas.ts +1 -1
- package/scripts/git/stash-pop-args.ts +7 -13
- package/scripts/git/stash-pop-cli.ts +2 -1
- package/{scripts-ai → scripts/git}/telegram-test-logic.ts +2 -2
- package/{scripts-ai → scripts/git}/telegram-test.ts +7 -7
- package/scripts/hooks/format-rewrite-notice.ts +2 -8
- package/scripts/init/init-ai-copy.ts +2 -5
- package/scripts/init/init.ts +8 -4
- package/scripts/init/start-steps.ts +2 -1
- package/scripts/init/start.ts +2 -1
- package/scripts/issue/issue-comment-cli.ts +2 -1
- package/scripts/issue/issue-file-cli.ts +2 -1
- package/scripts/issue/issue-fold-cli.ts +9 -16
- package/scripts/issue/issue-scout-cli.ts +8 -13
- package/scripts/issue/measure-rerun-cli.ts +7 -6
- package/scripts/josh/josh-commands-ai.ts +2 -2
- package/scripts/josh/josh-commands-backlog.ts +1 -1
- package/scripts/josh/josh-commands-development.ts +1 -1
- package/scripts/josh/josh-commands-workflow.ts +4 -4
- package/scripts/lane/lane-cli.ts +2 -1
- package/scripts/lane/lane-open.ts +3 -2
- package/scripts/lane/lane-registry.ts +3 -6
- package/scripts/lib/cli-flags.ts +20 -2
- package/scripts/lib/error-message.ts +9 -0
- package/scripts/lib/read-file.ts +26 -2
- package/scripts/observations/observation-ledger-home.ts +98 -26
- package/scripts/observations/observation-ledger-migrate.ts +26 -21
- package/scripts/observations/observation-ledger-prepare.ts +10 -20
- package/scripts/observations/observation-ledger.ts +58 -25
- package/scripts/observations/observations-flush-cli.ts +6 -23
- package/scripts/observations/observations-flush-landing.ts +2 -1
- package/scripts/observations/observations-flush.ts +29 -20
- package/scripts/package/package-scout-cli.ts +8 -16
- package/scripts/ports/port-command.ts +2 -1
- package/scripts/propagate/propagate-publish.ts +6 -7
- package/scripts/propagate/propagate-steps.ts +2 -1
- package/scripts/propagate/propagate.ts +3 -2
- package/scripts/refactor/import-graph.ts +2 -6
- package/scripts/registry-migration/migrate.ts +3 -2
- package/scripts/registry-migration/user-npmrc.ts +2 -2
- package/scripts/release/release-cli.ts +2 -1
- package/scripts/repo/repo-setting.ts +10 -8
- package/scripts/review/review-finding-ledger.ts +3 -3
- package/scripts/review/review-findings-cli.ts +4 -11
- package/scripts/review/review-record-cli.ts +14 -11
- package/scripts/review/review-record.ts +6 -16
- package/scripts/rules/decision-oracle.ts +2 -2
- package/scripts/rules/rule-body-guard.ts +2 -2
- package/scripts/rules/rule-value-cache.ts +99 -0
- package/scripts/rules/rule-value-cli.ts +10 -9
- package/scripts/rules/rule-value.ts +1 -1
- package/scripts/run/run-carry-args.ts +2 -6
- package/scripts/run/run-carry-cli.ts +5 -7
- package/scripts/run/run-cut-args.ts +7 -13
- package/scripts/run/run-ending-cli.ts +4 -7
- package/scripts/run/run-event-stream.ts +2 -5
- package/scripts/run/run-liveness-cli.ts +4 -7
- package/scripts/run/run-progress-args.ts +2 -6
- package/scripts/run/run-progress-cli.ts +2 -1
- package/scripts/run/run-tail-cli.ts +3 -3
- package/scripts/run/run-tidy-stashes.ts +7 -14
- package/scripts/run/run-wake-cli.ts +2 -6
- package/scripts/run/run-wake-driver.ts +15 -2
- package/scripts/run/run-wake-session.ts +14 -4
- package/scripts/safe-chain/project-config.ts +3 -6
- package/scripts/security/security-audit-provision.ts +6 -7
- package/scripts/sonar/sonar-hotspots-cli.ts +2 -1
- package/scripts/sync/directory-copy-guard.ts +2 -1
- package/scripts/sync/sync-ai-files.ts +3 -3
- package/scripts/sync/template-source-logic.ts +3 -4
- package/scripts/test/e2e-retry-check.ts +3 -6
- package/scripts/ui/ui-routes-cli.ts +3 -6
- package/scripts/version/bump-version.ts +2 -1
- package/scripts/version/version-remote.ts +18 -27
- package/scripts/version/version-targets.ts +3 -3
- package/.claude/skills/workflow-commands/rule-residency.md +0 -267
- package/evals/scenarios/consult-not-execute.json +0 -20
- package/evals/scenarios/no-implicit-workflow.json +0 -26
- package/evals/scenarios/overrides-both-locations.json +0 -29
- package/evals/scenarios/upstream-interrupt.json +0 -23
- package/evals/scenarios/workflow-skill-loaded.json +0 -16
- package/prompts/agent-lint-protocol.json +0 -79
- package/prompts/agent-rules.md +0 -63
- package/prompts/collaboration-workflow/consultation-vs-execution.md +0 -8
- package/prompts/collaboration-workflow/distributed-docs.md +0 -7
- package/prompts/collaboration-workflow/durable-rules.md +0 -24
- package/prompts/collaboration-workflow/latest-first.md +0 -14
- package/prompts/collaboration-workflow/no-clones.md +0 -11
- package/prompts/collaboration-workflow/simplicity-first.md +0 -9
- package/prompts/collaboration-workflow/single-source-rules.md +0 -13
- package/scripts/build/shim-shell.ts +0 -25
- package/scripts/claude/skill-meta.ts +0 -37
- package/scripts/document/document-scan.ts +0 -108
- package/scripts/document/generate-catalog.ts +0 -69
- package/scripts/document/retired-phrases.ts +0 -143
- package/scripts/document/review-agent-type.ts +0 -46
- package/scripts/document/single-source.ts +0 -73
- package/scripts/git/git-fixture-workspace.ts +0 -88
- package/scripts/hooks/format-edited-file-fixtures.ts +0 -109
- package/scripts/hooks/prompt-hooks.ts +0 -38
- package/scripts/init/hook-command-bootstrap.ts +0 -83
- package/scripts/issue/issue-logic.ts +0 -50
- package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +0 -1227
- package/scripts/josh/josh-script-reader.ts +0 -11
- package/scripts/package/production-dependency-graph.ts +0 -68
- package/scripts/retrospective/retrospective-cli.ts +0 -97
- package/scripts/retrospective/retrospective.ts +0 -127
- package/scripts/rules/delivered-rules-harness.ts +0 -72
- package/scripts/rules/top-level-scripts-guard.ts +0 -47
- package/scripts/run/run-carry-flush.ts +0 -58
- package/scripts/run/run-transcript.golden.txt +0 -57
- package/scripts/run/run-wake-work.ts +0 -108
- package/scripts/sync/dependabot-pin-logic.ts +0 -135
- package/scripts/test/classify-isolation.ts +0 -149
- package/scripts/test/http-fault-injection.ts +0 -79
- package/scripts/test/josh-harness-environment.ts +0 -260
- package/scripts/test/josh-harness.ts +0 -96
- package/scripts/test/pilot-files.ts +0 -452
- package/scripts/test/pilot-measure.ts +0 -78
- package/scripts/test/test-network-guard.ts +0 -453
- package/scripts/test/test-repository-guard.ts +0 -317
- package/scripts/test/test-state-guard.ts +0 -85
- package/scripts/test/test-stdout-guard.ts +0 -54
- package/scripts/test/test-telegram-guard.ts +0 -90
- package/scripts/test/unit-guard-environment.ts +0 -12
- package/scripts/test/unit-projects.ts +0 -139
- package/scripts/test/vitest-include-globs.ts +0 -12
- package/scripts/time-runtime/time-batch-guard-fixtures.ts +0 -66
- package/scripts-ai/completion-gate.ts +0 -13
- package/scripts-ai/environment-loader.ts +0 -9
- /package/{scripts-ai → scripts/epic}/epic-cli-argv.ts +0 -0
- /package/{scripts-ai → scripts/epic}/epic-cli-remove.ts +0 -0
- /package/{scripts-ai → scripts/git}/followup-issue-number.ts +0 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { EPIC_LABEL, has_label_name } from '#scripts/git/issue-labels'
|
|
2
|
+
import { parse_json_object_safe } from '#scripts/git/parse-json-array'
|
|
3
|
+
import { epic_subject_schema } from '#scripts/git/schemas'
|
|
4
|
+
import { epic_parse, type DeclarationState } from './epic-parse'
|
|
5
5
|
|
|
6
6
|
// The four requirements an epic has to satisfy are otherwise enforced only by an agent reading the
|
|
7
7
|
// procedure carefully, and three of the four fail silently: a missing label or a bare `#N` child
|
|
8
|
-
// list makes `
|
|
8
|
+
// list makes `epic-close.ts` skip the epic forever, and prose dependencies make the batch read
|
|
9
9
|
// as unordered so a skipped `--add-blocked-by` is never reported. Checking them here reuses
|
|
10
|
-
// `
|
|
10
|
+
// `epic-parse.ts` rather than restating the patterns, so "what the auto-close can read" and
|
|
11
11
|
// "what this check accepts" are one definition instead of two that can drift.
|
|
12
12
|
|
|
13
13
|
interface EpicSubject {
|
|
14
14
|
number: number
|
|
15
15
|
// The epic's own state, as GitHub returned it (`OPEN` / `CLOSED`, casing unnormalized). Only
|
|
16
|
-
// `
|
|
16
|
+
// `epic-add.ts` reads it — to refuse adding a child to a closed epic — so it is optional: a read
|
|
17
17
|
// that came back without the field leaves it undefined, which the refusal treats as "not confirmed
|
|
18
18
|
// closed" rather than blocking (joshuafolkken/kit#2337).
|
|
19
19
|
state?: string | undefined
|
|
@@ -65,7 +65,7 @@ function format_children(children: ReadonlyArray<number>): string {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function check_task_list(subject: EpicSubject): CheckResult {
|
|
68
|
-
const children =
|
|
68
|
+
const children = epic_parse.parse_task_list_issue_numbers(subject.body)
|
|
69
69
|
const is_passing = children.length > 0
|
|
70
70
|
|
|
71
71
|
return {
|
|
@@ -94,11 +94,11 @@ function describe_dependencies(state: DeclarationState): string {
|
|
|
94
94
|
// each of them. The literal is compared against the constant the generator emits, and the chain
|
|
95
95
|
// against the one the link reader parses, so no two of them can drift into disagreement.
|
|
96
96
|
function check_dependencies(subject: EpicSubject): CheckResult {
|
|
97
|
-
const state =
|
|
97
|
+
const state = epic_parse.read_declaration(subject.body)
|
|
98
98
|
|
|
99
99
|
return {
|
|
100
100
|
name: 'dependencies section',
|
|
101
|
-
is_passing:
|
|
101
|
+
is_passing: epic_parse.is_declaration_readable(state),
|
|
102
102
|
detail: describe_dependencies(state),
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -107,7 +107,7 @@ function check_dependencies(subject: EpicSubject): CheckResult {
|
|
|
107
107
|
// deliberately leaves such an epic open. Reporting it here is what turns "stayed open silently"
|
|
108
108
|
// into "was told to close it manually".
|
|
109
109
|
function check_external_children(subject: EpicSubject): CheckResult {
|
|
110
|
-
const has_external =
|
|
110
|
+
const has_external = epic_parse.has_external_task_list_entry(subject.body)
|
|
111
111
|
|
|
112
112
|
return {
|
|
113
113
|
name: 'auto-close eligibility',
|
|
@@ -144,12 +144,12 @@ function format_check_report(epic_number: number, results: ReadonlyArray<CheckRe
|
|
|
144
144
|
return [...lines, '', summary].join('\n')
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
const
|
|
147
|
+
const epic_validate = {
|
|
148
148
|
parse_epic_subject,
|
|
149
149
|
validate_epic,
|
|
150
150
|
is_epic_valid,
|
|
151
151
|
format_check_report,
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export {
|
|
154
|
+
export { epic_validate }
|
|
155
155
|
export type { CheckResult, EpicSubject }
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Create an epic Issue that satisfies every requirement the auto-close and the order warning read.
|
|
4
4
|
*
|
|
5
|
-
* Usage: tsx scripts
|
|
5
|
+
* Usage: tsx scripts/epic/epic.ts "<title>" <N1> <N2> ... [--ordered] [--rationale-file <path|->]
|
|
6
6
|
* [--origin <owner/repo#N>]
|
|
7
|
-
* tsx scripts
|
|
8
|
-
* tsx scripts
|
|
7
|
+
* tsx scripts/epic/epic.ts --promote <N> <N1> <N2> ... [same flags]
|
|
8
|
+
* tsx scripts/epic/epic.ts --add <E> <N1> <N2> ... [--before <M> | --after <M>]
|
|
9
9
|
* [--decision-file <path|->]
|
|
10
|
-
* tsx scripts
|
|
10
|
+
* tsx scripts/epic/epic.ts --remove <E> <M> <N> ... [--decision-file <path|->]
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { git_epic_run } from '../scripts/git/git-epic-run'
|
|
16
|
-
import { git_gh_command } from '../scripts/git/git-gh-command'
|
|
12
|
+
import { git_gh_command } from '#scripts/git/git-gh-command'
|
|
13
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
14
|
+
import { epic_add, type AddChildrenInput } from './epic-add'
|
|
17
15
|
import { epic_cli, type AddArguments, type CrossRepoAddTarget } from './epic-cli'
|
|
16
|
+
import { epic_reconcile } from './epic-reconcile'
|
|
17
|
+
import { epic_remove } from './epic-remove'
|
|
18
|
+
import { epic_run } from './epic-run'
|
|
18
19
|
|
|
19
20
|
const ARGV_OFFSET = 2
|
|
20
21
|
const FLAGS = '[--ordered] [--rationale-file <path|->] [--origin <owner/repo#N>]'
|
|
@@ -37,7 +38,7 @@ async function run_promotion(argv: ReadonlyArray<string>): Promise<number> {
|
|
|
37
38
|
return FAILURE_EXIT_CODE
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
return await
|
|
41
|
+
return await epic_run.promote_epic({
|
|
41
42
|
epic_number: parsed.epic_number,
|
|
42
43
|
children: parsed.children,
|
|
43
44
|
rationale: epic_cli.read_rationale(parsed.rationale_path),
|
|
@@ -67,7 +68,7 @@ function to_add_input(parsed: AddArguments): AddChildrenInput {
|
|
|
67
68
|
async function run_qualified_addition(found: CrossRepoAddTarget): Promise<number> {
|
|
68
69
|
const local = epic_cli.resolve_local_add(found, await git_gh_command.repo_get_name_with_owner())
|
|
69
70
|
|
|
70
|
-
if (local !== undefined) return await
|
|
71
|
+
if (local !== undefined) return await epic_add.add_children(to_add_input(local))
|
|
71
72
|
|
|
72
73
|
console.error(epic_cli.format_cross_repo_refusal(found))
|
|
73
74
|
|
|
@@ -109,7 +110,7 @@ async function run_addition(argv: ReadonlyArray<string>): Promise<number> {
|
|
|
109
110
|
|
|
110
111
|
if (parsed === undefined) return await refuse_addition(argv)
|
|
111
112
|
|
|
112
|
-
return await
|
|
113
|
+
return await epic_add.add_children(to_add_input(parsed))
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// Deleting a declared order. No position and no `--ordered`: the path itself says which orders go,
|
|
@@ -126,7 +127,7 @@ async function run_removal(argv: ReadonlyArray<string>): Promise<number> {
|
|
|
126
127
|
return FAILURE_EXIT_CODE
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
return await
|
|
130
|
+
return await epic_remove.remove_order({
|
|
130
131
|
epic_number: parsed.epic_number,
|
|
131
132
|
path: parsed.path,
|
|
132
133
|
decision: epic_cli.read_decision(parsed.decision_path),
|
|
@@ -144,7 +145,7 @@ async function run_reconciliation(argv: ReadonlyArray<string>): Promise<number>
|
|
|
144
145
|
return FAILURE_EXIT_CODE
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
return await
|
|
148
|
+
return await epic_reconcile.reconcile_epic(parsed.epic_number)
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
async function run_creation(argv: ReadonlyArray<string>): Promise<number> {
|
|
@@ -156,7 +157,7 @@ async function run_creation(argv: ReadonlyArray<string>): Promise<number> {
|
|
|
156
157
|
return FAILURE_EXIT_CODE
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
return await
|
|
160
|
+
return await epic_run.create_epic({
|
|
160
161
|
title: parsed.title,
|
|
161
162
|
children: parsed.children,
|
|
162
163
|
rationale: epic_cli.read_rationale(parsed.rationale_path),
|
|
@@ -187,6 +188,6 @@ async function main(): Promise<void> {
|
|
|
187
188
|
try {
|
|
188
189
|
await main()
|
|
189
190
|
} catch (error) {
|
|
190
|
-
console.error(`✖ ${
|
|
191
|
+
console.error(`✖ ${error_text.message_of(error)}`)
|
|
191
192
|
process.exit(FAILURE_EXIT_CODE)
|
|
192
193
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { file_reader } from '#scripts/lib/read-file'
|
|
4
5
|
import { z } from 'zod'
|
|
5
6
|
import { fix_gh_packages_logic, type LockfilePackage } from './fix-gh-packages-logic'
|
|
6
7
|
import { gh_cli_token } from './gh-cli-token'
|
|
@@ -19,7 +20,7 @@ const npm_packument_schema = z.looseObject({
|
|
|
19
20
|
type ParsedPackages = Record<string, LockfilePackage>
|
|
20
21
|
|
|
21
22
|
function read_file(file_path: string): string {
|
|
22
|
-
return
|
|
23
|
+
return file_reader.read_file_or_empty(file_path)
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
// Resolution order: NODE_AUTH_TOKEN → a literal token in the project .npmrc → `gh auth token`.
|
package/scripts/gh/gh-spawn.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { git_gh_api_path } from '#scripts/git/git-gh-api-path'
|
|
2
2
|
import { git_gh_exec } from '#scripts/git/git-gh-exec'
|
|
3
3
|
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
4
|
-
import { execaSync } from 'execa'
|
|
5
4
|
|
|
6
5
|
// The synchronous twin of `git_gh_repo.repo_get_name_with_owner`: same fact, read the same way, but
|
|
7
|
-
//
|
|
6
|
+
// synchronously because `josh init` / `josh sync` / `josh doctor` decide before they can await.
|
|
8
7
|
// It asks REST for the same reason — `gh repo view` goes through GraphQL, which a cloud session is
|
|
9
8
|
// refused (403), and a repository that reads as unresolved makes `init` / `sync` skip
|
|
10
9
|
// `sonar-project.properties` outright (joshuafolkken/kit#1023). The path comes from the shared
|
|
11
10
|
// builder rather than being spelled out again here.
|
|
12
11
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
12
|
+
// An unbounded lookup asks for `NO_BUDGET`, execa's own "no timeout": the shared layer otherwise
|
|
13
|
+
// applies its default budget, which would change what `init` / `sync` wait for.
|
|
14
|
+
const NO_BUDGET = 0
|
|
15
|
+
|
|
15
16
|
function fetch_repo_name(timeout_ms: number | undefined): string | undefined {
|
|
16
|
-
const
|
|
17
|
-
|
|
17
|
+
const stdout = git_gh_exec.read_gh_api_sync({
|
|
18
|
+
path: git_gh_api_path.repo_api_path(),
|
|
19
|
+
jq_filter: '.full_name',
|
|
18
20
|
cwd: PROJECT_ROOT,
|
|
19
|
-
|
|
20
|
-
...(timeout_ms !== undefined && { timeout: timeout_ms }),
|
|
21
|
+
timeout_ms: timeout_ms ?? NO_BUDGET,
|
|
21
22
|
})
|
|
22
|
-
if (result.exitCode !== 0 || !result.stdout) return undefined
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
const name = stdout?.trim()
|
|
25
|
+
|
|
26
|
+
return name === '' ? undefined : name
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
// The unbounded lookup, for callers whose *writes* depend on the answer. A timeout would surface as
|
package/scripts/git/constants.ts
CHANGED
|
@@ -10,7 +10,7 @@ const GIT_COMMAND_UNIX = '/usr/bin/git'
|
|
|
10
10
|
// modules (joshuafolkken/kit#1640) and a copy in each is a second answer to one question.
|
|
11
11
|
const PORCELAIN_FLAG = '--porcelain'
|
|
12
12
|
// The untracked-files mode every porcelain status reading passes (`git-command.ts` carries why it is
|
|
13
|
-
// passed and why it is `all`), shared so
|
|
13
|
+
// passed and why it is `all`), shared so another module's own reading cannot drift from it.
|
|
14
14
|
const UNTRACKED_FILES_FLAG = '--untracked-files=all'
|
|
15
15
|
|
|
16
16
|
function get_git_command(): string {
|
|
@@ -75,7 +75,7 @@ async function pull_latest(): Promise<void> {
|
|
|
75
75
|
)
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const ISSUE_PREFIX_PATTERN =
|
|
78
|
+
const ISSUE_PREFIX_PATTERN = /^(\d+)-/u
|
|
79
79
|
|
|
80
80
|
function has_same_issue_prefix(branch_a: string, branch_b: string): boolean {
|
|
81
81
|
const prefix_a = ISSUE_PREFIX_PATTERN.exec(branch_a)?.[0]
|
|
@@ -84,6 +84,14 @@ function has_same_issue_prefix(branch_a: string, branch_b: string): boolean {
|
|
|
84
84
|
return prefix_a !== undefined && prefix_a === prefix_b
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// The issue a branch names, or `undefined` when it does not lead with one — `1937-lane` and
|
|
88
|
+
// `1937-add-a-scope` both read 1937, while `main` reads nothing.
|
|
89
|
+
function issue_from_branch(branch: string): number | undefined {
|
|
90
|
+
const digits = ISSUE_PREFIX_PATTERN.exec(branch)?.[1]
|
|
91
|
+
|
|
92
|
+
return digits === undefined ? undefined : Number(digits)
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
// The one rule `check_and_create_branch` refuses on, kept pure so `git-preflight.ts` asks it before
|
|
88
96
|
// anything is pulled, switched or staged.
|
|
89
97
|
function is_mismatch(
|
|
@@ -133,6 +141,7 @@ const git_branch = {
|
|
|
133
141
|
// second copy of the pattern (joshuafolkken/kit#1497). A copy is what let `lane/<N>` ship: nothing
|
|
134
142
|
// asserted that the name `lane:open` writes is one this function accepts.
|
|
135
143
|
has_same_issue_prefix,
|
|
144
|
+
issue_from_branch,
|
|
136
145
|
}
|
|
137
146
|
|
|
138
147
|
export { git_branch }
|
|
@@ -411,7 +411,7 @@ async function push(): Promise<void> {
|
|
|
411
411
|
// the same thing: it is on the default branch, bringing it up to date before doing something else —
|
|
412
412
|
// `main-sync.ts` for `josh ms`, `release-cli.ts` / `release-publish.ts` around the release pull
|
|
413
413
|
// request, `scripts-ai/prep.ts` before it snapshots the overrides, and `git-branch.ts` →
|
|
414
|
-
// `pull_latest` — reached from `
|
|
414
|
+
// `pull_latest` — reached from `git-workflow.ts`, so it runs on every `josh git` /
|
|
415
415
|
// `josh pr` started from the default branch, which makes it the hottest of the five rather than a
|
|
416
416
|
// dormant one. **None of them is
|
|
417
417
|
// asking to absorb divergence**, so `merge_branch`'s reasoning inverts here: a default branch that
|
package/scripts/git/git-error.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
1
2
|
import { has_stderr_field } from './git-gh-exec'
|
|
2
3
|
|
|
3
|
-
function get_error_message(error: unknown): string {
|
|
4
|
-
return error instanceof Error ? error.message : String(error)
|
|
5
|
-
}
|
|
6
|
-
|
|
7
4
|
function get_stderr_from_error(cause: Error): string | undefined {
|
|
8
5
|
if (!has_stderr_field(cause)) return undefined
|
|
9
6
|
|
|
@@ -46,7 +43,7 @@ function display_error_details(cause: unknown): void {
|
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
function handle(error: unknown): void {
|
|
49
|
-
const error_message =
|
|
46
|
+
const error_message = error_text.message_of(error)
|
|
50
47
|
|
|
51
48
|
console.error('')
|
|
52
49
|
console.error('❌ Error:', error_message)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { review_stamps } from '../scripts/review/review-stamps'
|
|
6
|
-
import { run_hold } from '../scripts/run/run-hold'
|
|
7
|
-
import { run_progress_clock } from '../scripts/run/run-progress-clock'
|
|
1
|
+
import { review_attest } from '#scripts/review/review-attest'
|
|
2
|
+
import { review_stamps } from '#scripts/review/review-stamps'
|
|
3
|
+
import { run_hold } from '#scripts/run/run-hold'
|
|
4
|
+
import { run_progress_clock } from '#scripts/run/run-progress-clock'
|
|
8
5
|
import { parse_completed_issue_number } from './followup-issue-number'
|
|
6
|
+
import { git_followup_cleanup, type CleanupStep } from './git-followup-cleanup'
|
|
7
|
+
import { git_followup_pending } from './git-followup-pending'
|
|
8
|
+
import { git_next_issues } from './git-next-issues'
|
|
9
9
|
|
|
10
10
|
// **The count of unreleased merges, not the project version** (joshuafolkken/kit#1486). This line
|
|
11
11
|
// used to read the local `package.json` and was read as "the version this run just shipped"; children
|
|
@@ -1,62 +1,88 @@
|
|
|
1
1
|
import { observation_ledger } from '#scripts/observations/observation-ledger'
|
|
2
|
-
import {
|
|
2
|
+
import { observation_ledger_prepare } from '#scripts/observations/observation-ledger-prepare'
|
|
3
3
|
import { observations_flush } from '#scripts/observations/observations-flush'
|
|
4
4
|
import { git_command } from './git-command'
|
|
5
|
-
import {
|
|
6
|
-
import { main_sync } from './main-sync'
|
|
5
|
+
import { git_spawn } from './git-spawn'
|
|
7
6
|
|
|
8
7
|
// The residual commit path for the observation ledger (joshuafolkken/kit#1810). A run's appended lines
|
|
9
|
-
// ride its own commit (joshuafolkken/kit#2763), so
|
|
10
|
-
// short-circuits; what it still catches is a line appended after
|
|
11
|
-
// record — which would otherwise stay in the working tree
|
|
12
|
-
// wires the flush into `pnpm josh followup`, the one step that knows the merge has landed.
|
|
8
|
+
// ride its own commit (joshuafolkken/kit#2763), so the ledger is usually clean by now and this
|
|
9
|
+
// short-circuits; what it still catches is a line appended after that commit — a second review round's
|
|
10
|
+
// record — which would otherwise stay in the working tree after the merge.
|
|
13
11
|
//
|
|
14
|
-
// **It
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
async function sync_and_flush(): Promise<void> {
|
|
27
|
-
if ((await main_sync.run([])) !== MAIN_SYNC_SUCCESS) throw new Error(SYNC_FAILURE_MESSAGE)
|
|
28
|
-
|
|
29
|
-
console.info(await observations_flush.flush(new Date()))
|
|
12
|
+
// **It commits onto the pull request's own branch, before the merge** (joshuafolkken/kit#2919). It used
|
|
13
|
+
// to flush after the merge from the default branch, which a lane cannot reach, so a lane's lines
|
|
14
|
+
// waited in the primary checkout for a batch-end flush and were lost there to another run's stash.
|
|
15
|
+
// Committed to the branch instead, the lines merge with the pull request — in a lane as anywhere — and
|
|
16
|
+
// the CI wait `pnpm josh followup` runs next covers the pushed commit like any other push.
|
|
17
|
+
|
|
18
|
+
const COMMIT_MESSAGE_PREFIX = 'Record observation ledger entries'
|
|
19
|
+
|
|
20
|
+
function commit_message(issue_number: string | undefined): string {
|
|
21
|
+
return issue_number === undefined
|
|
22
|
+
? COMMIT_MESSAGE_PREFIX
|
|
23
|
+
: `${COMMIT_MESSAGE_PREFIX} #${issue_number}`
|
|
30
24
|
}
|
|
31
25
|
|
|
32
|
-
// **
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
26
|
+
// **A broken line refuses the merge rather than riding it** (joshuafolkken/kit#2123): the branch's
|
|
27
|
+
// ledger file goes away with the lane, so a line left behind here is a line lost.
|
|
28
|
+
async function assert_grammar(): Promise<void> {
|
|
29
|
+
const broken = await observation_ledger_prepare.prepare(await git_command.repository_root())
|
|
30
|
+
|
|
31
|
+
if (broken.length > 0) throw new Error(observations_flush.broken_lines_message(broken))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// **A push that fails takes its commit back**, leaving the lines staged: the next `pnpm josh followup`
|
|
35
|
+
// then finds them pending and retries. Left committed, they would read as clean and the merge would
|
|
36
|
+
// go ahead without them, the lines stranded in a local commit no reader sees.
|
|
37
|
+
async function push_or_undo_commit(): Promise<void> {
|
|
38
|
+
try {
|
|
39
|
+
await git_command.push()
|
|
40
|
+
} catch (error) {
|
|
41
|
+
await git_spawn.read(['reset', '--soft', 'HEAD~1'])
|
|
42
|
+
throw error
|
|
47
43
|
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Only the ledger paths are staged — whatever else the tree holds is the run's to commit, not this
|
|
47
|
+
// step's — and `-A` takes a migration's deletion of an old path with it.
|
|
48
|
+
async function commit_and_push(
|
|
49
|
+
paths: ReadonlyArray<string>,
|
|
50
|
+
issue_number: string | undefined,
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
await git_spawn.read(['add', '-A', '--', ...paths])
|
|
53
|
+
await git_command.commit(commit_message(issue_number))
|
|
54
|
+
await push_or_undo_commit()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// **Short-circuits when the ledger holds no pending append**, which is every run that recorded nothing
|
|
58
|
+
// after its commit, and on a `--no-merge` run, which has no merge for the lines to ride.
|
|
59
|
+
async function commit_ledger_step(
|
|
60
|
+
should_merge: boolean,
|
|
61
|
+
issue_number: string | undefined,
|
|
62
|
+
): Promise<void> {
|
|
63
|
+
if (!should_merge) return
|
|
64
|
+
|
|
65
|
+
const status_output = await git_command.status()
|
|
66
|
+
|
|
67
|
+
if (!observation_ledger.has_pending_append(status_output)) return
|
|
68
|
+
|
|
69
|
+
await assert_grammar()
|
|
70
|
+
|
|
71
|
+
// Read again: the grammar check migrated any old-path ledger, which changes what is to be staged.
|
|
72
|
+
const paths = observation_ledger
|
|
73
|
+
.ledger_paths(await git_command.status())
|
|
74
|
+
.filter((file_path) => !observation_ledger.is_migration_claim(file_path))
|
|
75
|
+
|
|
76
|
+
// A live run's migration claim alone is pending, not a line: with no path, `git add -A --` would
|
|
77
|
+
// stage the whole tree.
|
|
78
|
+
if (paths.length === 0) return
|
|
48
79
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
await git_followup_cleanup.run_guarded_step(should_merge, {
|
|
54
|
-
label: 'The observation ledger flush',
|
|
55
|
-
recovery: FLUSH_RECOVERY,
|
|
56
|
-
run: sync_and_flush,
|
|
57
|
-
})
|
|
80
|
+
await commit_and_push(paths, issue_number)
|
|
81
|
+
console.info(
|
|
82
|
+
`💡 Committed ${String(paths.length)} observation ledger path(s) to the pull request.`,
|
|
83
|
+
)
|
|
58
84
|
}
|
|
59
85
|
|
|
60
|
-
const git_followup_flush = {
|
|
86
|
+
const git_followup_flush = { COMMIT_MESSAGE_PREFIX, commit_ledger_step }
|
|
61
87
|
|
|
62
88
|
export { git_followup_flush }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { epic_parse } from '#scripts/epic/epic-parse'
|
|
1
2
|
import { poll, type PollOptions } from '#scripts/lib/poll'
|
|
2
3
|
import { z } from 'zod'
|
|
3
|
-
import { git_epic_parse } from './git-epic-parse'
|
|
4
4
|
import { git_gh_command } from './git-gh-command'
|
|
5
5
|
import { parse_json_object_safe } from './parse-json-array'
|
|
6
6
|
|
|
@@ -28,7 +28,7 @@ async function is_issue_closed(issue_number: string): Promise<boolean> {
|
|
|
28
28
|
const raw = await git_gh_command.issue_get_state_and_relations(issue_number)
|
|
29
29
|
const parsed = raw === undefined ? undefined : parse_json_object_safe(raw, state_read_schema)
|
|
30
30
|
|
|
31
|
-
return
|
|
31
|
+
return epic_parse.is_state_closed(parsed?.state)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const FOLLOWUP_CLOSER = 'pnpm josh followup'
|
|
@@ -46,7 +46,7 @@ async function read_label_names(issue_number: string): Promise<ReadonlyArray<str
|
|
|
46
46
|
// **An issue that does not carry it is never written to**, which is what keeps the step silent on a
|
|
47
47
|
// run whose issue was never labelled — a `404` swallowed into a warning would report a failure where
|
|
48
48
|
// there was nothing to do. The read itself is always paid: one `number,labels,body` call per merged
|
|
49
|
-
// run, which is the read `
|
|
49
|
+
// run, which is the read `epic-read.ts` already makes rather than a field list of its own.
|
|
50
50
|
//
|
|
51
51
|
// A run whose pull request named no issue has nothing to strip, so it returns rather than throwing:
|
|
52
52
|
// the number is recovered from the `closes #N` keyword, and its absence is already reported where
|
|
@@ -21,7 +21,7 @@ import { git_command } from './git-command'
|
|
|
21
21
|
// there cannot include this run's own merge, and a bare number would be understated by exactly one.
|
|
22
22
|
// Saying so is the honest form of the same measurement. The console line printed after the merge
|
|
23
23
|
// passes `false` and carries no note, because by then the merge is on the remote and the fetch below
|
|
24
|
-
// brings it in; `
|
|
24
|
+
// brings it in; `git-followup-finish.ts` is that caller, so **both branches of this flag
|
|
25
25
|
// are live**. What a run *does* about the count is `pnpm josh release:scope`, asked after the merge,
|
|
26
26
|
// which reads `read_pending` below rather than this line (joshuafolkken/kit#1582).
|
|
27
27
|
const MERGE_PENDING_NOTE = "— this run's merge is not counted; it lands next"
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { parseArgs } from 'node:util'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { live_evidence } from '../scripts/review/live-evidence'
|
|
9
|
-
import { review_attest } from '../scripts/review/review-attest'
|
|
10
|
-
import { review_record } from '../scripts/review/review-record'
|
|
11
|
-
import { load_optional_environment } from './environment-loader'
|
|
3
|
+
import { cli_body } from '#scripts/josh/cli-body'
|
|
4
|
+
import { josh_environment_file } from '#scripts/josh/josh-environment-file'
|
|
5
|
+
import { live_evidence } from '#scripts/review/live-evidence'
|
|
6
|
+
import { review_attest } from '#scripts/review/review-attest'
|
|
7
|
+
import { review_record } from '#scripts/review/review-record'
|
|
12
8
|
import { parse_issue_number_from_text } from './followup-issue-number'
|
|
9
|
+
import { git_branch } from './git-branch'
|
|
10
|
+
import { git_error } from './git-error'
|
|
13
11
|
import { git_followup_finish } from './git-followup-finish'
|
|
12
|
+
import { git_followup_flush } from './git-followup-flush'
|
|
13
|
+
import { git_notify, type GitNotifyConfig } from './git-notify'
|
|
14
|
+
import { git_pr_followup } from './git-pr-followup'
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
josh_environment_file.load_environment_file()
|
|
16
17
|
|
|
17
18
|
// cspell:words coderabbit
|
|
18
19
|
|
|
@@ -202,6 +203,17 @@ async function assert_merge_gates(
|
|
|
202
203
|
await assert_live_evidence(should_merge, branch_name)
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
// After the gates, before the CI wait: a line appended since the run's commit rides the pull request
|
|
207
|
+
// itself, so it merges with it — a lane's included (joshuafolkken/kit#2919).
|
|
208
|
+
async function prepare_merge(
|
|
209
|
+
should_merge: boolean,
|
|
210
|
+
issue_number: string | undefined,
|
|
211
|
+
branch_name: string,
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
await assert_merge_gates(should_merge, issue_number, branch_name)
|
|
214
|
+
await git_followup_flush.commit_ledger_step(should_merge, issue_number)
|
|
215
|
+
}
|
|
216
|
+
|
|
205
217
|
async function main(): Promise<void> {
|
|
206
218
|
const cli = parse_cli_arguments()
|
|
207
219
|
|
|
@@ -216,7 +228,7 @@ async function main(): Promise<void> {
|
|
|
216
228
|
const should_merge = is_merge_resolved(cli.values)
|
|
217
229
|
const branch_name = await resolve_branch_name(cli.values.branch)
|
|
218
230
|
|
|
219
|
-
await
|
|
231
|
+
await prepare_merge(should_merge, issue_number, branch_name)
|
|
220
232
|
// **The number the run reports on is the one it used**, which is the number the pull request
|
|
221
233
|
// closes where the invocation named none (joshuafolkken/kit#1539). Recovered inside `run`, so the
|
|
222
234
|
// tail records a run the command line could not identify rather than silently skipping it.
|