@joshuafolkken/kit 1.1166.0 → 1.1178.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/skills/workflow-commands/backlogrun-lanes.md +3 -3
- package/.claude/skills/workflow-commands/backlogrun-park.md +6 -7
- package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -4
- package/.github/workflows/ci.yml +15 -2
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-5KTCMCOT.js → chunk-32GQTL4F.js} +1 -1
- package/dist/hooks/{chunk-URJA6XY4.js → chunk-DO6NWWHU.js} +4 -4
- package/dist/hooks/{chunk-GU5MATVE.js → chunk-G6KRCKEC.js} +11 -19
- package/dist/hooks/{chunk-ZDZ555YH.js → chunk-GDS5N2KB.js} +88 -291
- package/dist/hooks/{chunk-GYNGP7HI.js → chunk-I4XSL4TT.js} +1 -1
- package/dist/hooks/{chunk-DYAVAM6S.js → chunk-S6X6WYKR.js} +324 -49
- package/dist/hooks/{chunk-ANJ2WGFD.js → chunk-UAGLLIGZ.js} +1 -1
- package/dist/hooks/{chunk-ENA7P5FB.js → chunk-VESKRQOF.js} +3 -3
- package/dist/hooks/{chunk-V2BTOZHT.js → chunk-VQLLNFNT.js} +3 -3
- package/dist/hooks/{chunk-A6P7PN7P.js → chunk-ZAL3NRGL.js} +2 -2
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/inputs.json +192 -192
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +9 -9
- package/dist/hooks/stop-guard.js +18 -4
- package/dist/josh.js +4 -1
- package/package.json +1 -1
- package/scripts/backlog/backlog-next.ts +15 -4
- package/scripts/backlog/backlog-plan-cli.ts +6 -5
- package/scripts/backlog/backlog-rank.ts +18 -9
- package/scripts/backlog/backlog-restructure.ts +152 -0
- package/scripts/backlog/backlog-waves.ts +15 -17
- package/scripts/cost-runtime/context-cut-threshold.ts +1 -9
- package/scripts/cost-runtime/cost-verdict.ts +15 -28
- package/scripts/followup/git-followup-stages.ts +9 -0
- package/scripts/followup/git-pr-followup.ts +1 -1
- package/scripts/gh/git-gh-issue.ts +5 -3
- package/scripts/gh/git-gh-pr-read.ts +4 -0
- package/scripts/gh/git-pr-checks-eval.ts +8 -0
- package/scripts/gh/git-pr-checks.ts +11 -1
- package/scripts/git/constants.ts +10 -0
- package/scripts/git/main-merge.ts +57 -21
- package/scripts/git/schemas.ts +2 -0
- package/scripts/josh/josh-commands-development.ts +1 -1
- package/scripts/lane/lane-launch-cli.ts +21 -3
- package/scripts/notify/telegram-notify.ts +26 -1
- package/scripts/rules/pre-gate-cut.ts +2 -2
- package/scripts/run/run-carry.ts +11 -5
- package/scripts/run/run-cut-cli.ts +1 -1
- package/scripts/run/run-cut-report.ts +2 -2
- package/scripts/run/run-ship-cli.ts +27 -6
- package/scripts/run/run-ship-next.ts +13 -0
- package/scripts/run/run-ship-pre-detach.ts +66 -0
- package/scripts/run/run-ship-return.ts +7 -4
- package/scripts/run/run-ship-stage.ts +13 -0
- package/scripts/run/run-ship-steps.ts +10 -2
- package/scripts/run/run-ship-sync.ts +114 -0
- package/scripts/run/run-ship.ts +6 -0
- package/scripts/run/run-wake-cli.ts +8 -1
- package/scripts/run/run-wake-driver.ts +42 -11
- package/scripts/test/test-red-logic.ts +17 -2
- package/scripts/test/test-red.ts +8 -7
- package/scripts/time-runtime/time-transcript-line.ts +27 -1
|
@@ -218,8 +218,8 @@ conflict.
|
|
|
218
218
|
| When | The lane | Why |
|
|
219
219
|
| --- | --- | --- |
|
|
220
220
|
| The child **merged** | `pnpm josh lane:close <N>` | `followup` released the hold and the branch is on `main`; nothing in that tree is wanted |
|
|
221
|
-
| The child was **parked before its commit** |
|
|
222
|
-
| The child was **parked after its commit and push** | **Left open**, its directory and held seat recorded on the Issue | The
|
|
221
|
+
| The child was **parked before its commit** | **Left open**, its uncommitted work in place, its directory and held seat recorded on the Issue | The stash stack is shared by every work tree, so a parallel lane can pop another's entry — the tree itself is the safe place for the work. `lane:close` is a **forced** removal that would take it. `pnpm josh lane:launch <N>` dispatches the released child into the kept lane rather than refusing it as `already-open` — only a lane a child was already dispatched into; a failed-install lane is still refused |
|
|
222
|
+
| The child was **parked after its commit and push** | **Left open**, its directory and held seat recorded on the Issue | The tree is clean because committed. What `lane:close` would take is the **local branch**, which is the resume path |
|
|
223
223
|
| The child hit a **merge conflict** | **Left open** — the resolution happens in it | The child resolves in place (`backlogrun-recovery.md` → "Conflicts are not predicted"). A park under that section's four conditions takes the row above |
|
|
224
224
|
| The child stopped on **`needs-human-review`** | **Left open and untouched** | The uncommitted work *is* the artifact a person has to look at. Name the lane directory in the stop report and in the Telegram |
|
|
225
225
|
| The child **failed** | Whichever of the two parked rows applies, plus the consecutive-failure count | Same reasoning; only the counter differs. **A merge conflict is not this row** — it takes the row above, and it is not counted |
|
|
@@ -229,7 +229,7 @@ conflict.
|
|
|
229
229
|
**A lane closed after a push is reopened by `pnpm josh lane:open <N>`**, which attaches to a local
|
|
230
230
|
`<N>-lane` or creates one from `origin/<N>-lane`, saying on standard error which it reused. **The branch
|
|
231
231
|
still has to have reached the remote for that to hold** — a child parked before its commit has nothing
|
|
232
|
-
on `origin`, which is why that row
|
|
232
|
+
on `origin`, which is why that row keeps its lane open rather than closing it. Rationale:
|
|
233
233
|
`docs/maintainers/backlogrun-lanes-rationale.md` → "Why a committed child's lane is kept".
|
|
234
234
|
|
|
235
235
|
**Which row a child takes is decided by what `followup` printed, not by reading the situation.** **What
|
|
@@ -75,12 +75,10 @@ pnpm josh issue:comment <N> --body-file <path> # what needs deciding, and the
|
|
|
75
75
|
`needs-decision` precedence over `in-progress`, so the next child is offered normally. Then return to
|
|
76
76
|
step 1; the other children are unaffected unless they depend on this one.
|
|
77
77
|
|
|
78
|
-
**
|
|
79
|
-
|
|
80
|
-
`
|
|
81
|
-
|
|
82
|
-
removes the work tree by force). **Parked after its commit and push**, the lane is *kept*: nothing to
|
|
83
|
-
stash, and closing would delete the local branch the resume needs. **A lost merge race is not one of
|
|
78
|
+
**A parked child's lane is kept, whether or not it had committed.** **Parked before its commit**, the
|
|
79
|
+
uncommitted work stays in the lane's tree — never in the stash, which every work tree shares — and
|
|
80
|
+
`lane:close` would remove it by force. **Parked after its commit and push**, closing would delete the
|
|
81
|
+
local branch the resume needs. **A lost merge race is not one of
|
|
84
82
|
these rows** — it resolves in its lane (`backlogrun-recovery.md` → "Conflicts are not predicted"), and parks only under that
|
|
85
83
|
section's four conditions, which take the after-commit row. Both rows and the `pnpm josh run:release
|
|
86
84
|
<N>` every parked ending owes are "What happens to a lane" above, the single source.
|
|
@@ -101,7 +99,8 @@ gh api -X DELETE repos/{owner}/{repo}/issues/<N>/labels/needs-decision 2>/dev/nu
|
|
|
101
99
|
|
|
102
100
|
**The released child goes back to a lane, never into the parent's own context.** A parent that is
|
|
103
101
|
*already* running, and clears a label mid-run because a person just answered, dispatches it the same way
|
|
104
|
-
rather than picking up its diff itself — `pnpm josh lane:
|
|
102
|
+
rather than picking up its diff itself — `pnpm josh lane:launch <N>`, which dispatches into the lane the
|
|
103
|
+
park kept, or opens one where none is. A
|
|
105
104
|
parent that implements the released child inline is the failure the orchestrator rule is written against:
|
|
106
105
|
"The parent orchestrates and never implements a child in its own context" above.
|
|
107
106
|
|
|
@@ -308,8 +308,9 @@ Rationale: `docs/maintainers/backlogrun-steps-rationale.md` → "Why the plan an
|
|
|
308
308
|
whose head is `pnpm josh backlog:offer`: the answer-to-budget mapping, the retry count, the `--exclude`
|
|
309
309
|
feedback and the lane count are its own (`docs/josh-commands-automation.md` → "`josh backlog:offer`"
|
|
310
310
|
and "`josh backlog:drive`"). **An AI session reaches this section only when the driver hands a branch
|
|
311
|
-
back** — the `Driver result:` line names it, and
|
|
312
|
-
`pnpm josh run:carry --
|
|
311
|
+
back** — the `Driver result:` line names it, and its `Next:` line is the order: claim the record with
|
|
312
|
+
`pnpm josh run:carry --resume "<invocation>" --owner "$PPID"`, act on the branch, then hand the loop
|
|
313
|
+
back with `pnpm josh run:carry --cut --owner "$PPID"`:
|
|
313
314
|
|
|
314
315
|
| Handed back | What the session judges |
|
|
315
316
|
| --- | --- |
|
|
@@ -58,7 +58,7 @@ pnpm josh run:cut <N>
|
|
|
58
58
|
- `cut` (0) — record written and handed to the lane's launch owner (OpenAI supervisor starts the
|
|
59
59
|
successor after this process exits; Anthropic relaunches directly). **End the turn immediately** —
|
|
60
60
|
the fresh process owns the run.
|
|
61
|
-
- `under-threshold` (0) — the
|
|
61
|
+
- `under-threshold` (0) — the newest request's billed input is under the shared `CONTEXT_CUT_THRESHOLD`,
|
|
62
62
|
so nothing was cut; **continue to the gate.**
|
|
63
63
|
- `not-a-lane` (0) — no open lane for this issue, so not a dispatched child. **Continue to the gate.**
|
|
64
64
|
- `unready` (1) — the tree is clean or on the default branch, nothing to carry. Continue to the gate.
|
|
@@ -79,7 +79,7 @@ carried, handing back the command above. Rationale:
|
|
|
79
79
|
`<lane root>/<issue number>` — **and** `JOSH_LANE_CHILD` names that same issue. An interactive
|
|
80
80
|
`fullrun` carries no mark and runs its gate untouched. `run:cut` uses an open-lane lookup instead, so
|
|
81
81
|
the guard and the command need not agree byte for byte.
|
|
82
|
-
- **It fires only when the
|
|
82
|
+
- **It fires only when the current context warrants a cut**. The guard
|
|
83
83
|
reads the same `cost_cli.session_verdict` `run:cut` reads, so an `under`-threshold lane is let through
|
|
84
84
|
to the gate rather than refused.
|
|
85
85
|
- **It is silent once the cut is carried**, so the resumed process goes straight to the gate.
|
|
@@ -180,8 +180,8 @@ after the fact by `pnpm josh run:ending <N> --output <path>` (joshuafolkken/kit#
|
|
|
180
180
|
|
|
181
181
|
## The threshold
|
|
182
182
|
|
|
183
|
-
`CONTEXT_CUT_THRESHOLD` and
|
|
184
|
-
|
|
183
|
+
`CONTEXT_CUT_THRESHOLD` and `cost_verdict.per_request_cost` (the newest request's billed input)
|
|
184
|
+
are computed by `scripts/cost-runtime/context-cut-payback.ts`, their
|
|
185
185
|
single source; both cuts and the parent hand-off read the same verdict, and an unmeasurable session is
|
|
186
186
|
always cut. Rationale: `docs/maintainers/pre-gate-cut-rationale.md` → "Why the threshold is a
|
|
187
187
|
break-even". Both cuts end the turn **before** the gate, in the same act that starts the successor, so
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -333,10 +333,21 @@ jobs:
|
|
|
333
333
|
# No ESLint cache here — nothing in this job lints — and no `--maxWorkers`: `gate-plan.ts` leaves
|
|
334
334
|
# any machine below its measured 11 cores uncapped, so vitest sizes its own pool from the runner
|
|
335
335
|
# exactly as it did inside the gate step.
|
|
336
|
+
# **Sharded across runners, because one runner is already saturated** (joshuafolkken/kit#3220).
|
|
337
|
+
# Alone on a 4-core runner vitest takes every core, so the suite can only get faster by spreading
|
|
338
|
+
# its files over more machines. `fail-fast: false` keeps a red shard from cancelling the others,
|
|
339
|
+
# so one run reports every failing file. The `Checks` aggregate below reads `needs.unit.result`,
|
|
340
|
+
# which for a matrix is `success` only when every shard succeeded — no change there is needed.
|
|
341
|
+
# Only kit shards: the distributed template runs the unit suite inside its single `checks` job,
|
|
342
|
+
# where a small consumer suite would pay the duplicated setup and could leave a shard with no file.
|
|
336
343
|
unit:
|
|
337
|
-
name: Unit Tests
|
|
344
|
+
name: Unit Tests (${{ matrix.shard }}/3)
|
|
338
345
|
needs: reuse-pr-checks
|
|
339
346
|
if: ${{ !cancelled() && needs.reuse-pr-checks.outputs.reuse != 'true' }}
|
|
347
|
+
strategy:
|
|
348
|
+
fail-fast: false
|
|
349
|
+
matrix:
|
|
350
|
+
shard: [1, 2, 3]
|
|
340
351
|
runs-on: ubuntu-latest
|
|
341
352
|
timeout-minutes: 8
|
|
342
353
|
permissions:
|
|
@@ -366,9 +377,11 @@ jobs:
|
|
|
366
377
|
# `scripts/ci/ci-yml-unit-job.test.ts` pins the command; the guard itself is
|
|
367
378
|
# `scripts/test/test-unit-guard.ts`.
|
|
368
379
|
- name: Run unit tests
|
|
369
|
-
run: pnpm josh test:unit
|
|
380
|
+
run: pnpm josh test:unit --shard=${{ matrix.shard }}/3
|
|
370
381
|
|
|
382
|
+
# One shard is enough: the check does not depend on which test files ran beside it.
|
|
371
383
|
- name: Verify optional ESLint consumer install
|
|
384
|
+
if: matrix.shard == 1
|
|
372
385
|
run: pnpm exec tsx scripts/package/verify-optional-eslint-install.ts
|
|
373
386
|
|
|
374
387
|
# **The required status check. `Checks` is a name the branch ruleset already requires, and this job
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
load_environment_file,
|
|
10
10
|
notice_refusal_path,
|
|
11
11
|
refusal_path
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-VQLLNFNT.js";
|
|
13
|
+
import "./chunk-I4XSL4TT.js";
|
|
14
|
+
import "./chunk-32GQTL4F.js";
|
|
15
|
+
import "./chunk-S6X6WYKR.js";
|
|
16
16
|
import "./chunk-WPALEIRX.js";
|
|
17
17
|
import "./chunk-RKUAD3I6.js";
|
|
18
18
|
export {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
investigation_reads
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZAL3NRGL.js";
|
|
4
4
|
import {
|
|
5
5
|
lane_guard_policy
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-I4XSL4TT.js";
|
|
7
7
|
import {
|
|
8
8
|
hook_decision
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-32GQTL4F.js";
|
|
10
10
|
import {
|
|
11
11
|
json_value,
|
|
12
12
|
time_spans
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-S6X6WYKR.js";
|
|
14
14
|
|
|
15
15
|
// scripts/delegation/duplicate-read-guard.ts
|
|
16
16
|
import { statSync } from "node:fs";
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
NEEDS_DECISION_LABEL,
|
|
6
6
|
NEEDS_HUMAN_REVIEW_LABEL,
|
|
7
7
|
PORCELAIN_FLAG,
|
|
8
|
-
RECENT_REQUEST_WINDOW,
|
|
9
8
|
agent_role_profile,
|
|
10
9
|
bash_triggers,
|
|
11
10
|
cli_flags,
|
|
@@ -22,7 +21,6 @@ import {
|
|
|
22
21
|
lane_background,
|
|
23
22
|
lane_park,
|
|
24
23
|
lane_registry,
|
|
25
|
-
open_issue_schema,
|
|
26
24
|
own_session,
|
|
27
25
|
parse_json_object_safe,
|
|
28
26
|
read_json_listing,
|
|
@@ -36,30 +34,30 @@ import {
|
|
|
36
34
|
run_tail,
|
|
37
35
|
shell_segments,
|
|
38
36
|
tail_commands
|
|
39
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-GDS5N2KB.js";
|
|
40
38
|
import {
|
|
41
39
|
find_local_bin_upwards
|
|
42
40
|
} from "./chunk-3V37IID6.js";
|
|
43
41
|
import {
|
|
44
42
|
batch_outcome
|
|
45
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-VQLLNFNT.js";
|
|
46
44
|
import {
|
|
47
45
|
investigation_refusal
|
|
48
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-VESKRQOF.js";
|
|
49
47
|
import {
|
|
50
48
|
duplicate_read_outcome
|
|
51
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-DO6NWWHU.js";
|
|
52
50
|
import {
|
|
53
51
|
investigation_reads
|
|
54
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-ZAL3NRGL.js";
|
|
55
53
|
import {
|
|
56
54
|
lane_guard_policy
|
|
57
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-I4XSL4TT.js";
|
|
58
56
|
import {
|
|
59
57
|
hook_decision,
|
|
60
58
|
lane_child_marker,
|
|
61
59
|
run_issue_number
|
|
62
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-32GQTL4F.js";
|
|
63
61
|
import {
|
|
64
62
|
PLATFORM_TEMP_ROOT,
|
|
65
63
|
cost_attribute,
|
|
@@ -69,10 +67,11 @@ import {
|
|
|
69
67
|
file_reader,
|
|
70
68
|
json_value,
|
|
71
69
|
lane_paths,
|
|
70
|
+
open_issue_schema,
|
|
72
71
|
stamp_file,
|
|
73
72
|
time_batch_guard,
|
|
74
73
|
time_shell
|
|
75
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-S6X6WYKR.js";
|
|
76
75
|
|
|
77
76
|
// scripts/rules/direct-filing.ts
|
|
78
77
|
var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>]`, never with `gh api \u2026/issues` or `gh issue create`. The command runs every filing step in order \u2014 the duplicate scout, the body lint and its classification labels, the depth and `route:` labels, the `## Origin` check when filing into another repository, and `epic:bundle` after the create \u2014 so none of them is a step to remember. When the scout prints candidates it holds the filing: read each, then reissue with `--distinct <N,\u2026>` for the ones that are separate deliverables. Reference: `docs/josh-commands-automation.md` \u2192 "`josh issue:file`". **This rule fires on every occurrence, not once per run.**';
|
|
@@ -897,22 +896,15 @@ var cost_corpus = {
|
|
|
897
896
|
var FAILURE_EXIT_CODE = 1;
|
|
898
897
|
var OVER_VERDICT = "over";
|
|
899
898
|
var UNDER_VERDICT = "under";
|
|
900
|
-
function recent_requests(measurement2) {
|
|
901
|
-
return measurement2.billed_input_per_request.slice(-RECENT_REQUEST_WINDOW);
|
|
902
|
-
}
|
|
903
899
|
function per_request_cost(measurement2) {
|
|
904
|
-
|
|
905
|
-
if (window.length === 0) return 0;
|
|
906
|
-
const total = window.reduce((sum, billed) => sum + billed, 0);
|
|
907
|
-
return Math.round(total / window.length);
|
|
900
|
+
return measurement2.billed_input_per_request.at(-1) ?? 0;
|
|
908
901
|
}
|
|
909
902
|
function classify(measurement2, limit) {
|
|
910
903
|
return per_request_cost(measurement2) > limit ? OVER_VERDICT : UNDER_VERDICT;
|
|
911
904
|
}
|
|
912
905
|
function over_summary(measurement2, limit) {
|
|
913
906
|
const total = measurement2.billed_input_per_request.length;
|
|
914
|
-
|
|
915
|
-
return `${String(per_request_cost(measurement2))} billed input tokens per request over the last ${String(window)} of ${String(total)} request(s); limit ${String(limit)}`;
|
|
907
|
+
return `${String(per_request_cost(measurement2))} billed input tokens per request, on the newest of ${String(total)} request(s); limit ${String(limit)}`;
|
|
916
908
|
}
|
|
917
909
|
function report_over(measurement2, limit) {
|
|
918
910
|
if (measurement2 === void 0 || measurement2.billed_input_per_request.length === 0) {
|