@joshuafolkken/kit 1.1379.0 → 1.1387.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-progress.md +2 -3
- package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -4
- package/.claude/skills/workflow-commands/retrospective.md +1 -2
- package/dist/hooks/batch-guard.js +6 -6
- package/dist/hooks/{chunk-RW4XMF47.js → chunk-2YSW3CXH.js} +133 -234
- package/dist/hooks/{chunk-4RWRP3FF.js → chunk-DCY2GWHC.js} +5 -5
- package/dist/hooks/{chunk-DHSKBAQ2.js → chunk-EAQEGME7.js} +1 -1
- package/dist/hooks/{chunk-E7LZL5AN.js → chunk-EBSHN25W.js} +3 -3
- package/dist/hooks/{chunk-HGA4EG5S.js → chunk-GJ7JPIHN.js} +15 -15
- package/dist/hooks/{chunk-TG2AB3W6.js → chunk-GNDJ7NJ7.js} +88 -501
- package/dist/hooks/{chunk-546X4PX3.js → chunk-IYVOLN6A.js} +3 -3
- package/dist/hooks/{chunk-NBEAGPS4.js → chunk-J3KSS7II.js} +1 -1
- package/dist/hooks/{chunk-7ZM464OW.js → chunk-LMWBRJIP.js} +3 -3
- package/dist/hooks/{chunk-TORRSNDJ.js → chunk-SL4GQ2XP.js} +3 -3
- package/dist/hooks/{chunk-PV3FWDSQ.js → chunk-STDSEPWU.js} +2 -2
- package/dist/hooks/{chunk-YSDAH73S.js → chunk-U32VSRNG.js} +420 -4
- package/dist/hooks/{chunk-QARPP36N.js → chunk-WNFJLBXI.js} +3 -3
- package/dist/hooks/codex-hook-adapter.js +13 -13
- package/dist/hooks/duplicate-read-guard.js +7 -7
- package/dist/hooks/format-edited.js +3 -3
- package/dist/hooks/inputs.json +213 -212
- package/dist/hooks/investigation-guard.js +7 -7
- package/dist/hooks/pretool-guard.js +12 -12
- package/dist/hooks/session-lang.js +65 -9
- package/dist/hooks/stop-guard.js +104 -32
- package/dist/josh.js +2 -2
- package/package.json +1 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
- package/scripts/backlog/backlog-budget-cli.ts +2 -20
- package/scripts/backlog/backlog-budget.ts +72 -109
- package/scripts/backlog/backlog-drive-cli.ts +12 -7
- package/scripts/backlog/backlog-drive-launch.ts +2 -0
- package/scripts/backlog/backlog-drive-owner.ts +72 -5
- package/scripts/backlog/backlog-drive.ts +5 -2
- package/scripts/backlog/backlog-offer-cli.ts +1 -15
- package/scripts/backlog/backlogrun-launch.ts +56 -5
- package/scripts/document/document-byte-budget.ts +1 -1
- package/scripts/epic/epic-candidate-confirm.ts +1 -1
- package/scripts/epic/epic-cross-repo.ts +4 -4
- package/scripts/epic/epic-next.ts +1 -1
- package/scripts/hooks/stop-guard.ts +20 -9
- package/scripts/init/start-plan.ts +15 -4
- package/scripts/init/start-steps.ts +31 -3
- package/scripts/init/start.ts +20 -13
- package/scripts/josh/josh-commands-ai.ts +1 -1
- package/scripts/josh/josh-commands-project.ts +1 -1
- package/scripts/lane/lane-cli.ts +1 -3
- package/scripts/run/board/run-board-header.ts +137 -88
- package/scripts/run/board/run-board-labels.ts +18 -17
- package/scripts/run/board/run-board-machine.ts +21 -8
- package/scripts/run/board/run-board-read.ts +9 -2
- package/scripts/run/board/run-board-render.ts +1 -5
- package/scripts/run/board/run-board-setup.ts +73 -0
- package/scripts/run/board/run-board-span.ts +49 -8
- package/scripts/run/board/run-board-status.ts +10 -23
- package/scripts/run/board/run-board-tick.ts +11 -2
- package/scripts/run/carry/run-carry-added.ts +1 -1
- package/scripts/run/carry/run-carry-change.ts +1 -1
- package/scripts/run/carry/run-carry-cli.ts +36 -60
- package/scripts/run/carry/run-carry-ended.ts +10 -2
- package/scripts/run/carry/run-carry.ts +38 -68
- package/scripts/run/cut/run-cut.ts +4 -4
- package/scripts/run/event/run-event-render.ts +1 -1
- package/scripts/run/event/run-event-scope.ts +4 -8
- package/scripts/run/event/run-event-setup.ts +47 -0
- package/scripts/run/event/run-event-stream-emit.ts +0 -25
- package/scripts/run/event/run-event-stream.ts +41 -28
- package/scripts/run/merge/run-merge-collect.ts +1 -1
- package/scripts/run/merge/run-merge-steps.ts +1 -1
- package/scripts/run/progress/run-progress-read.ts +1 -1
- package/scripts/run/run-headless.ts +2 -2
- package/scripts/run/run-status-cli.ts +1 -5
- package/scripts/run/run-step.ts +2 -9
- package/scripts/run/run-stop-notify.ts +1 -1
- package/scripts/run/run-stranded-detect.ts +61 -15
- package/scripts/run/run-stranded.ts +25 -17
- package/scripts/run/wake/run-wake-cli.ts +58 -15
- package/scripts/run/wake/run-wake-describe.ts +5 -5
- package/scripts/run/wake/run-wake-driver.ts +13 -4
- package/scripts/run/wake/run-wake-handoff.ts +1 -1
- package/scripts/run/wake/run-wake-loop.ts +4 -21
- package/scripts/run/wake/run-wake-restart.ts +1 -1
- package/scripts/run/wake/run-wake.ts +6 -7
- package/scripts/backlog/backlog-idle.ts +0 -88
|
@@ -106,12 +106,11 @@ the epic body; what merged the epic's task list.
|
|
|
106
106
|
|
|
107
107
|
| Setting | Value | Meaning |
|
|
108
108
|
| --- | --- | --- |
|
|
109
|
-
| Polling interval | 60 s | **In flight, a floor between two asks, never a clock** — the wake is `lane:await`'s completion or the watcher's arrival exit, never a report. **With nothing in flight no wake comes: it is the parent's own clock.** |
|
|
110
|
-
| `backlogrun` idle-watch poll | 5 min | Not the interval above, and a floor in the same sense. |
|
|
109
|
+
| Polling interval | 60 s | **In flight, a floor between two asks, never a clock** — the wake is `lane:await`'s completion or the watcher's arrival exit, never a report. **With nothing in flight no wake comes: it is the parent's own clock.** A `backlogrun` idle watch is polled at this same interval. |
|
|
111
110
|
| Silent delegated unit | 30 min | Not the child's duration — the time its output has gone **unchanged**. Past it, ask `run:liveness` and book a stopped unit as a failure. |
|
|
112
111
|
| Stale `in-progress` | 90 min | Past it, the other session is gone. |
|
|
113
112
|
| Publish wait | 10 min | `josh propagate`'s own budget. A failed publish never appears. |
|
|
114
|
-
|
|
|
113
|
+
| `backlogrun` idle watch | 8 h | Counted from when the run's hands became free, never from its start; `pnpm josh backlog:budget` decides it. |
|
|
115
114
|
|
|
116
115
|
Each timeout **ends the wait and reports** — none is retried indefinitely. Rationale for the figures:
|
|
117
116
|
`docs/maintainers/backlogrun-progress-rationale.md` → "Why the parent waits on classification, not a
|
|
@@ -29,7 +29,7 @@ provenance of each rule: `docs/maintainers/backlogrun-steps-rationale.md` → "W
|
|
|
29
29
|
| The bound | What it limits | Counted by |
|
|
30
30
|
| --- | --- | --- |
|
|
31
31
|
| `--max` | merges per invocation — a run's own filing competes for it | `run:carry --merged` |
|
|
32
|
-
| `--idle
|
|
32
|
+
| `--idle` (8 hours unless typed) | how long the run waits once nothing can proceed | `--active`, the moment its hands became free |
|
|
33
33
|
| **Ten filings per invocation** | additions to the pool on **every** filing route (`prerequisite.md`) — `route:tier-a`, `route:interrupt` and a review branch-2 filing are exempt from the depth test (`observation-filing.md`), never from this ceiling | `run:carry --filed` |
|
|
34
34
|
| The WIP cap on open issues | the pool across invocations | `prompts/collaboration-workflow/wip-cap.md` |
|
|
35
35
|
|
|
@@ -75,8 +75,6 @@ and `--filed 1`, and **`--cut` is the session's last write**.
|
|
|
75
75
|
| `busy` / `mismatch` / `unreadable` / `unknown` | **Stop; do not open a lane** — report what it printed; never resume into another invocation's record |
|
|
76
76
|
| `over` | **End the conversation**; retype the invocation in a fresh session |
|
|
77
77
|
| `standing` | **Stop; do not open a lane**: report `pnpm josh run:carry --resume "<invocation>" --owner "$PPID"` and `pnpm josh run:carry --end` for the person to choose — a crash from a run-tooling defect this run has since fixed you resume yourself (`upstream-interrupt.md` → "実行中のリポジトリ自身のラン機構の不具合") |
|
|
78
|
-
| `expired` | On standard output: report, stop and `--end` it. On standard error ahead of `began`: a new run replaced it |
|
|
79
|
-
|
|
80
78
|
**End the record when the run ends** — `pnpm josh run:report`, then `pnpm josh run:carry --end`, **never
|
|
81
79
|
batched with it**, and `pnpm josh run:wake --stop` in the same turn. **A run that ends by _stopping_**
|
|
82
80
|
(a `stop` verdict or the consecutive-failure guard) **ends with `pnpm josh run:carry --end --stopped
|
|
@@ -140,7 +138,7 @@ section the row names:
|
|
|
140
138
|
|
|
141
139
|
**A candidate only in another repository is never a token** — report it with its checkout. The budgets,
|
|
142
140
|
verdicts and stops are the driver's own: `docs/maintainers/backlogrun-driver.md` (rationale:
|
|
143
|
-
`docs/maintainers/backlogrun-steps-rationale.md` → "Why the idle watch
|
|
141
|
+
`docs/maintainers/backlogrun-steps-rationale.md` → "Why the idle watch lasts 8 hours from when the hands became free";
|
|
144
142
|
`docs/maintainers/backlogrun-steps-rationale.md` → "Why the cost check skips a watch").
|
|
145
143
|
|
|
146
144
|
Rationale: `docs/maintainers/backlogrun-steps-rationale.md` → "Why the loop's contract is shaped this way"
|
|
@@ -60,8 +60,7 @@ Issue, as after any filing.
|
|
|
60
60
|
`issue:file`'s default applies the label and the next run picks the improvements up without waiting
|
|
61
61
|
for a person. **`backlogrun-steps.md` → "What one invocation approves" is that default's single
|
|
62
62
|
source**; it is written there, beside the brakes that bound it, rather than restated here. Every brake still counts a retrospective's filings: the
|
|
63
|
-
ten-per-invocation ceiling, the WIP cap, `--max
|
|
64
|
-
whole-run bound.
|
|
63
|
+
ten-per-invocation ceiling, the WIP cap, `--max` and the 150,000-token session budget.
|
|
65
64
|
|
|
66
65
|
**Close with `pnpm josh run:carry --retrospective --summary "<result>" --owner "$PPID"`.** It marks the
|
|
67
66
|
retrospective run on the carry record, so `run:step` prints `stop` from then on rather than the step a
|
|
@@ -9,12 +9,12 @@ 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-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-LMWBRJIP.js";
|
|
13
|
+
import "./chunk-EAQEGME7.js";
|
|
14
|
+
import "./chunk-EBSHN25W.js";
|
|
15
|
+
import "./chunk-SL4GQ2XP.js";
|
|
16
|
+
import "./chunk-J3KSS7II.js";
|
|
17
|
+
import "./chunk-2YSW3CXH.js";
|
|
18
18
|
import "./chunk-NEC4AT4Z.js";
|
|
19
19
|
export {
|
|
20
20
|
DISABLED_VALUES,
|
|
@@ -25,134 +25,6 @@ function is_record(value) {
|
|
|
25
25
|
}
|
|
26
26
|
var json_value = { parse_or_undefined, parse_with, is_record };
|
|
27
27
|
|
|
28
|
-
// scripts/backlog/backlog-budget.ts
|
|
29
|
-
var MS_PER_MINUTE = 6e4;
|
|
30
|
-
var MINUTES_PER_HOUR = 60;
|
|
31
|
-
var WHOLE_RUN_BUDGET_HOURS = 8;
|
|
32
|
-
var WHOLE_RUN_BUDGET_MINUTES = WHOLE_RUN_BUDGET_HOURS * MINUTES_PER_HOUR;
|
|
33
|
-
var WHOLE_RUN_BUDGET_MS = WHOLE_RUN_BUDGET_MINUTES * MS_PER_MINUTE;
|
|
34
|
-
var DEFAULT_IDLE_MINUTES = 30;
|
|
35
|
-
var DEFAULT_IDLE_MS = DEFAULT_IDLE_MINUTES * MS_PER_MINUTE;
|
|
36
|
-
var IDLE_POLL_MINUTES = 5;
|
|
37
|
-
var RUN_VERDICT = "run";
|
|
38
|
-
var WATCH_VERDICT = "watch";
|
|
39
|
-
var STOP_VERDICT = "stop";
|
|
40
|
-
var TRIAGE_VERDICT = "triage";
|
|
41
|
-
var ANSWERS = ["blocked", "candidates", "exhausted", "parked", "unreadable", "untriaged"];
|
|
42
|
-
var WHOLE_RUN_REASON = `The whole-run bound of ${String(WHOLE_RUN_BUDGET_HOURS)} hours has passed. An unattended run that has not finished overnight needs a person, not more waiting.`;
|
|
43
|
-
var PARKED_REASON = "Nothing opted in can proceed without a person. Report the parked issues and finish.";
|
|
44
|
-
var UNREADABLE_REASON = "The backlog listing could not be read, so nothing was offered. Report what the command printed and finish \u2014 it is not an empty backlog.";
|
|
45
|
-
var BLOCKED_REASON = "Everything opted in is blocked or already running, so waiting can still change the answer. Poll again at the polling interval.";
|
|
46
|
-
var TRIAGE_REASON = "An opted-in candidate carries neither `run:solo` nor `run:lane`, so nothing starts until it is judged. Read each issue named above, record its order and one of the two labels with a comment, then ask again.";
|
|
47
|
-
var NO_IDLE_WATCH_REASON = "The backlog is empty and the idle watch was turned off with `--idle 0`, so the run finishes here.";
|
|
48
|
-
function to_minutes(duration_ms) {
|
|
49
|
-
return String(Math.ceil(duration_ms / MS_PER_MINUTE));
|
|
50
|
-
}
|
|
51
|
-
function max_reached_reason(merged, max_issues) {
|
|
52
|
-
return `This run's maximum of ${String(max_issues)} is reached, with ${String(merged)} merged. Report what was done, including how many were picked up during an idle watch, and finish.`;
|
|
53
|
-
}
|
|
54
|
-
function draining_reason(running, reason) {
|
|
55
|
-
return `Start nothing more and poll until the running children merge (running: ${String(running)}). Then report and finish \u2014 ${reason}`;
|
|
56
|
-
}
|
|
57
|
-
function idle_expired_reason(idle_budget_ms) {
|
|
58
|
-
return `The backlog stayed empty for the whole ${to_minutes(idle_budget_ms)}-minute idle watch. Report what was done, including how many were picked up during the watch, and finish.`;
|
|
59
|
-
}
|
|
60
|
-
function next_ask_minutes(left_ms) {
|
|
61
|
-
const left_minutes = Number(to_minutes(left_ms));
|
|
62
|
-
return String(Math.min(IDLE_POLL_MINUTES, left_minutes));
|
|
63
|
-
}
|
|
64
|
-
function idle_watch_reason(left_ms) {
|
|
65
|
-
return `The backlog is empty and the idle watch has about ${to_minutes(left_ms)} minutes left. Release the working tree, ask again in ${next_ask_minutes(left_ms)} minutes, and restart the watch the moment a candidate appears.`;
|
|
66
|
-
}
|
|
67
|
-
function running_watch_reason(running, left_ms) {
|
|
68
|
-
return `The backlog is empty and the idle watch has about ${to_minutes(left_ms)} minutes left, with ${String(running)} still running. Keep the working tree until they merge and poll at the polling interval, not the idle poll \u2014 the watch is running down meanwhile.`;
|
|
69
|
-
}
|
|
70
|
-
function watching_reason(input, left_ms) {
|
|
71
|
-
if (input.running === 0) return idle_watch_reason(left_ms);
|
|
72
|
-
return running_watch_reason(input.running, left_ms);
|
|
73
|
-
}
|
|
74
|
-
function taken_by(input) {
|
|
75
|
-
return input.merged + input.running;
|
|
76
|
-
}
|
|
77
|
-
function run_reason(input) {
|
|
78
|
-
const { max_issues } = input;
|
|
79
|
-
if (max_issues === void 0) return "No maximum was given, so start every issue offered.";
|
|
80
|
-
return `Start at most ${String(max_issues - taken_by(input))} more: this run's maximum is ${String(max_issues)}, with ${String(input.merged)} merged and ${String(input.running)} running.`;
|
|
81
|
-
}
|
|
82
|
-
var ANSWER_STOP_REASONS = {
|
|
83
|
-
parked: PARKED_REASON,
|
|
84
|
-
unreadable: UNREADABLE_REASON
|
|
85
|
-
};
|
|
86
|
-
function whole_run_reason(input) {
|
|
87
|
-
if (input.now_ms - input.started_at_ms < WHOLE_RUN_BUDGET_MS) return void 0;
|
|
88
|
-
return WHOLE_RUN_REASON;
|
|
89
|
-
}
|
|
90
|
-
function stop_reason(input) {
|
|
91
|
-
return ANSWER_STOP_REASONS[input.answer] ?? whole_run_reason(input);
|
|
92
|
-
}
|
|
93
|
-
function stopping(input, reason) {
|
|
94
|
-
if (input.running === 0) return { verdict: STOP_VERDICT, reason };
|
|
95
|
-
return { verdict: WATCH_VERDICT, reason: draining_reason(input.running, reason) };
|
|
96
|
-
}
|
|
97
|
-
function max_decision(input) {
|
|
98
|
-
const { max_issues } = input;
|
|
99
|
-
if (max_issues === void 0 || taken_by(input) < max_issues) return void 0;
|
|
100
|
-
return stopping(input, max_reached_reason(input.merged, max_issues));
|
|
101
|
-
}
|
|
102
|
-
function idle_decision(input) {
|
|
103
|
-
const { idle_budget_ms } = input;
|
|
104
|
-
if (idle_budget_ms === void 0) return stopping(input, NO_IDLE_WATCH_REASON);
|
|
105
|
-
const left_ms = idle_budget_ms - (input.now_ms - input.active_at_ms);
|
|
106
|
-
if (left_ms <= 0) return stopping(input, idle_expired_reason(idle_budget_ms));
|
|
107
|
-
return { verdict: WATCH_VERDICT, reason: watching_reason(input, left_ms) };
|
|
108
|
-
}
|
|
109
|
-
function is_finish(input) {
|
|
110
|
-
return stop_reason(input) === void 0 && max_decision(input) === void 0;
|
|
111
|
-
}
|
|
112
|
-
var FIXED_DECISIONS = {
|
|
113
|
-
blocked: { verdict: WATCH_VERDICT, reason: BLOCKED_REASON },
|
|
114
|
-
untriaged: { verdict: TRIAGE_VERDICT, reason: TRIAGE_REASON }
|
|
115
|
-
};
|
|
116
|
-
function answer_decision(input) {
|
|
117
|
-
if (input.answer === "candidates") return { verdict: RUN_VERDICT, reason: run_reason(input) };
|
|
118
|
-
return FIXED_DECISIONS[input.answer] ?? idle_decision(input);
|
|
119
|
-
}
|
|
120
|
-
function decide(input) {
|
|
121
|
-
const reason = stop_reason(input);
|
|
122
|
-
if (reason !== void 0) return stopping(input, reason);
|
|
123
|
-
const capped = max_decision(input);
|
|
124
|
-
if (capped !== void 0) return capped;
|
|
125
|
-
return answer_decision(input);
|
|
126
|
-
}
|
|
127
|
-
var backlog_budget = {
|
|
128
|
-
ANSWERS,
|
|
129
|
-
BLOCKED_REASON,
|
|
130
|
-
DEFAULT_IDLE_MINUTES,
|
|
131
|
-
DEFAULT_IDLE_MS,
|
|
132
|
-
IDLE_POLL_MINUTES,
|
|
133
|
-
MS_PER_MINUTE,
|
|
134
|
-
NO_IDLE_WATCH_REASON,
|
|
135
|
-
PARKED_REASON,
|
|
136
|
-
RUN_VERDICT,
|
|
137
|
-
STOP_VERDICT,
|
|
138
|
-
TRIAGE_REASON,
|
|
139
|
-
TRIAGE_VERDICT,
|
|
140
|
-
UNREADABLE_REASON,
|
|
141
|
-
WATCH_VERDICT,
|
|
142
|
-
WHOLE_RUN_BUDGET_HOURS,
|
|
143
|
-
WHOLE_RUN_BUDGET_MS,
|
|
144
|
-
WHOLE_RUN_REASON,
|
|
145
|
-
decide,
|
|
146
|
-
draining_reason,
|
|
147
|
-
idle_expired_reason,
|
|
148
|
-
idle_watch_reason,
|
|
149
|
-
is_finish,
|
|
150
|
-
max_reached_reason,
|
|
151
|
-
run_reason,
|
|
152
|
-
running_watch_reason,
|
|
153
|
-
taken_by
|
|
154
|
-
};
|
|
155
|
-
|
|
156
28
|
// scripts/git/constants.ts
|
|
157
29
|
import { platform } from "node:os";
|
|
158
30
|
var GIT_COMMAND_UNIX = "/usr/bin/git";
|
|
@@ -952,23 +824,6 @@ var process_identity = {
|
|
|
952
824
|
resolve_own_start
|
|
953
825
|
};
|
|
954
826
|
|
|
955
|
-
// scripts/josh/stamp-record.ts
|
|
956
|
-
var NONE_READ = { kind: "none" };
|
|
957
|
-
var UNREADABLE_READ = { kind: "unreadable" };
|
|
958
|
-
function is_older_than(iso, max_age_ms, now) {
|
|
959
|
-
const at = Date.parse(iso);
|
|
960
|
-
if (Number.isNaN(at)) return true;
|
|
961
|
-
return now.getTime() - at > max_age_ms;
|
|
962
|
-
}
|
|
963
|
-
function classify(raw, spec, now) {
|
|
964
|
-
if (raw === void 0) return NONE_READ;
|
|
965
|
-
const record = spec.parse(raw);
|
|
966
|
-
if (record === void 0) return UNREADABLE_READ;
|
|
967
|
-
const is_expired2 = is_older_than(spec.timestamp_of(record), spec.max_age_ms, now);
|
|
968
|
-
return { kind: is_expired2 ? "expired" : "carried", record };
|
|
969
|
-
}
|
|
970
|
-
var stamp_record = { classify, is_older_than };
|
|
971
|
-
|
|
972
827
|
// scripts/backlog/backlog-budget-cli.ts
|
|
973
828
|
import { fileURLToPath } from "node:url";
|
|
974
829
|
|
|
@@ -1116,55 +971,125 @@ var cli_flags = {
|
|
|
1116
971
|
is_value_unusable
|
|
1117
972
|
};
|
|
1118
973
|
|
|
1119
|
-
// scripts/backlog/backlog-
|
|
1120
|
-
var
|
|
1121
|
-
var
|
|
1122
|
-
var
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
974
|
+
// scripts/backlog/backlog-budget.ts
|
|
975
|
+
var MS_PER_MINUTE = 6e4;
|
|
976
|
+
var MINUTES_PER_HOUR = 60;
|
|
977
|
+
var IDLE_WAIT_HOURS = 8;
|
|
978
|
+
var DEFAULT_IDLE_MINUTES = IDLE_WAIT_HOURS * MINUTES_PER_HOUR;
|
|
979
|
+
var DEFAULT_IDLE_MS = DEFAULT_IDLE_MINUTES * MS_PER_MINUTE;
|
|
980
|
+
var OFFER_INTERVAL_SECONDS = 60;
|
|
981
|
+
var MS_PER_SECOND3 = 1e3;
|
|
982
|
+
var OFFER_INTERVAL_MS = OFFER_INTERVAL_SECONDS * MS_PER_SECOND3;
|
|
983
|
+
var RUN_VERDICT = "run";
|
|
984
|
+
var WATCH_VERDICT = "watch";
|
|
985
|
+
var STOP_VERDICT = "stop";
|
|
986
|
+
var TRIAGE_VERDICT = "triage";
|
|
987
|
+
var ANSWERS = ["blocked", "candidates", "exhausted", "parked", "unreadable", "untriaged"];
|
|
988
|
+
var BLOCKED_REASON = "Everything opted in is blocked or already running, so waiting can still change the answer. Poll again at the polling interval.";
|
|
989
|
+
var TRIAGE_REASON = "An opted-in candidate carries neither `run:solo` nor `run:lane`, so nothing starts until it is judged. Read each issue named above, record its order and one of the two labels with a comment, then ask again.";
|
|
990
|
+
var EMPTY_BACKLOG = "The backlog is empty";
|
|
991
|
+
var WAITING_ON = {
|
|
992
|
+
exhausted: EMPTY_BACKLOG,
|
|
993
|
+
parked: "Nothing opted in can proceed without a person",
|
|
994
|
+
unreadable: "The backlog listing could not be read"
|
|
995
|
+
};
|
|
996
|
+
function waiting_on(answer) {
|
|
997
|
+
return WAITING_ON[answer] ?? EMPTY_BACKLOG;
|
|
998
|
+
}
|
|
999
|
+
function no_idle_watch_reason(answer) {
|
|
1000
|
+
return `${waiting_on(answer)} and the idle watch was turned off with \`--idle 0\`, so the run finishes here.`;
|
|
1001
|
+
}
|
|
1002
|
+
function to_minutes(duration_ms) {
|
|
1003
|
+
return String(Math.ceil(duration_ms / MS_PER_MINUTE));
|
|
1004
|
+
}
|
|
1005
|
+
function max_reached_reason(merged, max_issues) {
|
|
1006
|
+
return `This run's maximum of ${String(max_issues)} is reached, with ${String(merged)} merged. Report what was done, including how many were picked up during an idle watch, and finish.`;
|
|
1007
|
+
}
|
|
1008
|
+
function draining_reason(running, reason) {
|
|
1009
|
+
return `Start nothing more and poll until the running children merge (running: ${String(running)}). Then report and finish \u2014 ${reason}`;
|
|
1134
1010
|
}
|
|
1135
|
-
function
|
|
1136
|
-
return
|
|
1011
|
+
function idle_expired_reason(answer, idle_budget_ms) {
|
|
1012
|
+
return `${waiting_on(answer)}, and stayed so for the whole ${to_minutes(idle_budget_ms)}-minute idle watch. Report what was done, including how many were picked up during the watch, and finish.`;
|
|
1137
1013
|
}
|
|
1138
|
-
function
|
|
1139
|
-
|
|
1140
|
-
return `idle since ${iso_of(since_ms)} until ${iso_of(until_ms)} (${bound}) asked ${iso_of(asked_ms)}`;
|
|
1014
|
+
function idle_watch_reason(answer, left_ms) {
|
|
1015
|
+
return `${waiting_on(answer)} and the idle watch has about ${to_minutes(left_ms)} minutes left. Release the working tree, ask again in ${String(OFFER_INTERVAL_SECONDS)} seconds, and restart the watch the moment a candidate appears.`;
|
|
1141
1016
|
}
|
|
1142
|
-
function
|
|
1143
|
-
return
|
|
1017
|
+
function running_watch_reason(answer, running, left_ms) {
|
|
1018
|
+
return `${waiting_on(answer)} and the idle watch has about ${to_minutes(left_ms)} minutes left, with ${String(running)} still running. Keep the working tree until they merge and poll at the polling interval \u2014 the watch is running down meanwhile.`;
|
|
1144
1019
|
}
|
|
1145
|
-
function
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1020
|
+
function watching_reason(input, left_ms) {
|
|
1021
|
+
if (input.running === 0) return idle_watch_reason(input.answer, left_ms);
|
|
1022
|
+
return running_watch_reason(input.answer, input.running, left_ms);
|
|
1023
|
+
}
|
|
1024
|
+
function taken_by(input) {
|
|
1025
|
+
return input.merged + input.running;
|
|
1026
|
+
}
|
|
1027
|
+
function run_reason(input) {
|
|
1028
|
+
const { max_issues } = input;
|
|
1029
|
+
if (max_issues === void 0) return "No maximum was given, so start every issue offered.";
|
|
1030
|
+
return `Start at most ${String(max_issues - taken_by(input))} more: this run's maximum is ${String(max_issues)}, with ${String(input.merged)} merged and ${String(input.running)} running.`;
|
|
1031
|
+
}
|
|
1032
|
+
function stopping(input, reason) {
|
|
1033
|
+
if (input.running === 0) return { verdict: STOP_VERDICT, reason };
|
|
1034
|
+
return { verdict: WATCH_VERDICT, reason: draining_reason(input.running, reason) };
|
|
1150
1035
|
}
|
|
1151
|
-
function
|
|
1152
|
-
const
|
|
1153
|
-
if (
|
|
1154
|
-
return
|
|
1036
|
+
function max_decision(input) {
|
|
1037
|
+
const { max_issues } = input;
|
|
1038
|
+
if (max_issues === void 0 || taken_by(input) < max_issues) return void 0;
|
|
1039
|
+
return stopping(input, max_reached_reason(input.merged, max_issues));
|
|
1155
1040
|
}
|
|
1156
|
-
function
|
|
1157
|
-
const
|
|
1158
|
-
|
|
1041
|
+
function idle_decision(input) {
|
|
1042
|
+
const { idle_budget_ms } = input;
|
|
1043
|
+
if (idle_budget_ms === void 0) return stopping(input, no_idle_watch_reason(input.answer));
|
|
1044
|
+
const left_ms = idle_budget_ms - (input.now_ms - input.active_at_ms);
|
|
1045
|
+
if (left_ms > 0) return { verdict: WATCH_VERDICT, reason: watching_reason(input, left_ms) };
|
|
1046
|
+
return stopping(input, idle_expired_reason(input.answer, idle_budget_ms));
|
|
1047
|
+
}
|
|
1048
|
+
function is_finish(input) {
|
|
1049
|
+
return input.answer === "exhausted" && max_decision(input) === void 0;
|
|
1159
1050
|
}
|
|
1160
|
-
var
|
|
1051
|
+
var FIXED_DECISIONS = {
|
|
1052
|
+
blocked: { verdict: WATCH_VERDICT, reason: BLOCKED_REASON },
|
|
1053
|
+
untriaged: { verdict: TRIAGE_VERDICT, reason: TRIAGE_REASON }
|
|
1054
|
+
};
|
|
1055
|
+
function answer_decision(input) {
|
|
1056
|
+
if (input.answer === "candidates") return { verdict: RUN_VERDICT, reason: run_reason(input) };
|
|
1057
|
+
return FIXED_DECISIONS[input.answer] ?? idle_decision(input);
|
|
1058
|
+
}
|
|
1059
|
+
function decide(input) {
|
|
1060
|
+
return max_decision(input) ?? answer_decision(input);
|
|
1061
|
+
}
|
|
1062
|
+
var backlog_budget = {
|
|
1063
|
+
ANSWERS,
|
|
1064
|
+
BLOCKED_REASON,
|
|
1065
|
+
DEFAULT_IDLE_MINUTES,
|
|
1066
|
+
DEFAULT_IDLE_MS,
|
|
1067
|
+
IDLE_WAIT_HOURS,
|
|
1068
|
+
MS_PER_MINUTE,
|
|
1069
|
+
OFFER_INTERVAL_MS,
|
|
1070
|
+
RUN_VERDICT,
|
|
1071
|
+
STOP_VERDICT,
|
|
1072
|
+
TRIAGE_REASON,
|
|
1073
|
+
TRIAGE_VERDICT,
|
|
1074
|
+
WAITING_ON,
|
|
1075
|
+
WATCH_VERDICT,
|
|
1076
|
+
decide,
|
|
1077
|
+
draining_reason,
|
|
1078
|
+
idle_expired_reason,
|
|
1079
|
+
idle_watch_reason,
|
|
1080
|
+
is_finish,
|
|
1081
|
+
max_reached_reason,
|
|
1082
|
+
no_idle_watch_reason,
|
|
1083
|
+
run_reason,
|
|
1084
|
+
running_watch_reason,
|
|
1085
|
+
taken_by
|
|
1086
|
+
};
|
|
1161
1087
|
|
|
1162
1088
|
// scripts/backlog/backlog-budget-cli.ts
|
|
1163
1089
|
var ARGV_OFFSET = 2;
|
|
1164
1090
|
var SUCCESS_EXIT_CODE2 = 0;
|
|
1165
1091
|
var FAILURE_EXIT_CODE2 = 1;
|
|
1166
1092
|
var JSON_KEY = "budget";
|
|
1167
|
-
var EXHAUSTED_ANSWER = "exhausted";
|
|
1168
1093
|
var USAGE = `Usage: josh backlog:budget --answer <${backlog_budget.ANSWERS.join("|")}> --started <ISO-8601> [--active <ISO-8601>, required unless the watch is off] [--merged <count>] [--running <count>] [--max <count>] [--idle <minutes>, 0 to turn the watch off] [--json]`;
|
|
1169
1094
|
var OPTIONS = {
|
|
1170
1095
|
active: { type: "string" },
|
|
@@ -1243,18 +1168,10 @@ function build_input(values, now_ms) {
|
|
|
1243
1168
|
if (!are_values_readable(values)) return void 0;
|
|
1244
1169
|
return input_of(values, { answer, now_ms, started_at_ms });
|
|
1245
1170
|
}
|
|
1246
|
-
function idle_of(input, verdict) {
|
|
1247
|
-
const is_idle_watch = verdict === backlog_budget.WATCH_VERDICT && input.answer === EXHAUSTED_ANSWER && backlog_budget.is_finish(input);
|
|
1248
|
-
const window = is_idle_watch ? backlog_idle.window_of(input) : void 0;
|
|
1249
|
-
return window === void 0 ? void 0 : backlog_idle.text_of(window);
|
|
1250
|
-
}
|
|
1251
1171
|
function print_json(input, decision) {
|
|
1252
1172
|
const { verdict, reason } = decision;
|
|
1253
|
-
const idle = idle_of(input, verdict);
|
|
1254
1173
|
const is_finish2 = backlog_budget.is_finish(input);
|
|
1255
|
-
console.info(
|
|
1256
|
-
JSON.stringify({ [JSON_KEY]: verdict, reason, is_finish: is_finish2, ...idle !== void 0 && { idle } })
|
|
1257
|
-
);
|
|
1174
|
+
console.info(JSON.stringify({ [JSON_KEY]: verdict, reason, is_finish: is_finish2 }));
|
|
1258
1175
|
}
|
|
1259
1176
|
function refuse() {
|
|
1260
1177
|
console.error(USAGE);
|
|
@@ -1363,7 +1280,7 @@ function argument_tokens(invocation) {
|
|
|
1363
1280
|
tokens: true
|
|
1364
1281
|
})?.tokens;
|
|
1365
1282
|
}
|
|
1366
|
-
function
|
|
1283
|
+
function parse(invocation) {
|
|
1367
1284
|
const tokens = argument_tokens(invocation);
|
|
1368
1285
|
if (tokens === void 0) return void 0;
|
|
1369
1286
|
const stop = tokens.findIndex((token) => token.kind !== "positional");
|
|
@@ -1380,7 +1297,7 @@ function joined(command, rendered) {
|
|
|
1380
1297
|
return [command, ...rendered].join(TOKEN_SEPARATOR);
|
|
1381
1298
|
}
|
|
1382
1299
|
function rebuild(invocation) {
|
|
1383
|
-
const parsed =
|
|
1300
|
+
const parsed = parse(invocation);
|
|
1384
1301
|
if (parsed === void 0) return void 0;
|
|
1385
1302
|
return joined(BACKLOG_COMMAND, [
|
|
1386
1303
|
...parsed.issues.map((issue) => issue_token(issue)),
|
|
@@ -1391,12 +1308,12 @@ function issue_numbers(invocation) {
|
|
|
1391
1308
|
const tokens = tokens_of(invocation);
|
|
1392
1309
|
const stop = tokens.findIndex((token) => token.startsWith(FLAG_PREFIX));
|
|
1393
1310
|
const leading = stop === NOT_FOUND ? tokens : tokens.slice(FIRST_TOKEN, stop);
|
|
1394
|
-
const issues =
|
|
1311
|
+
const issues = parse(leading.join(TOKEN_SEPARATOR))?.issues;
|
|
1395
1312
|
if (issues === void 0 || issues.length === EMPTY_LENGTH) return void 0;
|
|
1396
1313
|
return issues;
|
|
1397
1314
|
}
|
|
1398
1315
|
function has_only(invocation) {
|
|
1399
|
-
return
|
|
1316
|
+
return parse(invocation)?.flags.includes(ONLY_FLAG) === true;
|
|
1400
1317
|
}
|
|
1401
1318
|
var run_invocation = {
|
|
1402
1319
|
has_only,
|
|
@@ -1424,7 +1341,7 @@ function next_added(carry, additions) {
|
|
|
1424
1341
|
}
|
|
1425
1342
|
function add_issues(target, carry, additions) {
|
|
1426
1343
|
const next = { ...carry, added: next_added(carry, additions) };
|
|
1427
|
-
stamp_file.
|
|
1344
|
+
stamp_file.replace_stamp(target, next);
|
|
1428
1345
|
return next;
|
|
1429
1346
|
}
|
|
1430
1347
|
var run_carry_added = { add_issues, ordered };
|
|
@@ -1517,7 +1434,7 @@ function apply_change(target, carry, change, now = /* @__PURE__ */ new Date()) {
|
|
|
1517
1434
|
done: next_done(carry, effective.done),
|
|
1518
1435
|
retrospective: effective.retrospective === true || carry.retrospective
|
|
1519
1436
|
};
|
|
1520
|
-
stamp_file.
|
|
1437
|
+
stamp_file.replace_stamp(target, next);
|
|
1521
1438
|
return next;
|
|
1522
1439
|
}
|
|
1523
1440
|
var run_carry_change = { apply_change };
|
|
@@ -1695,7 +1612,7 @@ var ASSISTANT_TYPE = "assistant";
|
|
|
1695
1612
|
function is_priced_line(data) {
|
|
1696
1613
|
return data.type === ASSISTANT_TYPE && data.message?.model !== SYNTHETIC_MODEL;
|
|
1697
1614
|
}
|
|
1698
|
-
function
|
|
1615
|
+
function classify(data) {
|
|
1699
1616
|
if (!is_priced_line(data)) return { kind: "skipped" };
|
|
1700
1617
|
const usage = data.message?.usage;
|
|
1701
1618
|
return usage ? { kind: "record", record: to_record(data, usage) } : { kind: "no_usage" };
|
|
@@ -1703,7 +1620,7 @@ function classify2(data) {
|
|
|
1703
1620
|
function parse_line(line) {
|
|
1704
1621
|
if (line.trim() === "") return { kind: "skipped" };
|
|
1705
1622
|
const parsed = LINE_SCHEMA.safeParse(json_value.parse_or_undefined(line));
|
|
1706
|
-
return parsed.success ?
|
|
1623
|
+
return parsed.success ? classify(parsed.data) : { kind: "malformed" };
|
|
1707
1624
|
}
|
|
1708
1625
|
function later_instant(left, right) {
|
|
1709
1626
|
if (left === void 0) return right;
|
|
@@ -2108,8 +2025,6 @@ var run_carry_conversation = {
|
|
|
2108
2025
|
// scripts/run/carry/run-carry.ts
|
|
2109
2026
|
var CARRY_PREFIX = "josh-run-carry-";
|
|
2110
2027
|
var REPOSITORY_DIRECTORY_INDEX = 1;
|
|
2111
|
-
var CARRY_MAX_AGE_HOURS = backlog_budget.WHOLE_RUN_BUDGET_HOURS;
|
|
2112
|
-
var CARRY_MAX_AGE_MS = backlog_budget.WHOLE_RUN_BUDGET_MS;
|
|
2113
2028
|
var NO_INCREMENT3 = 0;
|
|
2114
2029
|
var MAX_CUTS = 6;
|
|
2115
2030
|
var END_COMMAND = "pnpm josh run:carry --end";
|
|
@@ -2150,24 +2065,16 @@ async function repository_directory() {
|
|
|
2150
2065
|
function parse_carry(raw) {
|
|
2151
2066
|
return json_value.parse_with(raw, run_carry_schema);
|
|
2152
2067
|
}
|
|
2153
|
-
function
|
|
2154
|
-
return
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
};
|
|
2161
|
-
function is_expired(carry, now) {
|
|
2162
|
-
return stamp_record.is_older_than(started_at_of(carry), CARRY_MAX_AGE_MS, now);
|
|
2163
|
-
}
|
|
2164
|
-
function classify3(raw, now) {
|
|
2165
|
-
const read3 = stamp_record.classify(raw, CARRY_SPEC, now);
|
|
2166
|
-
if (!("record" in read3)) return read3;
|
|
2167
|
-
return { kind: read3.kind, carry: read3.record };
|
|
2068
|
+
function classify2(raw) {
|
|
2069
|
+
if (raw === void 0) return { kind: "none" };
|
|
2070
|
+
const carry = parse_carry(raw);
|
|
2071
|
+
if (carry === void 0 || Number.isNaN(Date.parse(carry.started_at))) {
|
|
2072
|
+
return { kind: "unreadable" };
|
|
2073
|
+
}
|
|
2074
|
+
return { kind: "carried", carry };
|
|
2168
2075
|
}
|
|
2169
|
-
function read_carry(target
|
|
2170
|
-
return
|
|
2076
|
+
function read_carry(target) {
|
|
2077
|
+
return classify2(stamp_file.read_stamp_text(target));
|
|
2171
2078
|
}
|
|
2172
2079
|
function owner_of(pid, read3 = process_identity.read_start, transcript = run_carry_conversation.own_transcript()) {
|
|
2173
2080
|
return { pid, start: read3(pid), transcript };
|
|
@@ -2190,10 +2097,6 @@ function begin_carry(target, invocation, owner = NO_OWNER, now = /* @__PURE__ */
|
|
|
2190
2097
|
const carry = fresh_carry(invocation, owner, now);
|
|
2191
2098
|
return stamp_file.create_stamp(target, carry) ? carry : void 0;
|
|
2192
2099
|
}
|
|
2193
|
-
function replace_carry(target, invocation, owner = NO_OWNER, now = /* @__PURE__ */ new Date()) {
|
|
2194
|
-
stamp_file.remove_stamp(target);
|
|
2195
|
-
return begin_carry(target, invocation, owner, now);
|
|
2196
|
-
}
|
|
2197
2100
|
function adopt_carry(target, carry, owner = NO_OWNER) {
|
|
2198
2101
|
const next = {
|
|
2199
2102
|
...carry,
|
|
@@ -2216,6 +2119,11 @@ function is_owned_by(carry, owner) {
|
|
|
2216
2119
|
function is_foreign_live_owner(carry, owner) {
|
|
2217
2120
|
return is_owner_live(carry) && !is_owned_by(carry, owner);
|
|
2218
2121
|
}
|
|
2122
|
+
function is_held_by_another(carry, is_live = is_owner_live) {
|
|
2123
|
+
const caller = owner_of(process.pid);
|
|
2124
|
+
const is_own = carry.owner_pid === caller.pid && carry.owner_start === caller.start;
|
|
2125
|
+
return !is_own && is_live(carry);
|
|
2126
|
+
}
|
|
2219
2127
|
function is_handed_off_to(carry, invocation) {
|
|
2220
2128
|
return carry.is_handed_off === true && carry.invocation === invocation;
|
|
2221
2129
|
}
|
|
@@ -2235,8 +2143,7 @@ function end_carry(target) {
|
|
|
2235
2143
|
stamp_file.remove_stamp(target);
|
|
2236
2144
|
}
|
|
2237
2145
|
function retrospective_done_of(read3) {
|
|
2238
|
-
|
|
2239
|
-
return read3.carry.retrospective === true;
|
|
2146
|
+
return read3.kind === "carried" && read3.carry.retrospective === true;
|
|
2240
2147
|
}
|
|
2241
2148
|
function remaining_of(carry) {
|
|
2242
2149
|
if (carry === void 0) return void 0;
|
|
@@ -2252,9 +2159,6 @@ function done_note(carry) {
|
|
|
2252
2159
|
function describe_carry(carry) {
|
|
2253
2160
|
return `${carry.invocation} started ${carry.started_at}; ${String(carry.merged)} merged, ${String(carry.filed)} filed, ${String(carry.failures)} failed in a row, ${String(carry.outages)} outage(s) in a row, ${String(carry.cuts)} cut(s) crossed${done_note(carry)}`;
|
|
2254
2161
|
}
|
|
2255
|
-
function expired_message(carry) {
|
|
2256
|
-
return `The ${String(CARRY_MAX_AGE_HOURS)}-hour whole-run bound is spent: ${describe_carry(carry)}. Clear it with \`${END_COMMAND}\`.`;
|
|
2257
|
-
}
|
|
2258
2162
|
function mismatch_message(carry, invocation) {
|
|
2259
2163
|
return `A different invocation is carried here \u2014 ${describe_carry(carry)}. This one is \`${invocation}\`. End the standing record with \`${END_COMMAND}\` once you know its run is over, then begin again.`;
|
|
2260
2164
|
}
|
|
@@ -2286,8 +2190,6 @@ function unknown_message() {
|
|
|
2286
2190
|
return "This repository\u2019s git directory could not be read, so no run record was established.";
|
|
2287
2191
|
}
|
|
2288
2192
|
var run_carry = {
|
|
2289
|
-
CARRY_MAX_AGE_HOURS,
|
|
2290
|
-
CARRY_MAX_AGE_MS,
|
|
2291
2193
|
END_COMMAND,
|
|
2292
2194
|
MAX_CUTS,
|
|
2293
2195
|
NO_OWNER,
|
|
@@ -2298,18 +2200,17 @@ var run_carry = {
|
|
|
2298
2200
|
busy_message,
|
|
2299
2201
|
carry_path,
|
|
2300
2202
|
claim_command,
|
|
2301
|
-
classify:
|
|
2203
|
+
classify: classify2,
|
|
2302
2204
|
classify_claim,
|
|
2303
2205
|
count_refused_message,
|
|
2304
2206
|
is_at_cut_cap,
|
|
2305
2207
|
describe_carry,
|
|
2306
2208
|
end_carry,
|
|
2307
|
-
expired_message,
|
|
2308
2209
|
mismatch_message,
|
|
2309
2210
|
fresh_carry,
|
|
2310
2211
|
is_count_refused,
|
|
2311
|
-
is_expired,
|
|
2312
2212
|
is_foreign_live_owner,
|
|
2213
|
+
is_held_by_another,
|
|
2313
2214
|
is_owner_live,
|
|
2314
2215
|
lost_message,
|
|
2315
2216
|
nothing_to_resume_message,
|
|
@@ -2317,7 +2218,6 @@ var run_carry = {
|
|
|
2317
2218
|
parse_carry,
|
|
2318
2219
|
read_carry,
|
|
2319
2220
|
remaining_of,
|
|
2320
|
-
replace_carry,
|
|
2321
2221
|
repository_directory,
|
|
2322
2222
|
retrospective_done_of,
|
|
2323
2223
|
standing_message,
|
|
@@ -2421,7 +2321,6 @@ export {
|
|
|
2421
2321
|
ports,
|
|
2422
2322
|
process_identity,
|
|
2423
2323
|
process_owner_schema,
|
|
2424
|
-
backlog_budget,
|
|
2425
2324
|
PORCELAIN_FLAG,
|
|
2426
2325
|
git_utilities,
|
|
2427
2326
|
has_timed_out,
|
|
@@ -2430,8 +2329,8 @@ export {
|
|
|
2430
2329
|
git_location_environment,
|
|
2431
2330
|
git_spawn_sync,
|
|
2432
2331
|
git_command,
|
|
2433
|
-
stamp_record,
|
|
2434
2332
|
cli_flags,
|
|
2333
|
+
backlog_budget,
|
|
2435
2334
|
issue_number_shape,
|
|
2436
2335
|
run_invocation,
|
|
2437
2336
|
lane_paths,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
investigation_reads
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WNFJLBXI.js";
|
|
4
4
|
import {
|
|
5
5
|
lane_guard_policy
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EAQEGME7.js";
|
|
7
7
|
import {
|
|
8
8
|
hook_decision
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-EBSHN25W.js";
|
|
10
10
|
import {
|
|
11
11
|
time_spans
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SL4GQ2XP.js";
|
|
13
13
|
import {
|
|
14
14
|
json_value
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2YSW3CXH.js";
|
|
16
16
|
|
|
17
17
|
// scripts/delegation/duplicate-read-guard.ts
|
|
18
18
|
import { statSync } from "node:fs";
|