@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
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**単一ソースはこのファイルである。**
|
|
4
4
|
|
|
5
|
-
**この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/delivered-rules.ts` の `WIP_CAP_REASON`
|
|
5
|
+
**この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/delivered-rules.ts` の `WIP_CAP_REASON` にある(固定するテストは `docs/maintainers/wip-cap-rationale.md` →「文言を固定しているテスト」)。
|
|
6
|
+
|
|
7
|
+
背景・測定・経緯は保守者向けの `docs/maintainers/wip-cap-rationale.md` にあり、ラン中に読む必要はない。
|
|
6
8
|
|
|
7
9
|
## 規則
|
|
8
10
|
|
|
@@ -19,11 +21,11 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
19
21
|
- epic も子も含める。epic を除外すると、epic を作ることで上限を回避できてしまう。
|
|
20
22
|
- **上限は 30。** 31 件目以降を作る前に 1 件閉じる。
|
|
21
23
|
- **プルリクエストは数えない。** REST の `issues` エンドポイントは PR も返すため、`select(.pull_request == null)` で落とす。この 1 句を省くと、PR が開いているだけで上限に達する。
|
|
22
|
-
- **`gh issue list` は使わない。** 配布ドキュメントの実行可能ブロックに置ける `gh` は REST のものだけで、`gh issue list` は GraphQL 経由のためクラウドセッションで 403
|
|
24
|
+
- **`gh issue list` は使わない。** 配布ドキュメントの実行可能ブロックに置ける `gh` は REST のものだけで、`gh issue list` は GraphQL 経由のためクラウドセッションで 403 になる。
|
|
23
25
|
|
|
24
26
|
## なぜ上限が要るのか
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
測定は `docs/maintainers/wip-cap-rationale.md` →「なぜ上限が要るのか — 測定」。
|
|
27
29
|
|
|
28
30
|
**上限は、増加を見えるようにするための強制装置である。** 数を減らすこと自体が目的ではない。30 を超えた状態で起票しようとしたときに「本当にこれは 1 件増やす価値があるか」を必ず 1 回考えさせる、そこだけが役割である。
|
|
29
31
|
|
|
@@ -45,15 +47,15 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
45
47
|
|
|
46
48
|
前提 Issue(`SKILL.md` → §2d)、別パッケージ起因の割り込み Issue、ユーザーが `new` と打った入口、`issue:scout` が重複無しと答えた新規作業、**そして分割判定が作る子 Issue と epic**。**これらは起票しないと実行が進まない。**
|
|
47
49
|
|
|
48
|
-
- **上限を理由に止めない。**
|
|
49
|
-
- **分割の子がここに入る理由**: 分割を検出した `fullrun` / `halfrun` は「子と epic を起票して **STOP**」と定められている(`fullrun.md` / `halfrun.md
|
|
50
|
+
- **上限を理由に止めない。** 理由は `docs/maintainers/wip-cap-rationale.md` →「実行が詰まる起票を止めない理由」。
|
|
51
|
+
- **分割の子がここに入る理由**: 分割を検出した `fullrun` / `halfrun` は「子と epic を起票して **STOP**」と定められている(`fullrun.md` / `halfrun.md`)。**分割するかどうかを決めるのは分割判定の側**で、既定はもう「分割しない」に上がっている — 上限が二重に効く必要はない。
|
|
50
52
|
- **超過した事実は完了報告に 1 行書く**(例: 「オープン 34 件で起票した」)。上限は可視化のための装置なので、超えたことが見えていれば役割は果たしている。
|
|
51
53
|
|
|
52
54
|
### 割り込み起票 — 上限が効かない側(3 条件で機械的に決める)
|
|
53
55
|
|
|
54
|
-
**重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** joshuafolkken/kit#1517
|
|
56
|
+
**重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** 上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。由来は `docs/maintainers/wip-cap-rationale.md` →「割り込み区分の由来 — joshuafolkken/kit#1517」。
|
|
55
57
|
|
|
56
|
-
**別パッケージ起因の割り込みとは別の区分である。** あちらは上流リポジトリへ起票して停止する手順(`upstream-interrupt.md`、`route:tier-a
|
|
58
|
+
**別パッケージ起因の割り込みとは別の区分である。** あちらは上流リポジトリへ起票して停止する手順(`upstream-interrupt.md`、`route:tier-a`)で、実行が詰まる側に属する。ここで言う割り込みは、**このリポジトリの欠陥で、発見したランをブロックしていないもの**を指す。
|
|
57
59
|
|
|
58
60
|
#### 3 条件 — 該当するかは判断ではない
|
|
59
61
|
|
|
@@ -65,7 +67,7 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
65
67
|
|
|
66
68
|
**3 つのいずれにも当たらない発見は、従来どおり裁量側の出口を取る。** 改善案、設計上の好み、未検証の疑い、「あとで直したい」はここに入らない — レビュー指摘なら branch 3(PR 本文に 1 行残して落とす)であり、それは既定の出口であって上限に阻まれたときの代替ではない。
|
|
67
69
|
|
|
68
|
-
**深刻さの自己申告は条件ではない。**
|
|
70
|
+
**深刻さの自己申告は条件ではない。** 理由は `docs/maintainers/wip-cap-rationale.md` →「深刻さの自己申告を条件にしない理由」。
|
|
69
71
|
|
|
70
72
|
#### 該当したときの手順
|
|
71
73
|
|
|
@@ -76,14 +78,14 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
76
78
|
```
|
|
77
79
|
|
|
78
80
|
2. **超過している事実と、当たった条件の番号を本文に 1 行書く**(例:「オープン 37 件で起票。3 条件のうち 2(文書化された手順が完了できない)に該当」)。**どちらか一方では足りない** — 件数だけでは判定が再現できず、条件だけでは上限の可視化が効かない。
|
|
79
|
-
3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` 関係を実際に書き込むため(`docs/josh-commands.md` →「`josh epic --add`」)、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になり、`epic:next` が実装中の子を「割り込みにブロックされている」として出さなくなる。位置を指定しない追加は依存を一切宣言しない(joshuafolkken/kit#1253)ので、**順序は実行側が持つ** —
|
|
81
|
+
3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` 関係を実際に書き込むため(`docs/josh-commands.md` →「`josh epic --add`」)、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になり、`epic:next` が実装中の子を「割り込みにブロックされている」として出さなくなる。位置を指定しない追加は依存を一切宣言しない(joshuafolkken/kit#1253)ので、**順序は実行側が持つ** — 次に取り上げるのは実行側の選択であって、宣言された関係ではない(経緯は `docs/maintainers/wip-cap-rationale.md` →「位置を指定しない追加の経緯」)。**先に提示させたいときは `--order-before <M>` を使う**(joshuafolkken/kit#1738)— これはタスクリストの行だけを動かし、依存宣言も `blocked-by` も一切書かないので、上の禁止には当たらない。**禁止しているのは依存を書き込む `--before` / `--after` であって、順序そのものではない。** `epic:next` は runnable な子をタスクリスト順に提示する(joshuafolkken/kit#1583)ため、位置を指定しない追加は「末尾に提示される」を意味する — 割り込みを次に取り上げてほしいなら、行だけを前に出すこの指定がその手段である。**epic の下に無いなら挿入先そのものが無い**ので、この手順は飛ばして 4 だけを行う。
|
|
80
82
|
4. **着手は、既にある承認の内側でのみ、指示を待たずに行う。** `backlogrun` の中なら、打たれたキーワードがバッチを承認しているので、割り込みは次の子として着手してよい。**バッチの外では `CLAUDE.md` →「Explicit invocation required」が変わらず効く** — 起票と挿入まで済ませたうえで、利用者に打つべきコマンド(`fullrun #<N>`)を報告して止まる。**割り込みは上限の例外であって、明示起動規則の例外ではない。**
|
|
81
83
|
|
|
82
84
|
**起票と、実行されるようにするところまでが 1 つのまとまりである。** epic の下にある割り込みを起票だけして追加しなければ、`epic:next` はそれを候補にすら出さない — Issue は残るが実行されないという、コメントに埋もれるのと大差ない状態になる。**epic の外にある割り込みでは、まとまりの後半は 4 の報告そのもの**であり、打つべきコマンドを利用者に渡すまでが 1 回の行為である。上の「ひとまとまりで判定する」がここにも効く。
|
|
83
85
|
|
|
84
86
|
#### 実行のしかた — 検証経路そのものの欠陥は単独で走らせる
|
|
85
87
|
|
|
86
|
-
**割り込みの対象が検証経路そのものの欠陥であるとき、その Issue は単独で実行し、バッチを再開するのはそれが `main` へマージされてからとする。** 「着地」はマージであって、PR
|
|
88
|
+
**割り込みの対象が検証経路そのものの欠陥であるとき、その Issue は単独で実行し、バッチを再開するのはそれが `main` へマージされてからとする。** 「着地」はマージであって、PR を開いた時点でもレビューが収束した時点でもない。
|
|
87
89
|
|
|
88
90
|
**該当するかは判断ではなく、影響先の列挙で決まる。** 欠陥が次のいずれかに影響するか:
|
|
89
91
|
|
|
@@ -92,14 +94,9 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
92
94
|
- **push 時のフック**
|
|
93
95
|
- **マージ時のチェック**
|
|
94
96
|
|
|
95
|
-
**いずれかに当たれば単独実行。** その Issue に `run:solo` を付け、強制はそれを読む `backlog:next` と `epic:next --lanes` が行う(joshuafolkken/kit#2776)。当たらなければ(機能追加、文書修正など)`run:lane` を付け、並列バッチの一員として走らせてよい。どちらもなければ `triage` が返り何も始まらない(joshuafolkken/kit#2779)ので、run が起票する Issue
|
|
96
|
-
|
|
97
|
-
**理由は 2 つあり、どちらか一方だけでも単独実行の根拠として十分である。**
|
|
98
|
-
|
|
99
|
-
1. **壊れた検証の上でバッチを回すと、全員の結果が信用できない。** 6 レーンを並列で走らせれば、6 件分のゲートまたはレビューがまとめて無意味になる。直したあとに全部やり直すことになるので、単独実行は遅い選択ですらない。
|
|
100
|
-
2. **割り込み自身の検証が、その割り込みが直そうとしている欠陥の影響下にある。** joshuafolkken/kit#1515(テストが実ネットワークを叩いていた)と joshuafolkken/kit#1517(同時実行のスイートが一時ディレクトリを共有していた)はどちらもこの自己言及の罠を抱えており、両者とも単独実行で扱った。
|
|
97
|
+
**いずれかに当たれば単独実行。** その Issue に `run:solo` を付け、強制はそれを読む `backlog:next` と `epic:next --lanes` が行う(joshuafolkken/kit#2776)。当たらなければ(機能追加、文書修正など)`run:lane` を付け、並列バッチの一員として走らせてよい。どちらもなければ `triage` が返り何も始まらない(joshuafolkken/kit#2779)ので、run が起票する Issue(割り込み・分割・前提)は起票時にどちらかを付ける。**「重大だと感じるか」は判定条件ではない**(3 条件と同じ理由)。
|
|
101
98
|
|
|
102
|
-
|
|
99
|
+
**理由は 2 つあり、どちらか一方だけでも単独実行の根拠として十分である。** その 2 つと、判定を列挙にした由来は `docs/maintainers/wip-cap-rationale.md` →「単独実行の理由と由来」。
|
|
103
100
|
|
|
104
101
|
## 上限そのものを変えるとき
|
|
105
102
|
|
|
@@ -109,7 +106,7 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
109
106
|
|
|
110
107
|
## 3 つは一緒に動く
|
|
111
108
|
|
|
112
|
-
上限は単独では効かない。**製造側を止めないまま上限だけ入れると、製造は続いたまま実行だけが止まる。**
|
|
109
|
+
上限は単独では効かない。**製造側を止めないまま上限だけ入れると、製造は続いたまま実行だけが止まる。** 経緯は `docs/maintainers/wip-cap-rationale.md` →「3 つを 1 コミットで着地させた経緯」。
|
|
113
110
|
|
|
114
111
|
| 製造元 | 変更 | 単一ソース |
|
|
115
112
|
| ------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
@@ -10,34 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
**話題ごとにファイルが分かれている。** 以前はこの内容が 1 本の 169KB のファイルにあり、1 つの節を確かめるだけでも全体を読む必要があった。読んだものはそのセッションの残り全ターンで積み上がった前置きとして課金され続けるため、確認 1 回の費用が会話の長さに比例して効いていた(joshuafolkken/kit#965)。**必要な 1 本だけを開くこと。この索引を入口に、下の表から選ぶ。**
|
|
12
12
|
|
|
13
|
-
| 話題
|
|
14
|
-
|
|
|
15
|
-
| Overview
|
|
16
|
-
| Step 1: Issue 作成テンプレ
|
|
17
|
-
| Step 2: 提案依頼(AI 共通)
|
|
18
|
-
| Step 3: 計画コメントを記録して通知する
|
|
19
|
-
| 報告フォーマット(平易な概要 + 技術詳細)
|
|
20
|
-
| セッション向け出力で Issue はリンク+短い日本語要約で参照する
|
|
21
|
-
| 後から関連が判明した Issue を epic
|
|
22
|
-
| オープン Issue の WIP 上限(30 件)
|
|
23
|
-
| リポジトリをまたぐ EPIC
|
|
24
|
-
| `josh epic:audit` — 子 Issue
|
|
25
|
-
| 別パッケージ起因の問題は割り込み Issue で対応する
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
| 独立した呼び出しは同じターンに載せる | [`turn-batching.md`](./collaboration-workflow/turn-batching.md) |
|
|
36
|
-
| `gh` は REST(`gh api`)で書く — 散文の指示も含む | [`gh-rest.md`](./collaboration-workflow/gh-rest.md) |
|
|
37
|
-
| 常駐ドキュメントと skill の分担(何を常駐に残すか) | [`residency.md`](./collaboration-workflow/residency.md) |
|
|
38
|
-
| 引き金つき配送 — 規則を効く瞬間に届ける | [`rule-delivery.md`](./collaboration-workflow/rule-delivery.md) |
|
|
39
|
-
| コマンド出力が文脈へ持ち込む量の上限 | [`output-bounds.md`](./collaboration-workflow/output-bounds.md) |
|
|
40
|
-
| 運用ルール | [`operating-rules.md`](./collaboration-workflow/operating-rules.md) |
|
|
13
|
+
| 話題 | ファイル |
|
|
14
|
+
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
15
|
+
| Overview | [`overview.md`](./collaboration-workflow/overview.md) |
|
|
16
|
+
| Step 1: Issue 作成テンプレ | [`issue-template.md`](./collaboration-workflow/issue-template.md) |
|
|
17
|
+
| Step 2: 提案依頼(AI 共通) | [`proposal-request.md`](./collaboration-workflow/proposal-request.md) |
|
|
18
|
+
| Step 3: 計画コメントを記録して通知する | [`plan-comment.md`](./collaboration-workflow/plan-comment.md) |
|
|
19
|
+
| 報告フォーマット(平易な概要 + 技術詳細) | [`report-format.md`](./collaboration-workflow/report-format.md) |
|
|
20
|
+
| セッション向け出力で Issue はリンク+短い日本語要約で参照する | [`issue-citation.md`](./collaboration-workflow/issue-citation.md) |
|
|
21
|
+
| 後から関連が判明した Issue を epic に束ねる(本文は `epic-commands` skill) | [`epic-bundle.md`](./collaboration-workflow/epic-bundle.md) |
|
|
22
|
+
| オープン Issue の WIP 上限(30 件) | [`wip-cap.md`](./collaboration-workflow/wip-cap.md) |
|
|
23
|
+
| リポジトリをまたぐ EPIC(本文は `epic-commands` skill) | [`cross-repo-epic.md`](./collaboration-workflow/cross-repo-epic.md) |
|
|
24
|
+
| `josh epic:audit` — 子 Issue 群を横断して矛盾を検出する(本文は `epic-commands` skill) | [`epic-audit.md`](./collaboration-workflow/epic-audit.md) |
|
|
25
|
+
| 別パッケージ起因の問題は割り込み Issue で対応する | [`upstream-interrupt.md`](./collaboration-workflow/upstream-interrupt.md) |
|
|
26
|
+
| 原則 — クローン禁止・シンプル第一・相談と実行の区別・最新優先・恒久ルールと配布物と規則の置き場所 | [`principles.md`](./collaboration-workflow/principles.md) |
|
|
27
|
+
| ファイル編集はコマンド本文に本文を載せない | [`file-edits.md`](./collaboration-workflow/file-edits.md) |
|
|
28
|
+
| 本文をシェルの二重引用符に載せない | [`shell-body.md`](./collaboration-workflow/shell-body.md) |
|
|
29
|
+
| 独立した呼び出しは同じターンに載せる | [`turn-batching.md`](./collaboration-workflow/turn-batching.md) |
|
|
30
|
+
| `gh` は REST(`gh api`)で書く — 散文の指示も含む | [`gh-rest.md`](./collaboration-workflow/gh-rest.md) |
|
|
31
|
+
| 常駐ドキュメントと skill の分担(何を常駐に残すか) | [`residency.md`](./collaboration-workflow/residency.md) |
|
|
32
|
+
| 引き金つき配送 — 規則を効く瞬間に届ける | [`rule-delivery.md`](./collaboration-workflow/rule-delivery.md) |
|
|
33
|
+
| コマンド出力が文脈へ持ち込む量の上限 | [`output-bounds.md`](./collaboration-workflow/output-bounds.md) |
|
|
34
|
+
| 運用ルール | [`operating-rules.md`](./collaboration-workflow/operating-rules.md) |
|
|
41
35
|
|
|
42
36
|
**どの 1 本を開けばよいかを決めるのに必要なのは、この索引だけである。** バイト数はここに書かない — 手で保守した数字は本文より先に古くなり、古い数字は無いより悪い。実サイズは `ls -l prompts/collaboration-workflow/` が答える。
|
|
43
37
|
|
|
@@ -42,7 +42,7 @@ per the table below, and do not let it silently block an unrelated change).
|
|
|
42
42
|
## Step A / Step B: fetch the hotspots and read each one's disposition
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
pnpm josh sonar:hotspots <PR>
|
|
45
|
+
pnpm josh sonar:hotspots <PR>
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
The command fetches the hotspots on the pull request from SonarCloud's public API (no auth), reading
|
|
@@ -12,7 +12,7 @@ const ADOPT_ORIGIN = 'Opened by `josh adopt` in this repository.'
|
|
|
12
12
|
const INCOMPLETE_HEADLINE =
|
|
13
13
|
'Refusing to adopt: these declared toolkits would fall out of the plan, and the run would sync the rest without them.'
|
|
14
14
|
const INCOMPLETE_EFFECT =
|
|
15
|
-
"The toolkits overlay files derived from kit's own (see docs/sync.md), so syncing kit without one rewrites that overlay back to kit's original — a wrong diff wearing kit's face."
|
|
15
|
+
"The toolkits overlay files derived from kit's own (see docs/maintainers/sync-rationale.md), so syncing kit without one rewrites that overlay back to kit's original — a wrong diff wearing kit's face."
|
|
16
16
|
const MISPLACED_CAUSE =
|
|
17
17
|
'declared under `dependencies`; the upgrade installs with `pnpm add -D` and would relocate it. Move it to `devDependencies`.'
|
|
18
18
|
const ABSENT_CAUSE =
|
|
@@ -60,7 +60,7 @@ function name_causes(package_names: ReadonlyArray<string>, cause: string): Array
|
|
|
60
60
|
|
|
61
61
|
// A declared toolkit that falls out of the plan is a refusal rather than a warning
|
|
62
62
|
// (joshuafolkken/kit#1540). kit distributes the base files and every other toolkit overlays files
|
|
63
|
-
// *derived* from them (`docs/sync.md` →
|
|
63
|
+
// *derived* from them (`docs/maintainers/sync-rationale.md` → "The managed-workflow stamp"), so a run that syncs kit without the
|
|
64
64
|
// overlay does not merely do less — it writes the overlay's paths back to kit's originals. That diff
|
|
65
65
|
// then wears kit's own face in the pull request, which is exactly what a reviewer cannot spot.
|
|
66
66
|
//
|
|
@@ -32,7 +32,7 @@ function is_toolkit_package(package_name: string): boolean {
|
|
|
32
32
|
|
|
33
33
|
// kit is the base tier and every other toolkit distributes files *derived* from kit's, so the two
|
|
34
34
|
// can manage the same path and whichever `sync` ran last decides its contents
|
|
35
|
-
// (`docs/sync.md` → "
|
|
35
|
+
// (`docs/maintainers/sync-rationale.md` → "The managed-workflow stamp"). Ordering is therefore base-first: kit syncs, then the
|
|
36
36
|
// toolkits that overlay it. Sorting by name would put kit last and have it overwrite the overlay
|
|
37
37
|
// with the original every single run.
|
|
38
38
|
function toolkit_rank(package_name: string): number {
|
|
@@ -171,7 +171,9 @@ const adopt_toolkits = {
|
|
|
171
171
|
declared_toolkits,
|
|
172
172
|
misplaced_toolkits,
|
|
173
173
|
pick_bin_name,
|
|
174
|
+
bin_name_of,
|
|
174
175
|
read_bin_name,
|
|
176
|
+
all_declared_toolkits,
|
|
175
177
|
is_unreachable_toolkit,
|
|
176
178
|
resolve_toolkit,
|
|
177
179
|
discover_toolkits,
|
package/scripts/adopt/adopt.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
4
|
-
import {
|
|
4
|
+
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
5
5
|
import { propagate_run, type TargetResult } from '#scripts/propagate/propagate-run'
|
|
6
6
|
import { propagate_steps, type Release, type ReleasePlan } from '#scripts/propagate/propagate-steps'
|
|
7
7
|
import type { PropagateTarget } from '#scripts/propagate/propagate-targets'
|
|
@@ -40,7 +40,7 @@ interface RunOptions {
|
|
|
40
40
|
|
|
41
41
|
function parse_options(argv: ReadonlyArray<string>): RunOptions {
|
|
42
42
|
const options: RunOptions = { is_dry_run: argv.includes(DRY_RUN_FLAG) }
|
|
43
|
-
const usage = refuse_unknown_flags(argv, KNOWN_FLAGS, 'adopt')
|
|
43
|
+
const usage = cli_flags.refuse_unknown_flags(argv, KNOWN_FLAGS, 'adopt')
|
|
44
44
|
|
|
45
45
|
return usage === undefined ? options : { ...options, usage }
|
|
46
46
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
1
2
|
import { z } from 'zod'
|
|
2
3
|
import type { AgentProvider } from './agent-role-profile'
|
|
3
4
|
import { claude_result_event } from './claude-result-event'
|
|
@@ -53,14 +54,6 @@ const EMPTY_STATE: AgentEventState = {
|
|
|
53
54
|
const LAUNCH_HEADER_PREFIX = '=== '
|
|
54
55
|
const LAUNCH_HEADER_MARKER = ' · started by process '
|
|
55
56
|
|
|
56
|
-
function parse_line(line: string): unknown {
|
|
57
|
-
try {
|
|
58
|
-
return JSON.parse(line)
|
|
59
|
-
} catch {
|
|
60
|
-
return undefined
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
57
|
function usable_text(value: unknown): string | undefined {
|
|
65
58
|
return typeof value === 'string' && value.trim() !== '' ? value : undefined
|
|
66
59
|
}
|
|
@@ -149,7 +142,7 @@ function next_state(line: string, state: AgentEventState): AgentEventState {
|
|
|
149
142
|
const is_header = line.startsWith(LAUNCH_HEADER_PREFIX) && line.includes(LAUNCH_HEADER_MARKER)
|
|
150
143
|
if (is_header) return EMPTY_STATE
|
|
151
144
|
|
|
152
|
-
return normalized(
|
|
145
|
+
return normalized(json_value.parse_or_undefined(line), state)
|
|
153
146
|
}
|
|
154
147
|
|
|
155
148
|
function read(transcript: string): AgentEventState {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
1
2
|
import { claude_result_event, type ClaudeResultEvent } from './claude-result-event'
|
|
2
3
|
|
|
3
4
|
// The exit record of a dispatched lane child — the terminal `result` event a `claude -p` session
|
|
@@ -12,18 +13,10 @@ import { claude_result_event, type ClaudeResultEvent } from './claude-result-eve
|
|
|
12
13
|
// over; a transcript with no result event at all reads as `undefined`, which the classifier treats as
|
|
13
14
|
// an unreadable ending rather than guessing one.
|
|
14
15
|
|
|
15
|
-
function parse_line(line: string): unknown {
|
|
16
|
-
try {
|
|
17
|
-
return JSON.parse(line)
|
|
18
|
-
} catch {
|
|
19
|
-
return undefined
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
16
|
function read_exit_record(transcript: string): ClaudeResultEvent | undefined {
|
|
24
17
|
return transcript
|
|
25
18
|
.split('\n')
|
|
26
|
-
.map((line) => claude_result_event.decode(
|
|
19
|
+
.map((line) => claude_result_event.decode(json_value.parse_or_undefined(line)))
|
|
27
20
|
.findLast((record) => record !== undefined)
|
|
28
21
|
}
|
|
29
22
|
|
|
@@ -310,9 +310,8 @@ async function fetch_tracking(count: number): Promise<TrackingRead> {
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
// The pickup *order* is `git_next_issues.
|
|
314
|
-
// `epic` / `in-progress` / `needs-decision` exclusions
|
|
315
|
-
// which reads only the first row.
|
|
313
|
+
// The pickup *order* is `git_next_issues.order` itself, not a copy of it: the ranking `prioritize`
|
|
314
|
+
// shows, with the `epic` / `in-progress` / `needs-decision` exclusions, before its display cap.
|
|
316
315
|
//
|
|
317
316
|
// The two are no longer the same *set*, and deliberately so: since joshuafolkken/kit#996 the pickup
|
|
318
317
|
// also drops a candidate whose prerequisite is still open, while `🗒 Next issues` shows every open
|
|
@@ -323,9 +322,12 @@ async function fetch_tracking(count: number): Promise<TrackingRead> {
|
|
|
323
322
|
// Membership of the label is the *query's* job, not this function's: `--label` is what makes the
|
|
324
323
|
// listing the opted-in set, so re-testing it here would be a second definition of opting in.
|
|
325
324
|
//
|
|
326
|
-
// The exclusions are applied
|
|
327
|
-
//
|
|
328
|
-
// runnable issue sits below them.
|
|
325
|
+
// The exclusions are applied to `git_next_issues.order`'s **uncapped** ranking, never to
|
|
326
|
+
// `prioritize`'s capped one, which would answer `none` whenever its first rows happen to be blocked
|
|
327
|
+
// while a runnable issue sits below them. They are applied **after** the ranking, not before it: the
|
|
328
|
+
// dependents key counts the issues waiting on a row, and a waiting issue is by definition blocked —
|
|
329
|
+
// filtered first, every row would count zero and the key would never decide anything
|
|
330
|
+
// (joshuafolkken/kit#2928).
|
|
329
331
|
//
|
|
330
332
|
// The `🗒 Next issues` display is deliberately *not* filtered this way; `git-next-issues.ts` records
|
|
331
333
|
// why, and the short version is that a person can see a blocked issue and choose to start it anyway
|
|
@@ -354,9 +356,7 @@ function pick_next(
|
|
|
354
356
|
tracked: ReadonlyMap<number, number> = new Map(),
|
|
355
357
|
exclude: ReadonlyArray<number> = [],
|
|
356
358
|
): OpenIssueData | undefined {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return git_next_issues.prioritize(runnable)[0]
|
|
359
|
+
return git_next_issues.order(issues).find((issue) => is_runnable(issue, tracked, exclude))
|
|
360
360
|
}
|
|
361
361
|
|
|
362
362
|
// Why there is nothing to run. "No open issue carries the label" and "every opted-in issue is
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
|
-
import { parseArgs } from 'node:util'
|
|
4
3
|
import { path_decision } from '#scripts/josh/path-decision'
|
|
4
|
+
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
5
5
|
import { backlog_budget, type BacklogAnswer, type BudgetInput } from './backlog-budget'
|
|
6
6
|
|
|
7
7
|
// The thin half of `josh backlog:budget` (joshuafolkken/kit#1632): read the loop's state off the
|
|
@@ -32,11 +32,7 @@ type ParsedValues = Partial<Record<OptionName, string | boolean>>
|
|
|
32
32
|
// A misspelled flag is refused rather than defaulted, the contract `path_decision.has_unknown_flag`
|
|
33
33
|
// states for the path-decided commands: an invocation nobody can read is never answered.
|
|
34
34
|
function read_arguments(argv: ReadonlyArray<string>): ParsedValues | undefined {
|
|
35
|
-
|
|
36
|
-
return parseArgs({ args: [...argv], options: OPTIONS, strict: true }).values
|
|
37
|
-
} catch {
|
|
38
|
-
return undefined
|
|
39
|
-
}
|
|
35
|
+
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
function text_of(value: string | boolean | undefined): string | undefined {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { setTimeout as sleep } from 'node:timers/promises'
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
|
-
import { parseArgs } from 'node:util'
|
|
5
4
|
import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-threshold'
|
|
6
5
|
import { hook_decision } from '#scripts/josh/hook-decision'
|
|
7
6
|
import { josh_command } from '#scripts/josh/josh-run'
|
|
8
7
|
import { lane_await, type AwaitState } from '#scripts/lane/lane-await'
|
|
9
8
|
import { lane_launch_cli } from '#scripts/lane/lane-launch-cli'
|
|
10
9
|
import { lane_registry } from '#scripts/lane/lane-registry'
|
|
10
|
+
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
11
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
11
12
|
import { run_carry, type RunCarry } from '#scripts/run/run-carry'
|
|
12
13
|
import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
|
|
13
14
|
import { run_merge_cli } from '#scripts/run/run-merge-cli'
|
|
@@ -49,7 +50,7 @@ const LIST_SEPARATOR = ','
|
|
|
49
50
|
const COUNT_PATTERN = /^\d+$/u
|
|
50
51
|
const ISSUE_PATTERN = /^[1-9]\d*$/u
|
|
51
52
|
const USAGE =
|
|
52
|
-
'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>]'
|
|
53
|
+
'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>] [--stopped <n>]'
|
|
53
54
|
|
|
54
55
|
const OPTIONS = {
|
|
55
56
|
active: { type: 'string' },
|
|
@@ -59,6 +60,7 @@ const OPTIONS = {
|
|
|
59
60
|
max: { type: 'string' },
|
|
60
61
|
only: { type: 'boolean' },
|
|
61
62
|
owner: { type: 'string' },
|
|
63
|
+
stopped: { type: 'string' },
|
|
62
64
|
window: { type: 'string' },
|
|
63
65
|
} as const
|
|
64
66
|
|
|
@@ -72,16 +74,14 @@ interface DriveContext {
|
|
|
72
74
|
window_ms: number | undefined
|
|
73
75
|
window: string | undefined
|
|
74
76
|
is_only: boolean
|
|
77
|
+
// The child whose merge answered `stop` before the hand-back: the resumed run starts already stopping.
|
|
78
|
+
stopped: string | undefined
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
type Values = Partial<Record<Exclude<keyof typeof OPTIONS, 'only'>, string>> & { only?: boolean }
|
|
78
82
|
|
|
79
83
|
function read_values(argv: ReadonlyArray<string>): Values | undefined {
|
|
80
|
-
|
|
81
|
-
return parseArgs({ args: [...argv], options: OPTIONS, strict: true }).values
|
|
82
|
-
} catch {
|
|
83
|
-
return undefined
|
|
84
|
-
}
|
|
84
|
+
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// A comma list of issue numbers; one entry that is not an issue number refuses the whole list.
|
|
@@ -110,6 +110,12 @@ function is_valid_window(raw: string | undefined): boolean {
|
|
|
110
110
|
return raw === undefined || COUNT_PATTERN.test(raw)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
function is_valid_single(values: Values): boolean {
|
|
114
|
+
const is_valid_stopped = values.stopped === undefined || ISSUE_PATTERN.test(values.stopped)
|
|
115
|
+
|
|
116
|
+
return is_valid_stopped && is_valid_window(values.window)
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
function owner_of(values: Values | undefined): string | undefined {
|
|
114
120
|
const owner = values?.owner
|
|
115
121
|
|
|
@@ -117,7 +123,7 @@ function owner_of(values: Values | undefined): string | undefined {
|
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
function to_context(values: Values, owner: string): DriveContext | undefined {
|
|
120
|
-
if (!
|
|
126
|
+
if (!is_valid_single(values)) return undefined
|
|
121
127
|
|
|
122
128
|
const forwarded = forwarded_of(values)
|
|
123
129
|
const exclude = to_issues(values.exclude)
|
|
@@ -136,6 +142,7 @@ function to_context(values: Values, owner: string): DriveContext | undefined {
|
|
|
136
142
|
window_ms,
|
|
137
143
|
window: values.window,
|
|
138
144
|
is_only: values.only === true,
|
|
145
|
+
stopped: values.stopped,
|
|
139
146
|
}
|
|
140
147
|
}
|
|
141
148
|
|
|
@@ -274,6 +281,7 @@ function resume_line(state: DriveState, context: DriveContext): string {
|
|
|
274
281
|
|
|
275
282
|
if (exclude.length > 0) flags.push('--exclude', exclude.join(LIST_SEPARATOR))
|
|
276
283
|
if (context.window !== undefined) flags.push('--window', context.window)
|
|
284
|
+
if (state.stopped_by !== undefined) flags.push('--stopped', state.stopped_by)
|
|
277
285
|
|
|
278
286
|
return `resume: ${flags.join(' ')}`
|
|
279
287
|
}
|
|
@@ -325,7 +333,9 @@ async function drive(context: DriveContext): Promise<number> {
|
|
|
325
333
|
const seeded = await seeded_lanes(context)
|
|
326
334
|
|
|
327
335
|
if (seeded === undefined) return FAILURE_EXIT_CODE
|
|
328
|
-
const
|
|
336
|
+
const fresh = backlog_drive.initial_state(seeded, context.active ?? new Date().toISOString())
|
|
337
|
+
const initial =
|
|
338
|
+
context.stopped === undefined ? fresh : backlog_drive.merge_stopped(context.stopped, fresh)
|
|
329
339
|
const last = { state: { ...initial, exclude: [...context.exclude] } }
|
|
330
340
|
const config = { poll_ms: POLL_MS, offer_ms: OFFER_MS, window_ms: context.window_ms }
|
|
331
341
|
const end = await backlog_drive.run_loop(last.state, config, ports_of(context, seeded, last))
|
|
@@ -340,7 +350,7 @@ async function run_safe(context: DriveContext): Promise<number> {
|
|
|
340
350
|
try {
|
|
341
351
|
return await drive(context)
|
|
342
352
|
} catch (error) {
|
|
343
|
-
console.info(`error ${
|
|
353
|
+
console.info(`error ${error_text.message_of(error)}`)
|
|
344
354
|
|
|
345
355
|
return FAILURE_EXIT_CODE
|
|
346
356
|
}
|
|
@@ -16,19 +16,22 @@
|
|
|
16
16
|
// **Everything it touches is a port**, the pattern `run-wake-loop.ts` set, so the sequencing is pinned
|
|
17
17
|
// without a process, a network or a clock.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const RUN_VERDICT = 'run'
|
|
20
|
+
const STOP_VERDICT = 'stop'
|
|
21
|
+
// The `run:merge` tokens that end the loop at once: a hand-off, a person's stop, the environment down,
|
|
22
|
+
// a foreign owner, an unreadable state. `resumed` is not among them — the same lane is awaited again.
|
|
23
|
+
const IMMEDIATE_TOKENS: ReadonlySet<string> = new Set([
|
|
22
24
|
'over',
|
|
23
25
|
'human-review',
|
|
24
|
-
'stop',
|
|
25
26
|
'environment',
|
|
26
27
|
'busy',
|
|
27
28
|
'retry',
|
|
28
29
|
])
|
|
30
|
+
// Every token `run:merge` prints first even on a non-zero exit. `stop` — a parked backlog or the failure
|
|
31
|
+
// guard — is the offer's `stop` reached through a merge: the child is collected, nothing more starts,
|
|
32
|
+
// and the children still in flight are collected before the loop ends (joshuafolkken/kit#2881).
|
|
33
|
+
const HANDOFF_TOKENS: ReadonlySet<string> = new Set([...IMMEDIATE_TOKENS, STOP_VERDICT])
|
|
29
34
|
const RESUMED_TOKEN = 'resumed'
|
|
30
|
-
const RUN_VERDICT = 'run'
|
|
31
|
-
const STOP_VERDICT = 'stop'
|
|
32
35
|
const WATCH_VERDICT = 'watch'
|
|
33
36
|
// The verdicts the loop acts on without the parent. Any other is handed back as it was printed.
|
|
34
37
|
const KNOWN_VERDICTS: ReadonlySet<string> = new Set([
|
|
@@ -63,6 +66,8 @@ interface DriveState {
|
|
|
63
66
|
is_stopping: boolean
|
|
64
67
|
stop_reason?: string | undefined
|
|
65
68
|
stop_is_finish?: boolean | undefined
|
|
69
|
+
// The child whose merge answered `stop`, carried on the resume line: no offer re-derives that stop.
|
|
70
|
+
stopped_by?: string | undefined
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
interface DriveEnd {
|
|
@@ -133,22 +138,43 @@ function initial_state(in_flight: ReadonlyArray<string>, active: string): DriveS
|
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
|
|
136
|
-
//
|
|
141
|
+
// The stop a merge reached: kept as the first stop's reason when an offer already stopped the run.
|
|
142
|
+
function merge_stopped(issue: string, state: DriveState): DriveState {
|
|
143
|
+
if (state.is_stopping) return state
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
...state,
|
|
147
|
+
is_stopping: true,
|
|
148
|
+
stop_reason: `run:merge #${issue} answered stop`,
|
|
149
|
+
stopped_by: issue,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// The child collected and excluded, and — unless its cut was resumed in place — out of flight.
|
|
154
|
+
function collected_state(
|
|
155
|
+
issue: string,
|
|
156
|
+
token: string,
|
|
157
|
+
state: DriveState,
|
|
158
|
+
active: string,
|
|
159
|
+
): DriveState {
|
|
160
|
+
const in_flight =
|
|
161
|
+
token === RESUMED_TOKEN ? state.in_flight : state.in_flight.filter((item) => item !== issue)
|
|
162
|
+
const exclude = state.exclude.includes(issue) ? state.exclude : [...state.exclude, issue]
|
|
163
|
+
|
|
164
|
+
return { ...state, in_flight, exclude, active }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// One finished child: handed back on an immediate token, otherwise collected.
|
|
137
168
|
async function collect(issue: string, state: DriveState, ports: DrivePorts): Promise<PassResult> {
|
|
138
169
|
const token = await ports.merge(issue)
|
|
139
170
|
|
|
140
171
|
// An empty first line is a `run:merge` that failed before printing one: never read as a collection.
|
|
141
172
|
if (token === '') return ended('merge', state, undefined, issue)
|
|
142
|
-
if (
|
|
173
|
+
if (IMMEDIATE_TOKENS.has(token)) return ended('merge', state, token, issue)
|
|
143
174
|
|
|
144
|
-
const
|
|
145
|
-
token === RESUMED_TOKEN ? state.in_flight : state.in_flight.filter((item) => item !== issue)
|
|
146
|
-
const exclude = state.exclude.includes(issue) ? state.exclude : [...state.exclude, issue]
|
|
175
|
+
const next = collected_state(issue, token, state, ports.now().toISOString())
|
|
147
176
|
|
|
148
|
-
return {
|
|
149
|
-
kind: 'continue',
|
|
150
|
-
state: { ...state, in_flight, exclude, active: ports.now().toISOString() },
|
|
151
|
-
}
|
|
177
|
+
return { kind: 'continue', state: token === STOP_VERDICT ? merge_stopped(issue, next) : next }
|
|
152
178
|
}
|
|
153
179
|
|
|
154
180
|
async function collect_finished(state: DriveState, ports: DrivePorts): Promise<PassResult> {
|
|
@@ -320,7 +346,15 @@ async function run_loop(
|
|
|
320
346
|
return step.end
|
|
321
347
|
}
|
|
322
348
|
|
|
323
|
-
const backlog_drive = {
|
|
349
|
+
const backlog_drive = {
|
|
350
|
+
HANDOFF_TOKENS,
|
|
351
|
+
collect,
|
|
352
|
+
initial_state,
|
|
353
|
+
merge_stopped,
|
|
354
|
+
on_verdict,
|
|
355
|
+
run_loop,
|
|
356
|
+
run_pass,
|
|
357
|
+
}
|
|
324
358
|
|
|
325
359
|
export type { DriveEnd, DrivePorts, DriveState, LoopConfig, LoopPorts, OfferRead, PassResult }
|
|
326
360
|
export { backlog_drive }
|