@joshuafolkken/kit 1.1010.0 → 1.1050.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/verify-ui/SKILL.md +1 -1
- package/.claude/skills/workflow-commands/SKILL.md +10 -25
- package/.claude/skills/workflow-commands/background-commands.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-child.md +6 -4
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
- package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -36
- package/.claude/skills/workflow-commands/backlogrun-steps.md +16 -16
- package/.claude/skills/workflow-commands/backlogrun.md +3 -12
- package/.claude/skills/workflow-commands/chain-rule.md +2 -2
- package/.claude/skills/workflow-commands/followup-reference.md +2 -2
- 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/issue-comments.md +1 -1
- package/.claude/skills/workflow-commands/observation-filing.md +80 -126
- package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
- package/.claude/skills/workflow-commands/prerequisite.md +1 -1
- package/.claude/skills/workflow-commands/working-tree-hold.md +2 -2
- package/.codex/hooks.json +1 -5
- package/.github/workflows/auto-tag.yml +21 -0
- package/.github/workflows/publish.yml +9 -10
- 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-6PSTVOLH.js → chunk-5BK3K7V4.js} +114 -90
- package/dist/hooks/{chunk-PAXMLGSS.js → chunk-7VPDUBRN.js} +93 -175
- package/dist/hooks/{chunk-KPZN42RT.js → chunk-DMQN45FN.js} +3 -3
- package/dist/hooks/{chunk-WMIR5SNX.js → chunk-EJDX2TOB.js} +13 -3
- package/dist/hooks/{chunk-A2H5I2VD.js → chunk-GQ7KP45M.js} +2 -2
- package/dist/hooks/{chunk-4GDR2YTV.js → chunk-HJIISEAC.js} +4 -4
- package/dist/hooks/{chunk-AWTFKKFW.js → chunk-NAS4C7GP.js} +6 -33
- package/dist/hooks/{chunk-56LGMJJV.js → chunk-NJQOBE6L.js} +2 -2
- package/dist/hooks/{chunk-EZLHXKJ6.js → chunk-RLDX5SOC.js} +1222 -941
- package/dist/hooks/{chunk-GBJUERYK.js → chunk-WQ4OSBSS.js} +10 -3
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +15 -34
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +23 -16
- package/dist/hooks/stop-guard.js +21 -200
- package/dist/josh.js +42 -125
- package/dist/version/index.js +466 -42
- package/eslint/base.js +2 -11
- package/package.json +36 -10
- 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/file-edits.md +6 -53
- 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 +55 -15
- package/prompts/collaboration-workflow/rule-delivery.md +5 -46
- package/prompts/collaboration-workflow/shell-body.md +7 -9
- package/prompts/collaboration-workflow/turn-batching.md +21 -37
- package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
- package/prompts/collaboration-workflow/wip-cap.md +15 -18
- package/prompts/collaboration-workflow.md +22 -28
- package/prompts/sonar-hotspot-handling.md +1 -1
- package/scripts/adopt/adopt-logic.ts +2 -2
- package/scripts/adopt/adopt-toolkits.ts +3 -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/auto-ok/auto-ok-cli.ts +9 -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-next.ts +24 -8
- package/scripts/backlog/backlog-offer-cli.ts +6 -5
- package/scripts/backlog/backlog-plan-cli.ts +5 -1
- package/scripts/backlog/backlog-plan.ts +1 -1
- package/scripts/backlog/backlog-pool.ts +31 -11
- package/scripts/backlog/backlog-rank.ts +106 -0
- package/scripts/backlog/backlog-waves.ts +42 -29
- package/scripts/build/build-bin.ts +2 -1
- package/scripts/build/build-config-merge.ts +2 -1
- package/scripts/build/build-hooks.ts +31 -6
- 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/delegation/delegation-policy.ts +11 -0
- package/scripts/doctor/doctor-consumer.ts +5 -12
- package/scripts/doctor/doctor-ports.ts +2 -2
- package/scripts/document/document-byte-budget.ts +13 -21
- package/scripts/document/document-section.ts +2 -6
- package/scripts/document/entry-read-budget.ts +6 -5
- 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-lane-offer.ts +11 -22
- 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/epic/epic-rank.ts +37 -0
- 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/epic/epic-solo.ts +29 -28
- 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 +2 -2
- package/scripts/git/git-error.ts +2 -5
- package/scripts/git/git-execa-error.ts +6 -1
- 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-next-issues.ts +34 -5
- package/scripts/git/git-pr-followup-wrapup.ts +2 -6
- package/scripts/git/git-preflight.ts +25 -10
- package/scripts/git/git-push-transport.ts +12 -69
- package/scripts/git/git-spawn.ts +79 -3
- package/scripts/git/git-ssh-keepalive.ts +74 -0
- 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/gone-branch.ts +3 -2
- package/scripts/git/issue-labels.ts +13 -1
- package/scripts/git/issue-rank.ts +89 -0
- 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-edited-cli.ts +15 -0
- package/scripts/hooks/format-edited-file.ts +2 -9
- package/scripts/hooks/format-rewrite-notice.ts +2 -8
- package/scripts/hooks/pretool-guard-cli.ts +21 -0
- package/scripts/hooks/pretool-guard.ts +14 -15
- package/scripts/init/init-ai-copy.ts +2 -5
- package/scripts/init/init.ts +8 -4
- package/scripts/init/start-exec.ts +7 -1
- package/scripts/init/start-plan.ts +18 -5
- package/scripts/init/start-setup-pr.ts +46 -19
- package/scripts/init/start-steps.ts +43 -10
- package/scripts/init/start.ts +42 -11
- package/scripts/issue/issue-cite.ts +19 -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-command-map.ts +0 -102
- 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 +3 -3
- package/scripts/josh/josh-commands-project.ts +1 -1
- package/scripts/josh/josh-commands-workflow.ts +4 -4
- package/scripts/lane/lane-child-marker.ts +16 -2
- package/scripts/lane/lane-cli.ts +34 -15
- package/scripts/lane/lane-open.ts +3 -2
- package/scripts/lane/lane-registry.ts +3 -6
- package/scripts/lane/lane-report.ts +10 -4
- 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-plan.ts +185 -0
- package/scripts/propagate/propagate-publish.ts +6 -7
- package/scripts/propagate/propagate-run.ts +5 -1
- package/scripts/propagate/propagate-steps.ts +18 -2
- package/scripts/propagate/propagate-targets.ts +13 -2
- package/scripts/propagate/propagate.ts +63 -44
- package/scripts/refactor/import-graph.ts +2 -6
- package/scripts/registry-migration/migrate-logic.ts +1 -0
- package/scripts/registry-migration/migrate.ts +3 -2
- package/scripts/registry-migration/user-npmrc.ts +2 -2
- package/scripts/release/github-release.ts +1 -1
- package/scripts/release/release-cli.ts +2 -1
- package/scripts/repo/repo-setting.ts +10 -8
- package/scripts/review/review-attest.ts +44 -0
- package/scripts/review/review-brief-cli.ts +49 -2
- package/scripts/review/review-brief.ts +46 -1
- 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/review/review-stamps.ts +7 -0
- package/scripts/rules/decision-oracle.ts +2 -2
- package/scripts/rules/implementation-cut.ts +1 -1
- package/scripts/rules/issue-fold.ts +1 -2
- package/scripts/rules/lane-carry-conflict.ts +1 -2
- package/scripts/rules/lane-park.ts +1 -2
- package/scripts/rules/pre-gate-cut.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-headless.ts +22 -6
- package/scripts/run/run-liveness-cli.ts +4 -7
- package/scripts/run/run-parent-cut-hook.ts +144 -0
- package/scripts/run/run-progress-args.ts +2 -6
- package/scripts/run/run-progress-cli.ts +2 -1
- package/scripts/run/run-progress-read.ts +2 -1
- package/scripts/run/run-progress.ts +21 -8
- package/scripts/run/run-ship-cli.ts +6 -74
- package/scripts/run/run-ship-preflight.ts +87 -0
- package/scripts/run/run-ship-review-steps.ts +5 -26
- package/scripts/run/run-ship-review.ts +9 -0
- package/scripts/run/run-ship-scoped.ts +44 -0
- package/scripts/run/run-ship-stage.ts +5 -1
- package/scripts/run/run-ship-steps.ts +105 -0
- package/scripts/run/run-ship.ts +2 -0
- 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 +4 -8
- package/scripts/run/run-wake-describe.ts +19 -1
- package/scripts/run/run-wake-driver.ts +15 -2
- package/scripts/run/run-wake-session.ts +14 -4
- package/scripts/run/run-watcher-hook.ts +1 -1
- 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/time-runtime/time-bundle-call.ts +2 -2
- package/scripts/ui/ui-routes-cli.ts +3 -6
- package/scripts/version/bump-version.ts +2 -1
- package/scripts/version/npm-registry.ts +97 -0
- package/scripts/version/version-commands.ts +5 -4
- package/scripts/version/version-remote.ts +38 -33
- 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
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { josh_command, type JoshResult } from '#scripts/josh/josh-run'
|
|
2
|
+
import { run_ship } from './run-ship'
|
|
3
|
+
import { run_ship_preflight } from './run-ship-preflight'
|
|
4
|
+
import { run_ship_review_steps } from './run-ship-review-steps'
|
|
5
|
+
import { run_ship_scoped } from './run-ship-scoped'
|
|
6
|
+
import { run_ship_stage, type ShipState, type Stage } from './run-ship-stage'
|
|
7
|
+
|
|
8
|
+
// The stages `josh ship` runs, in the order a change ships (joshuafolkken/kit#2398), kept apart from the
|
|
9
|
+
// chaining CLI so the order is read in one place.
|
|
10
|
+
|
|
11
|
+
const should_forward_stderr = true
|
|
12
|
+
|
|
13
|
+
interface ShipArguments {
|
|
14
|
+
title: string
|
|
15
|
+
number: string
|
|
16
|
+
notify: ReadonlyArray<string>
|
|
17
|
+
body: ReadonlyArray<string>
|
|
18
|
+
body_path: string | undefined
|
|
19
|
+
cites: ReadonlyArray<string>
|
|
20
|
+
is_review: boolean
|
|
21
|
+
is_detach: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Step {
|
|
25
|
+
stage: Stage
|
|
26
|
+
header: string
|
|
27
|
+
run: (args: ShipArguments, state: ShipState) => Promise<JoshResult>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { STAGE } = run_ship_stage
|
|
31
|
+
|
|
32
|
+
async function josh(argv: ReadonlyArray<string>): Promise<JoshResult> {
|
|
33
|
+
return await josh_command.josh_run(argv, should_forward_stderr)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// joshuafolkken/kit#2946: the pull request's preconditions and the scoped pair are asked first, so a
|
|
37
|
+
// stop they would cause lands before the review and the gate rather than after them.
|
|
38
|
+
const PREFLIGHT_STEP: Step = {
|
|
39
|
+
stage: STAGE.PREFLIGHT,
|
|
40
|
+
header: run_ship.PREFLIGHT_HEADER,
|
|
41
|
+
run: async (args) =>
|
|
42
|
+
await run_ship_preflight.stage({ title: args.title, body_path: args.body_path }),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The gate before the commit, the commit/push/PR before the merge. The gate meets the scoped pair
|
|
46
|
+
// first: a round-1 reviewer may have edited the tree since the preflight, and `josh gate` refuses a tree
|
|
47
|
+
// with no green record (joshuafolkken/kit#2946). The commit step carries the `--skip-*` flags a resumed
|
|
48
|
+
// ship needs, so an existing commit or push is never made twice.
|
|
49
|
+
const COMMIT_STEPS: ReadonlyArray<Step> = [
|
|
50
|
+
{
|
|
51
|
+
stage: STAGE.GATE,
|
|
52
|
+
header: run_ship.GATE_HEADER,
|
|
53
|
+
run: async () =>
|
|
54
|
+
await run_ship_scoped.run_phases([
|
|
55
|
+
run_ship_scoped.scoped_pair,
|
|
56
|
+
async () => await josh(['gate']),
|
|
57
|
+
]),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
stage: STAGE.COMMIT,
|
|
61
|
+
header: run_ship.COMMIT_HEADER,
|
|
62
|
+
run: async (args, state) =>
|
|
63
|
+
await josh(['git', '-y', ...run_ship_stage.commit_flags(state), ...args.body, args.title]),
|
|
64
|
+
},
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
// The merge before the report bookkeeping.
|
|
68
|
+
const MERGE_STEPS: ReadonlyArray<Step> = [
|
|
69
|
+
{
|
|
70
|
+
stage: STAGE.FOLLOWUP,
|
|
71
|
+
header: run_ship.FOLLOWUP_HEADER,
|
|
72
|
+
run: async (args) => await josh(['followup', args.title, ...args.notify]),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
stage: STAGE.REPORT,
|
|
76
|
+
header: run_ship.REPORT_HEADER,
|
|
77
|
+
run: async (args) => await josh(['run:tail', args.number, ...args.cites]),
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
// `--review` (joshuafolkken/kit#2427) puts the supervised round-1 review in front of the gate: it
|
|
82
|
+
// launches the gate itself, so the gate stage that follows reuses that tree's green record. It also
|
|
83
|
+
// puts the round-2 pass between the commit and the followup (joshuafolkken/kit#2489), so the PR opens
|
|
84
|
+
// between the rounds and round 2 runs beside CI — a no-op when round 1 left no fix delta.
|
|
85
|
+
const REVIEW_STEP: Step = {
|
|
86
|
+
stage: STAGE.REVIEW,
|
|
87
|
+
header: run_ship.REVIEW_HEADER,
|
|
88
|
+
run: async (args) => await run_ship_review_steps.review_stage(args.number),
|
|
89
|
+
}
|
|
90
|
+
const ROUND_TWO_STEP: Step = {
|
|
91
|
+
stage: STAGE.ROUND_TWO,
|
|
92
|
+
header: run_ship.ROUND_TWO_HEADER,
|
|
93
|
+
run: async (args) => await run_ship_review_steps.round_two_stage(args.number),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function steps(args: ShipArguments): ReadonlyArray<Step> {
|
|
97
|
+
if (!args.is_review) return [PREFLIGHT_STEP, ...COMMIT_STEPS, ...MERGE_STEPS]
|
|
98
|
+
|
|
99
|
+
return [PREFLIGHT_STEP, REVIEW_STEP, ...COMMIT_STEPS, ROUND_TWO_STEP, ...MERGE_STEPS]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const run_ship_steps = { steps }
|
|
103
|
+
|
|
104
|
+
export type { ShipArguments, Step }
|
|
105
|
+
export { run_ship_steps }
|
package/scripts/run/run-ship.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// `run:tail`, ship stops at the first failed step: a red gate must never reach the commit, so the
|
|
10
10
|
// composite ends at the failure, and the report names the step that failed so the run reads only it.
|
|
11
11
|
|
|
12
|
+
const PREFLIGHT_HEADER = '=== preflight ==='
|
|
12
13
|
const REVIEW_HEADER = '=== review ==='
|
|
13
14
|
const GATE_HEADER = '=== gate ==='
|
|
14
15
|
const COMMIT_HEADER = '=== commit/push/PR ==='
|
|
@@ -63,6 +64,7 @@ const run_ship = {
|
|
|
63
64
|
COMMIT_HEADER,
|
|
64
65
|
FOLLOWUP_HEADER,
|
|
65
66
|
GATE_HEADER,
|
|
67
|
+
PREFLIGHT_HEADER,
|
|
66
68
|
REPORT_HEADER,
|
|
67
69
|
REVIEW_HEADER,
|
|
68
70
|
ROUND_TWO_HEADER,
|
|
@@ -17,9 +17,9 @@ import { run_tail, type TailSection } from './run-tail'
|
|
|
17
17
|
//
|
|
18
18
|
// **A dispatched lane child skips the ledger step** (joshuafolkken/kit#2492). A flush opens a
|
|
19
19
|
// ledger-only pull request and waits out its whole CI before it merges — minutes per issue, spent on a
|
|
20
|
-
// file only the retrospective and the measurements read
|
|
21
|
-
//
|
|
22
|
-
//
|
|
20
|
+
// file only the retrospective and the measurements read — and a lane has nothing for it: its lines
|
|
21
|
+
// merged with its own pull request (joshuafolkken/kit#2919). A single run outside a lane keeps the
|
|
22
|
+
// step for a line written on the default branch outside any issue's run.
|
|
23
23
|
|
|
24
24
|
const ARGV_OFFSET = 2
|
|
25
25
|
const SUCCESS_EXIT_CODE = 0
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises'
|
|
2
1
|
import { git_stash, type StashEntry } from '#scripts/git/git-stash'
|
|
3
2
|
import { stash_orphans } from '#scripts/git/stash-orphans'
|
|
4
3
|
import { stash_sweep_lock } from '#scripts/git/stash-sweep-lock'
|
|
@@ -18,16 +17,8 @@ const READ_CONCURRENCY = 8
|
|
|
18
17
|
const GONE_REASON = 'already dropped by another run'
|
|
19
18
|
const BUSY_REASON = 'another run held the stash sweep lock'
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return await readFile(ledger_path, 'utf8')
|
|
24
|
-
} catch {
|
|
25
|
-
return ''
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// An entry cut before joshuafolkken/kit#2724 holds its lines at the ledger's old path, so the lines of
|
|
30
|
-
// every ledger path it touches are carried to the current ledger.
|
|
20
|
+
// An entry cut before joshuafolkken/kit#2919 holds its lines at an old single-file path, so the lines
|
|
21
|
+
// of every ledger path it touches are carried to the current ledger.
|
|
31
22
|
async function added_ledger_lines(
|
|
32
23
|
hash: string,
|
|
33
24
|
ledger_paths: ReadonlyArray<string>,
|
|
@@ -43,16 +34,18 @@ async function added_ledger_lines(
|
|
|
43
34
|
return added
|
|
44
35
|
}
|
|
45
36
|
|
|
46
|
-
// How many ledger lines went into the
|
|
37
|
+
// How many ledger lines went into the running work tree's ledger before the drop. The duplicate check
|
|
38
|
+
// reads every issue's file, and the lines land in the file this tree writes (joshuafolkken/kit#2919),
|
|
39
|
+
// so the run's own commit takes them to the default branch.
|
|
47
40
|
async function carry_ledger(hash: string): Promise<number> {
|
|
48
41
|
const changed = await git_stash.changed_paths(hash)
|
|
49
42
|
const ledger_paths = changed.filter((file_path) => observation_ledger.is_ledger_path(file_path))
|
|
50
43
|
|
|
51
44
|
if (ledger_paths.length === 0) return 0
|
|
52
45
|
|
|
53
|
-
const ledger_path = observation_ledger_home.
|
|
46
|
+
const ledger_path = await observation_ledger_home.writer_path(new Date())
|
|
54
47
|
const added = await added_ledger_lines(hash, ledger_paths)
|
|
55
|
-
const carried = run_tidy.ledger_carry(added, await
|
|
48
|
+
const carried = run_tidy.ledger_carry(added, (await observation_ledger_home.read()) ?? '')
|
|
56
49
|
|
|
57
50
|
await observation_ledger_home.append(ledger_path, carried)
|
|
58
51
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { randomUUID } from 'node:crypto'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
|
-
import { parseArgs } from 'node:util'
|
|
6
5
|
import type { AgentProfile } from '#scripts/agent/agent-role-profile'
|
|
7
6
|
import { telegram_notify } from '#scripts/git/telegram-notify'
|
|
7
|
+
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
8
8
|
import { run_carry, type CarryRead } from './run-carry'
|
|
9
9
|
import { run_event_stream } from './run-event-stream'
|
|
10
10
|
import { run_headless } from './run-headless'
|
|
@@ -120,11 +120,7 @@ function note_to_stderr(note: string): void {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
function read_arguments(argv: ReadonlyArray<string>): ParsedValues | undefined {
|
|
123
|
-
|
|
124
|
-
return parseArgs({ args: [...argv], options: OPTIONS, strict: true }).values
|
|
125
|
-
} catch {
|
|
126
|
-
return undefined
|
|
127
|
-
}
|
|
123
|
+
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
|
|
128
124
|
}
|
|
129
125
|
|
|
130
126
|
function text_of(value: string | boolean | undefined): string | undefined {
|
|
@@ -294,7 +290,7 @@ function start(context: WakeContext, interval: string | undefined): number {
|
|
|
294
290
|
const existing = run_wake.read_wake(context.wake_target)
|
|
295
291
|
|
|
296
292
|
if (existing !== undefined && run_wake.is_supervisor_live(existing)) {
|
|
297
|
-
console.error(run_wake_describe.
|
|
293
|
+
console.error(run_wake_describe.describe_wake_cited(existing, context))
|
|
298
294
|
|
|
299
295
|
return report(RUNNING_VERDICT)
|
|
300
296
|
}
|
|
@@ -346,7 +342,7 @@ function list(context: WakeContext): number {
|
|
|
346
342
|
|
|
347
343
|
if (wake === undefined) return report(NONE_VERDICT)
|
|
348
344
|
|
|
349
|
-
console.error(run_wake_describe.
|
|
345
|
+
console.error(run_wake_describe.describe_wake_cited(wake, context))
|
|
350
346
|
|
|
351
347
|
return report(run_wake.is_supervisor_live(wake) ? SUPERVISING_VERDICT : STALE_VERDICT)
|
|
352
348
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { agent_role_profile } from '#scripts/agent/agent-role-profile'
|
|
2
|
+
import { gh_spawn } from '#scripts/gh/gh-spawn'
|
|
3
|
+
import { issue_citation } from '#scripts/rules/issue-citation'
|
|
2
4
|
import { run_carry, type CarryRead } from './run-carry'
|
|
3
5
|
import { run_event_stream } from './run-event-stream'
|
|
4
6
|
import { run_liveness } from './run-liveness'
|
|
@@ -9,6 +11,7 @@ import { run_wake, type RunWake } from './run-wake'
|
|
|
9
11
|
// record reads back to a person lives here, one cohesive block.
|
|
10
12
|
|
|
11
13
|
const UNKNOWN_CUTS = 'an unreadable number of'
|
|
14
|
+
const REPO_LOOKUP_TIMEOUT_MS = 10_000
|
|
12
15
|
const STOP_COMMAND = 'pnpm josh run:wake --stop'
|
|
13
16
|
|
|
14
17
|
// The three paths every verb needs: the carry record it reads, its own record, and the work tree a
|
|
@@ -91,7 +94,22 @@ function describe_wake(wake: RunWake, context: WakeContext): string {
|
|
|
91
94
|
.join('\n')
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
|
|
97
|
+
// The description as a person reads it, every issue on it a number-link (joshuafolkken/kit#2943). The
|
|
98
|
+
// invocation and the newest event both name issues (`backlogrun #1 #2`, `#1904 merged`), and a report
|
|
99
|
+
// that copies them bare is what the Stop guard sends back. The repository is asked here, bounded, rather
|
|
100
|
+
// than in the context every verb resolves: only the two describing verbs print it, and a lookup that
|
|
101
|
+
// does not answer leaves the description as it was rather than withholding it.
|
|
102
|
+
function cite_description(description: string, repo: string | undefined): string {
|
|
103
|
+
return repo === undefined ? description : issue_citation.linkify(description, repo)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function describe_wake_cited(wake: RunWake, context: WakeContext): string {
|
|
107
|
+
const repo = gh_spawn.get_repo_name_with_owner_within(REPO_LOOKUP_TIMEOUT_MS)
|
|
108
|
+
|
|
109
|
+
return cite_description(describe_wake(wake, context), repo)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const run_wake_describe = { STOP_COMMAND, cite_description, describe_wake, describe_wake_cited }
|
|
95
113
|
|
|
96
114
|
export type { WakeContext }
|
|
97
115
|
export { run_wake_describe }
|
|
@@ -6,6 +6,8 @@ import type { DriveResult } from './run-wake-loop'
|
|
|
6
6
|
const SUCCESS = 0
|
|
7
7
|
const FIRST_LINE = 0
|
|
8
8
|
const RESUME_PREFIX = 'resume: '
|
|
9
|
+
const DETAILS_TAIL_LENGTH = 2048
|
|
10
|
+
const TRUNCATION_MARK = '... '
|
|
9
11
|
|
|
10
12
|
function driver_args(invocation: string): ReadonlyArray<string> | undefined {
|
|
11
13
|
const rebuilt = run_invocation.rebuild(invocation)
|
|
@@ -24,13 +26,24 @@ function is_final_stop(verdict: string | undefined, read: CarryRead): boolean {
|
|
|
24
26
|
return verdict?.startsWith('stop') === true && read.kind === 'none'
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
// **The details are the driver's whole stderr, so only their tail is handed on, and it goes last**
|
|
30
|
+
// (joshuafolkken/kit#2931). The stderr carries every command the driver ran since it started, which
|
|
31
|
+
// after a long run is tens of kilobytes — far past what `is_safe_value` lets into an argv element. Its
|
|
32
|
+
// tail is where the reason for stopping is; placing it last means the cap `wake_argv` applies to the
|
|
33
|
+
// whole prompt can only ever cut into the details, never the verdict, the resume line or the epic note.
|
|
34
|
+
function details_tail(details: string): string {
|
|
35
|
+
return details.length > DETAILS_TAIL_LENGTH
|
|
36
|
+
? `${TRUNCATION_MARK}${details.slice(-DETAILS_TAIL_LENGTH)}`
|
|
37
|
+
: details
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
function handoff_material(verdict: string, resume: string, details: string): string {
|
|
28
|
-
const context = details === '' ? '' : `\nDetails: ${details}`
|
|
41
|
+
const context = details === '' ? '' : `\nDetails: ${details_tail(details)}`
|
|
29
42
|
const epic = verdict.startsWith('epic #')
|
|
30
43
|
? '\nThe named item is an epic. Follow backlogrun-steps.md named epic procedure; do not launch the epic root as a fullrun child. After all children merge or park, record the root with pnpm josh run:carry --done <epic-number> --owner "$PPID" before continuing to the next named item.'
|
|
31
44
|
: ''
|
|
32
45
|
|
|
33
|
-
return `Driver result: ${verdict}\n${resume}${
|
|
46
|
+
return `Driver result: ${verdict}\n${resume}${epic}${context}`
|
|
34
47
|
}
|
|
35
48
|
|
|
36
49
|
function driver_result(out: string, read: CarryRead, details = ''): DriveResult {
|
|
@@ -37,6 +37,8 @@ const WAKE_FLAGS = claude_agent_argv.AGENT_FLAGS
|
|
|
37
37
|
const LOOP_FLAG = '--loop'
|
|
38
38
|
const INTERVAL_FLAG = '--interval'
|
|
39
39
|
const SUPERVISOR_SESSION = 'run-wake-supervisor'
|
|
40
|
+
// eslint-disable-next-line no-control-regex -- matching control characters is the point
|
|
41
|
+
const CONTROL_CHARACTERS = /[\u{0}-\u{1F}\u{7F}]/gu
|
|
40
42
|
|
|
41
43
|
function scheduler_profile(): AgentProfile | undefined {
|
|
42
44
|
const resolved = agent_role_profile.resolve(agent_role_profile.SCHEDULER)
|
|
@@ -96,6 +98,17 @@ function resolved_argv(invocation: string, cwd?: string): AgentArgvResult {
|
|
|
96
98
|
: agent_argv.resolve_in(invocation, agent_role_profile.SCHEDULER, cwd)
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
// **Handoff material is made safe to launch rather than refused** (joshuafolkken/kit#2931). It is the
|
|
102
|
+
// driver's own output, not the record, so it is flattened — a newline becomes a separator, any other
|
|
103
|
+
// control character a space — and the prompt is cut at the cap `is_safe_value` enforces. The driver puts
|
|
104
|
+
// its verdict and resume line first, so the cut only ever shortens the details. The check itself is
|
|
105
|
+
// untouched: the argv still passes `is_safe_argv` before anything is spawned.
|
|
106
|
+
function handoff_prompt(matched: string, material: string): string {
|
|
107
|
+
const flattened = material.replaceAll('\n', ' | ').replaceAll(CONTROL_CHARACTERS, ' ')
|
|
108
|
+
|
|
109
|
+
return `${matched} | Driver handoff: ${flattened}`.slice(0, agent_role_profile.MAX_VALUE_LENGTH)
|
|
110
|
+
}
|
|
111
|
+
|
|
99
112
|
function wake_argv(
|
|
100
113
|
invocation: string,
|
|
101
114
|
profile?: AgentProfile,
|
|
@@ -104,10 +117,7 @@ function wake_argv(
|
|
|
104
117
|
): AgentArgvResult | undefined {
|
|
105
118
|
const matched = safe_invocation(invocation)
|
|
106
119
|
if (matched === undefined) return undefined
|
|
107
|
-
const prompt =
|
|
108
|
-
typeof session === 'object'
|
|
109
|
-
? `${matched} | Driver handoff: ${session.material.replaceAll('\n', ' | ')}`
|
|
110
|
-
: matched
|
|
120
|
+
const prompt = typeof session === 'object' ? handoff_prompt(matched, session.material) : matched
|
|
111
121
|
const session_id = typeof session === 'object' ? session.id : session
|
|
112
122
|
|
|
113
123
|
return profile === undefined
|
|
@@ -81,6 +81,6 @@ async function watcher_hook_reason(
|
|
|
81
81
|
return await stale_reason(transcript, now_ms)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const run_watcher_hook = { SWITCH_ENV_KEY, STAMP_PREFIX, watcher_hook_reason }
|
|
84
|
+
const run_watcher_hook = { SWITCH_ENV_KEY, STAMP_PREFIX, transcript_of, watcher_hook_reason }
|
|
85
85
|
|
|
86
86
|
export { run_watcher_hook }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
+
import { file_reader } from '#scripts/lib/read-file'
|
|
3
4
|
import { release_age } from '#scripts/version/release-age'
|
|
4
5
|
import { yaml_document } from '#scripts/yaml/yaml-document'
|
|
5
6
|
import { dump } from 'js-yaml'
|
|
@@ -126,17 +127,13 @@ function merge_project_config(existing: string, workspace: string, npmrc = ''):
|
|
|
126
127
|
return replace_safe_chain_block(existing, merged)
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
function read_optional(file_path: string): string {
|
|
130
|
-
return existsSync(file_path) ? readFileSync(file_path, 'utf8') : ''
|
|
131
|
-
}
|
|
132
|
-
|
|
133
130
|
function sync_project_config(root: string): boolean {
|
|
134
131
|
const workspace_path = path.join(root, WORKSPACE_FILE)
|
|
135
132
|
if (!existsSync(workspace_path)) return false
|
|
136
133
|
const config_path = path.join(root, PROJECT_CONFIG_FILE)
|
|
137
|
-
const existing =
|
|
134
|
+
const existing = file_reader.read_file_or_empty(config_path)
|
|
138
135
|
const workspace = readFileSync(workspace_path, 'utf8')
|
|
139
|
-
const npmrc =
|
|
136
|
+
const npmrc = file_reader.read_file_or_empty(path.join(root, NPMRC_FILE))
|
|
140
137
|
const merged = merge_project_config(existing, workspace, npmrc)
|
|
141
138
|
if (merged === existing) return false
|
|
142
139
|
writeFileSync(config_path, merged)
|
|
@@ -4,6 +4,7 @@ import path from 'node:path'
|
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
6
6
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
7
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
7
8
|
import { security_audit } from './security-audit'
|
|
8
9
|
import { security_audit_logic } from './security-audit-logic'
|
|
9
10
|
import { security_audit_provision_logic, type ScannerAsset } from './security-audit-provision-logic'
|
|
@@ -14,10 +15,6 @@ const FORCE_FLAG = '--force'
|
|
|
14
15
|
const PATH_LOCATION = 'on PATH'
|
|
15
16
|
const { RETRY_INTERVAL_MS } = security_audit_provision_logic
|
|
16
17
|
|
|
17
|
-
function describe_error(error: unknown): string {
|
|
18
|
-
return error instanceof Error ? error.message : String(error)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
18
|
// `content` absent is the failure, and `reason` says which one. A 404 — what a bumped version whose
|
|
22
19
|
// asset was renamed looks like, and the one failure that never fixes itself — would otherwise read
|
|
23
20
|
// exactly like a transient 503, and a rejected request like neither.
|
|
@@ -41,7 +38,7 @@ async function download(url: string, timeout_ms: number): Promise<DownloadOutcom
|
|
|
41
38
|
|
|
42
39
|
return { content: Buffer.from(await response.arrayBuffer()), reason: '' }
|
|
43
40
|
} catch (error) {
|
|
44
|
-
return { reason:
|
|
41
|
+
return { reason: error_text.message_of(error) }
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
44
|
|
|
@@ -128,7 +125,7 @@ async function attempt(
|
|
|
128
125
|
} catch (error) {
|
|
129
126
|
return record_failure(
|
|
130
127
|
target_path,
|
|
131
|
-
security_audit_provision_logic.format_provision_error(
|
|
128
|
+
security_audit_provision_logic.format_provision_error(error_text.message_of(error)),
|
|
132
129
|
)
|
|
133
130
|
}
|
|
134
131
|
}
|
|
@@ -175,7 +172,9 @@ async function main(): Promise<void> {
|
|
|
175
172
|
try {
|
|
176
173
|
console.info(await report(PROJECT_ROOT, process.platform, process.arch, is_forced))
|
|
177
174
|
} catch (error) {
|
|
178
|
-
console.warn(
|
|
175
|
+
console.warn(
|
|
176
|
+
security_audit_provision_logic.format_provision_error(error_text.message_of(error)),
|
|
177
|
+
)
|
|
179
178
|
}
|
|
180
179
|
}
|
|
181
180
|
|
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { git_command } from '#scripts/git/git-command'
|
|
6
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
6
7
|
import { managed_config_scope } from '#scripts/sync/managed-config-scope'
|
|
7
8
|
import { z } from 'zod'
|
|
8
9
|
import {
|
|
@@ -69,7 +70,7 @@ async function fetch_hotspots(url: string): Promise<HotspotFetch> {
|
|
|
69
70
|
|
|
70
71
|
return { hotspots: parsed.hotspots ?? [] }
|
|
71
72
|
} catch (error) {
|
|
72
|
-
return { error:
|
|
73
|
+
return { error: error_text.message_of(error) }
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cpSync, lstatSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { transform_copied_content } from '#scripts/init/init-copy-content'
|
|
4
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
4
5
|
import { file_content } from './file-content'
|
|
5
6
|
|
|
6
7
|
// `josh init` and `josh sync` both copy a distributed directory with `cpSync`, and both have to
|
|
@@ -143,7 +144,7 @@ function copy_directory(source_path: string, destination_path: string): boolean
|
|
|
143
144
|
// throw here would end `josh init` or `josh sync` in the middle of their work. The message is
|
|
144
145
|
// returned for the caller to report, the same way a blocker is.
|
|
145
146
|
function failure_message(prefix: string, error: unknown): string {
|
|
146
|
-
return `${prefix} (${
|
|
147
|
+
return `${prefix} (${error_text.message_of(error)})`
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
// The two failures are reported apart because they leave the destination in opposite states, and
|
|
@@ -5,6 +5,7 @@ import { transform_copied_content } from '#scripts/init/init-copy-content'
|
|
|
5
5
|
import { init_logic } from '#scripts/init/init-logic'
|
|
6
6
|
import { PACKAGE_DIR, PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
7
7
|
import type { ProjectShape } from '#scripts/init/project-profile'
|
|
8
|
+
import { file_reader } from '#scripts/lib/read-file'
|
|
8
9
|
import { copy_directory_failure, directory_copy_blocker } from './directory-copy-guard'
|
|
9
10
|
import { file_content } from './file-content'
|
|
10
11
|
import { REMOVED_SKILL_MANIFEST } from './removed-skill-manifest'
|
|
@@ -70,8 +71,7 @@ function sync_workspace_yaml(
|
|
|
70
71
|
is_force = false,
|
|
71
72
|
): boolean {
|
|
72
73
|
const template = readFileSync(template_path, 'utf8')
|
|
73
|
-
const existing =
|
|
74
|
-
!is_force && existsSync(destination_path) ? readFileSync(destination_path, 'utf8') : ''
|
|
74
|
+
const existing = is_force ? '' : file_reader.read_file_or_empty(destination_path)
|
|
75
75
|
const merged = init_logic.merge_workspace_yaml(existing, template)
|
|
76
76
|
|
|
77
77
|
return file_content.write_text_if_changed(destination_path, merged)
|
|
@@ -155,7 +155,7 @@ function ensured_claude_md(existing: string | undefined, shape?: ProjectShape):
|
|
|
155
155
|
// without ever disturbing those additions — so this ignores --force, which would otherwise mean
|
|
156
156
|
// discarding a consumer's content.
|
|
157
157
|
function sync_claude_md(destination_path: string, shape?: ProjectShape): void {
|
|
158
|
-
const existing =
|
|
158
|
+
const existing = file_reader.read_optional(destination_path)
|
|
159
159
|
const ensured = ensured_claude_md(existing, shape)
|
|
160
160
|
|
|
161
161
|
if (ensured === existing) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto'
|
|
2
|
-
import { copyFileSync,
|
|
2
|
+
import { copyFileSync, readFileSync, writeFileSync } from 'node:fs'
|
|
3
3
|
import { package_path } from '#scripts/init/init-paths'
|
|
4
|
+
import { file_reader } from '#scripts/lib/read-file'
|
|
4
5
|
import { z } from 'zod'
|
|
5
6
|
|
|
6
7
|
interface TemplateSourcePair {
|
|
@@ -39,9 +40,7 @@ function read_file(relative_path: string): string {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
function read_optional_file(relative_path: string): string {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return existsSync(full_path) ? readFileSync(full_path, 'utf8') : ''
|
|
43
|
+
return file_reader.read_file_or_empty(package_path(relative_path))
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
function hash_text(text: string): string {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
|
-
import { appendFileSync, readdirSync,
|
|
2
|
+
import { appendFileSync, readdirSync, statSync } from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { file_reader } from '#scripts/lib/read-file'
|
|
5
6
|
|
|
6
7
|
// Whether the preview server process died during a failed E2E attempt.
|
|
7
8
|
//
|
|
@@ -59,11 +60,7 @@ function has_crash_signature(log_text: string): boolean {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function read_file_safe(file_path: string): string {
|
|
62
|
-
|
|
63
|
-
return readFileSync(file_path, 'utf8')
|
|
64
|
-
} catch {
|
|
65
|
-
return ''
|
|
66
|
-
}
|
|
63
|
+
return file_reader.read_if_readable(file_path) ?? ''
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
// Every file under the directory, because wrangler names the debug log after the run and a job that
|
|
@@ -336,8 +336,8 @@ function josh_subcommand(command: string): string | undefined {
|
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
// Whether a shell line is one of the read-only `josh` bookkeeping commands, and nothing else. A chained
|
|
339
|
-
// line falls through. An alias is resolved to its canonical name first
|
|
340
|
-
//
|
|
339
|
+
// line falls through. An alias is resolved to its canonical name first, so the allow-list holds
|
|
340
|
+
// canonical names alone. Everything not on the list falls
|
|
341
341
|
// through to the read/mutation test, which is what keeps `josh gate` / `followup` / `git`
|
|
342
342
|
// non-bundleable (joshuafolkken/kit#1875).
|
|
343
343
|
function is_read_josh(command: string): boolean {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
|
-
import { readdirSync
|
|
2
|
+
import { readdirSync } from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { changed_paths } from '#scripts/git/changed-paths'
|
|
6
6
|
import { git_command } from '#scripts/git/git-command'
|
|
7
|
+
import { file_reader } from '#scripts/lib/read-file'
|
|
7
8
|
import { ui_routes } from './ui-routes'
|
|
8
9
|
|
|
9
10
|
// `josh ui:routes [--staged]` — list the screenshot-target routes the current change touches
|
|
@@ -59,11 +60,7 @@ function route_files(root: string): Array<RouteFile> {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function read_text(file: string): string {
|
|
62
|
-
|
|
63
|
-
return readFileSync(file, 'utf8')
|
|
64
|
-
} catch {
|
|
65
|
-
return ''
|
|
66
|
-
}
|
|
63
|
+
return file_reader.read_if_readable(file) ?? ''
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
// A route file imports the component when its source names the component's file — the import
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { readFileSync, writeFileSync } from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
5
6
|
import { json_object_schema, package_with_version_schema } from '#scripts/lib/schemas'
|
|
6
7
|
import semver from 'semver'
|
|
7
8
|
|
|
@@ -61,7 +62,7 @@ function main(): void {
|
|
|
61
62
|
try {
|
|
62
63
|
bump_version(bump_type as BumpType)
|
|
63
64
|
} catch (error) {
|
|
64
|
-
console.error(
|
|
65
|
+
console.error(error_text.message_of(error))
|
|
65
66
|
process.exit(1)
|
|
66
67
|
}
|
|
67
68
|
}
|