@joshuafolkken/kit 1.1453.0 → 1.1471.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/dependency-update/SKILL.md +26 -55
- package/.claude/skills/epic-commands/SKILL.md +87 -148
- package/.claude/skills/epic-commands/epic-bundle.md +45 -77
- package/.claude/skills/epic-commands/execution-waves.md +44 -81
- package/.claude/skills/verify-ui/SKILL.md +25 -50
- package/.claude/skills/workflow-commands/background-commands.md +36 -47
- package/.claude/skills/workflow-commands/backlogrun-child.md +72 -85
- package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +91 -121
- package/.claude/skills/workflow-commands/backlogrun-park.md +73 -117
- package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -9
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +11 -20
- package/.claude/skills/workflow-commands/backlogrun-steps.md +43 -52
- package/.claude/skills/workflow-commands/chain-rule.md +24 -34
- package/.claude/skills/workflow-commands/followup.md +57 -76
- package/.claude/skills/workflow-commands/halfrun.md +2 -1
- package/.claude/skills/workflow-commands/issue-comments.md +43 -60
- package/.claude/skills/workflow-commands/kickoff.md +65 -74
- package/.claude/skills/workflow-commands/observation-filing.md +62 -107
- package/.claude/skills/workflow-commands/observation-ledger.md +56 -111
- package/.claude/skills/workflow-commands/pre-gate-cut.md +89 -138
- package/.claude/skills/workflow-commands/prerequisite.md +10 -15
- package/.claude/skills/workflow-commands/progress-watcher.md +21 -26
- package/.claude/skills/workflow-commands/prrun.md +2 -1
- package/.claude/skills/workflow-commands/retrospective.md +31 -50
- package/.claude/skills/workflow-commands/split-assessment.md +34 -58
- package/.claude/skills/workflow-commands/working-tree-hold.md +54 -71
- package/CLAUDE.md +7 -6
- package/README.md +2 -9
- package/dist/CLAUDE.md +7 -6
- package/dist/hooks/batch-guard.js +6 -6
- package/dist/hooks/{chunk-Y3GKIKGW.js → chunk-43ZHT22P.js} +31 -15
- package/dist/hooks/{chunk-MBJYQPEK.js → chunk-AS74OU3D.js} +24 -8
- package/dist/hooks/{chunk-3C4XRYG6.js → chunk-E7OIKX5Z.js} +17 -12
- package/dist/hooks/{chunk-Z4XI7CZS.js → chunk-EUMACUK2.js} +18 -12
- package/dist/hooks/{chunk-NO4AALP5.js → chunk-H5HVWYXK.js} +4 -4
- package/dist/hooks/{chunk-5C7L6FRC.js → chunk-IIGFYXKC.js} +346 -241
- package/dist/hooks/{chunk-W5ZKGTSY.js → chunk-J47HU5H5.js} +14 -3
- package/dist/hooks/{chunk-OLMO72ON.js → chunk-K4EOONYM.js} +1 -1
- package/dist/hooks/{chunk-LBFYEOXJ.js → chunk-K4LMBQC2.js} +4 -4
- package/dist/hooks/{chunk-D3NJXN5M.js → chunk-KC5AK2GF.js} +8 -6
- package/dist/hooks/chunk-SHGPANFB.js +56 -0
- package/dist/hooks/{chunk-EF5GQ6WS.js → chunk-YHBZAJSV.js} +3 -3
- package/dist/hooks/{chunk-SHYUQOIS.js → chunk-YYPI7SJZ.js} +5 -5
- 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 +251 -247
- package/dist/hooks/investigation-guard.js +7 -7
- package/dist/hooks/pretool-guard.js +12 -12
- package/dist/hooks/session-lang.js +6 -5
- package/dist/hooks/stop-guard.js +75 -18
- package/dist/josh.js +6 -7
- package/dist/managed-marker/index.js +1 -2
- package/dist/version/index.js +15 -12
- package/eslint/base.js +2 -1
- package/eslint/rules/unicorn.js +16 -0
- package/package.json +3 -3
- package/prompts/coding-standards.md +12 -22
- package/prompts/collaboration-workflow/file-edits.md +26 -44
- package/prompts/collaboration-workflow/gh-rest.md +20 -36
- package/prompts/collaboration-workflow/glossary.md +5 -7
- package/prompts/collaboration-workflow/issue-citation.md +7 -13
- package/prompts/collaboration-workflow/issue-template.md +29 -29
- package/prompts/collaboration-workflow/operating-rules.md +35 -44
- package/prompts/collaboration-workflow/output-bounds.md +15 -15
- package/prompts/collaboration-workflow/overview.md +14 -19
- package/prompts/collaboration-workflow/plan-comment.md +13 -13
- package/prompts/collaboration-workflow/principles.md +50 -53
- package/prompts/collaboration-workflow/proposal-request.md +1 -9
- package/prompts/collaboration-workflow/report-format.md +32 -49
- package/prompts/collaboration-workflow/residency.md +10 -10
- package/prompts/collaboration-workflow/rule-delivery.md +9 -9
- package/prompts/collaboration-workflow/shell-body.md +11 -21
- package/prompts/collaboration-workflow/turn-batching.md +8 -14
- package/prompts/collaboration-workflow/upstream-interrupt.md +26 -34
- package/prompts/collaboration-workflow/wip-cap.md +24 -30
- package/prompts/collaboration-workflow.md +24 -25
- package/prompts/refactoring.md +33 -43
- package/prompts/review-rubric.md +84 -129
- package/prompts/review.md +111 -141
- package/prompts/sonar-hotspot-handling.md +22 -50
- package/prompts/testing-guide.md +48 -99
- package/scripts/adopt/adopt-toolkits.ts +2 -4
- package/scripts/agent/agent-exit-record.ts +23 -1
- package/scripts/agent/codex-agent-argv.ts +7 -2
- package/scripts/backlog/backlog-budget-cli.ts +1 -2
- package/scripts/backlog/backlog-drive-carried.ts +26 -0
- package/scripts/backlog/backlog-drive-cli.ts +10 -5
- package/scripts/backlog/backlog-drive-named.ts +2 -4
- package/scripts/backlog/backlog-drive-restore.ts +19 -1
- package/scripts/backlog/backlog-drive-seats.ts +27 -0
- package/scripts/backlog/backlog-drive.ts +11 -6
- package/scripts/backlog/backlog-ready.ts +13 -6
- package/scripts/behavior/behavior-rules.ts +3 -2
- package/scripts/cost-runtime/codex-usage.ts +4 -2
- package/scripts/cost-runtime/cost-cli.ts +1 -2
- package/scripts/delegation/investigation-guard.ts +1 -1
- package/scripts/delegation/investigation-reads.ts +1 -1
- package/scripts/discovery/repo-discovery.ts +4 -2
- package/scripts/discovery/repo-origin.ts +2 -4
- package/scripts/doctor/doctor-logic.ts +6 -3
- package/scripts/document/document-byte-budget.ts +27 -27
- package/scripts/document/document-byte-check.ts +1 -2
- package/scripts/document/entry-read-budget.ts +2 -2
- package/scripts/epic/epic-audit-rationale.ts +8 -2
- package/scripts/epic/epic-bundle-cli.ts +1 -2
- package/scripts/epic/epic-chains.ts +6 -2
- package/scripts/epic/epic-close-comment.ts +1 -2
- package/scripts/gate/verification-gate.ts +7 -2
- package/scripts/gh/git-pr-ai-review.ts +12 -1
- package/scripts/gh/git-pr-confirmation.ts +11 -7
- package/scripts/gh/git-pr.ts +6 -2
- package/scripts/git/git-common-directory.ts +3 -3
- package/scripts/git/git-diff-reads.ts +16 -9
- package/scripts/git/git-execa-error.ts +1 -2
- package/scripts/hooks/format-edited-file.ts +10 -4
- package/scripts/hooks/pre-push-unit.ts +15 -4
- package/scripts/hooks/pretool-guard.ts +23 -29
- package/scripts/hooks/step-zero-notice.ts +3 -2
- package/scripts/init/hook-command-rewrite.ts +6 -2
- package/scripts/init/init-logic-deploy-vps.ts +4 -2
- package/scripts/issue/behavior-change-lint.ts +12 -6
- package/scripts/issue/issue-scout-cli.ts +3 -2
- package/scripts/josh/file-map-stamp.ts +1 -3
- package/scripts/josh/hook-decision.ts +17 -2
- package/scripts/josh/josh-commands-workflow.ts +1 -1
- package/scripts/lane/lane-await.ts +3 -2
- package/scripts/lane/lane-child-invocation.ts +14 -1
- package/scripts/lane/lane-guard-policy.ts +4 -4
- package/scripts/lane/lane-ledger.ts +9 -0
- package/scripts/lane/lane-load.ts +9 -2
- package/scripts/lane/lane-measure-cli.ts +2 -0
- package/scripts/lane/lane-parked.ts +18 -0
- package/scripts/lane/lane-process-load.ts +125 -0
- package/scripts/lane/lane-process-stats.ts +93 -0
- package/scripts/lane/lane-registry.ts +8 -3
- package/scripts/lane/lane-session-broker.ts +29 -5
- package/scripts/lane/lane-spent.ts +14 -3
- package/scripts/lane/lane-stats.ts +1 -0
- package/scripts/managed-marker/managed-marker-logic.ts +1 -2
- package/scripts/notify/confirmation-options.ts +59 -0
- package/scripts/notify/notify-opt-in.ts +33 -0
- package/scripts/notify/telegram-notify.ts +25 -8
- package/scripts/notify/telegram-test-logic.ts +33 -1
- package/scripts/notify/telegram-test.ts +4 -2
- package/scripts/overrides/lockfile-overrides.ts +1 -3
- package/scripts/propagate/propagate.ts +1 -2
- package/scripts/release/release-progress.ts +3 -2
- package/scripts/report/report-lint.ts +7 -4
- package/scripts/review/review-record-cli.ts +6 -2
- package/scripts/rules/destructive-command.ts +6 -9
- package/scripts/rules/direct-filing.ts +3 -7
- package/scripts/rules/early-heartbeat.ts +7 -18
- package/scripts/rules/file-body.ts +6 -13
- package/scripts/rules/filing-cap.ts +3 -6
- package/scripts/rules/git-force.ts +5 -9
- package/scripts/rules/implementation-cut.ts +37 -35
- package/scripts/rules/index-guard.ts +4 -7
- package/scripts/rules/issue-comments.ts +5 -15
- package/scripts/rules/josh-git-bare.ts +3 -6
- package/scripts/rules/lane-background.ts +10 -21
- package/scripts/rules/lane-carry-conflict.ts +7 -17
- package/scripts/rules/lane-interactive-ask.ts +6 -11
- package/scripts/rules/lane-park.ts +5 -13
- package/scripts/rules/lane-split-park.ts +2 -7
- package/scripts/rules/lane-switch-main.ts +9 -12
- package/scripts/rules/oracle-consulted.ts +4 -5
- package/scripts/rules/piped-verification.ts +81 -31
- package/scripts/rules/poll-loop.ts +7 -17
- package/scripts/rules/pre-gate-cut.ts +7 -21
- package/scripts/rules/prior-comment-read.ts +7 -5
- package/scripts/rules/protected-files.ts +5 -9
- package/scripts/rules/raw-field-body.ts +3 -7
- package/scripts/rules/rule-body-guard.ts +4 -11
- package/scripts/rules/run-tail-rule.ts +6 -22
- package/scripts/rules/shell-body-trigger.ts +7 -8
- package/scripts/rules/shell-segments.ts +7 -0
- package/scripts/rules/stop-rules.ts +17 -29
- package/scripts/rules/test-declared-commit.ts +4 -10
- package/scripts/rules/third-party-write.ts +5 -10
- package/scripts/rules/worktree-guard.ts +5 -12
- package/scripts/run/board/run-board-github.ts +11 -3
- package/scripts/run/board/run-board-idle.ts +31 -0
- package/scripts/run/board/run-board-read.ts +9 -12
- package/scripts/run/board/run-board-reason.ts +7 -3
- package/scripts/run/board/run-board-state.ts +4 -0
- package/scripts/run/board/run-board-status.ts +18 -3
- package/scripts/run/board/run-board-thanks.ts +7 -2
- package/scripts/run/board/run-board-tick.ts +32 -7
- package/scripts/run/carry/run-carry-args.ts +1 -3
- package/scripts/run/carry/run-carry-conversation.ts +7 -2
- package/scripts/run/cut/run-cut-cli.ts +15 -20
- package/scripts/run/cut/run-cut-decline.ts +72 -0
- package/scripts/run/cut/run-cut-ready.ts +74 -0
- package/scripts/run/cut/run-cut-report.ts +13 -0
- package/scripts/run/cut/run-cut.ts +10 -1
- package/scripts/run/entry/run-entry-stop.ts +6 -3
- package/scripts/run/hold/run-hold-cli.ts +14 -3
- package/scripts/run/hold/run-hold.ts +6 -3
- package/scripts/run/merge/run-merge-cli.ts +30 -7
- package/scripts/run/merge/run-merge-ship.ts +59 -1
- package/scripts/run/merge/run-merge.ts +3 -2
- package/scripts/run/run-ending.ts +31 -3
- package/scripts/run/run-parent-cut-hook.ts +5 -10
- package/scripts/run/run-preflight.ts +1 -2
- package/scripts/run/run-stop-notify.ts +3 -2
- package/scripts/run/run-watcher-guard.ts +6 -3
- package/scripts/run/ship/run-ship-review-steps.ts +13 -4
- package/scripts/run/ship/run-ship-review.ts +15 -2
- package/scripts/run/tidy/run-tidy-cli.ts +3 -3
- package/scripts/run/tidy/run-tidy-lanes.ts +3 -2
- package/scripts/safe-chain/project-config.ts +7 -2
- package/scripts/sync/sync-hook-safety.ts +8 -2
- package/scripts/test/unit-worker-share.ts +3 -2
- package/scripts/time-runtime/time-batch-guard.ts +3 -3
- package/scripts/time-runtime/time-hook-transcript.ts +3 -2
- package/scripts/time-runtime/time-shell.ts +10 -0
- package/scripts/version/effective-upstream.ts +3 -4
- package/scripts/version/kit-version-config.ts +8 -2
- package/scripts/version/latest-corepack.ts +1 -2
- package/scripts/version/release-hold.ts +11 -4
- package/scripts/version/version-commands.ts +12 -4
- package/dist/hooks/chunk-UT7YC3N2.js +0 -56
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
duplicate_read_outcome
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YYPI7SJZ.js";
|
|
4
4
|
import {
|
|
5
5
|
ALREADY_DONE_LABEL,
|
|
6
6
|
CONTEXT_CUT_THRESHOLD,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
session_cite,
|
|
30
30
|
shell_segments,
|
|
31
31
|
tail_commands
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-43ZHT22P.js";
|
|
33
33
|
import {
|
|
34
34
|
ancestor_directories,
|
|
35
35
|
find_local_bin_upwards,
|
|
@@ -50,25 +50,25 @@ import {
|
|
|
50
50
|
run_event_stream_emit,
|
|
51
51
|
run_headless,
|
|
52
52
|
session_language
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-EUMACUK2.js";
|
|
54
54
|
import {
|
|
55
55
|
error_text
|
|
56
56
|
} from "./chunk-CDY4NFQG.js";
|
|
57
57
|
import {
|
|
58
58
|
batch_outcome
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-YHBZAJSV.js";
|
|
60
60
|
import {
|
|
61
|
-
|
|
62
|
-
} from "./chunk-
|
|
61
|
+
investigation_outcome
|
|
62
|
+
} from "./chunk-K4LMBQC2.js";
|
|
63
63
|
import {
|
|
64
64
|
investigation_reads
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-H5HVWYXK.js";
|
|
66
66
|
import {
|
|
67
67
|
lane_guard_policy
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-SHGPANFB.js";
|
|
69
69
|
import {
|
|
70
70
|
hook_decision
|
|
71
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-J47HU5H5.js";
|
|
72
72
|
import {
|
|
73
73
|
cost_attribute,
|
|
74
74
|
cost_blocks,
|
|
@@ -76,25 +76,27 @@ import {
|
|
|
76
76
|
time_batch_guard,
|
|
77
77
|
time_density_hook,
|
|
78
78
|
time_shell
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-AS74OU3D.js";
|
|
80
80
|
import {
|
|
81
81
|
lane_child_marker
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-K4EOONYM.js";
|
|
83
83
|
import {
|
|
84
84
|
GIT_LOCATION_VARIABLES,
|
|
85
85
|
PORCELAIN_FLAG,
|
|
86
|
+
UNTRACKED_FILES_FLAG,
|
|
86
87
|
cli_flags,
|
|
87
88
|
cost_transcript,
|
|
88
89
|
cost_usage,
|
|
89
90
|
file_reader,
|
|
90
91
|
git_command,
|
|
92
|
+
git_diff_reads,
|
|
91
93
|
git_spawn_sync,
|
|
92
94
|
issue_number_shape,
|
|
93
95
|
json_value,
|
|
94
96
|
lane_paths,
|
|
95
97
|
own_session,
|
|
96
98
|
run_carry
|
|
97
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-E7OIKX5Z.js";
|
|
98
100
|
import {
|
|
99
101
|
PLATFORM_TEMP_ROOT,
|
|
100
102
|
PROBE_TIMEOUT_MS,
|
|
@@ -162,9 +164,9 @@ function read_record(root) {
|
|
|
162
164
|
const raw = stamp_file.read_stamp_text(record_path(root));
|
|
163
165
|
return raw === void 0 ? void 0 : json_value.parse_with(raw, record_schema);
|
|
164
166
|
}
|
|
165
|
-
function write_record(
|
|
166
|
-
stamp_file.replace_stamp(record_path(root),
|
|
167
|
-
return
|
|
167
|
+
function write_record(record2, root) {
|
|
168
|
+
stamp_file.replace_stamp(record_path(root), record2);
|
|
169
|
+
return record2;
|
|
168
170
|
}
|
|
169
171
|
function clear(root) {
|
|
170
172
|
stamp_file.remove_stamp(record_path(root));
|
|
@@ -176,16 +178,16 @@ async function read_snapshot(request2, body, etag) {
|
|
|
176
178
|
return comments === void 0 ? UNREADABLE2 : { kind: "read", snapshot: { body, comments }, etag };
|
|
177
179
|
}
|
|
178
180
|
async function fetch_issue(request2) {
|
|
179
|
-
const
|
|
181
|
+
const read3 = await git_gh_conditional.read_conditional(
|
|
180
182
|
git_gh_api_path.issue_api_path(request2.issue),
|
|
181
183
|
request2.etag,
|
|
182
184
|
request2.timeout_ms
|
|
183
185
|
);
|
|
184
|
-
if (
|
|
185
|
-
const fields = json_value.parse_with(
|
|
186
|
+
if (read3.kind !== "changed") return read3;
|
|
187
|
+
const fields = json_value.parse_with(read3.body, issue_schema);
|
|
186
188
|
if (fields === void 0) return UNREADABLE2;
|
|
187
189
|
if (fields.state === CLOSED_STATE) return { kind: "closed" };
|
|
188
|
-
return await read_snapshot(request2, fields.body ?? "",
|
|
190
|
+
return await read_snapshot(request2, fields.body ?? "", read3.etag);
|
|
189
191
|
}
|
|
190
192
|
function fresh_record(issue, fetched, now, acknowledged_at = now.toISOString()) {
|
|
191
193
|
const baseline = issue_watch_diff.baseline_of(fetched.snapshot);
|
|
@@ -204,44 +206,44 @@ async function record_baseline_here(issue) {
|
|
|
204
206
|
async function clear_here() {
|
|
205
207
|
clear(await git_command.repository_root());
|
|
206
208
|
}
|
|
207
|
-
function with_fetched(
|
|
208
|
-
if (fetched.kind !== "read") return { ...
|
|
209
|
-
const pending = issue_watch_diff.unread_diff(
|
|
210
|
-
return { ...
|
|
209
|
+
function with_fetched(record2, fetched, checked_at) {
|
|
210
|
+
if (fetched.kind !== "read") return { ...record2, checked_at };
|
|
211
|
+
const pending = issue_watch_diff.unread_diff(record2, fetched.snapshot);
|
|
212
|
+
return { ...record2, checked_at, etag: fetched.etag, pending };
|
|
211
213
|
}
|
|
212
|
-
function is_due(
|
|
213
|
-
return now.getTime() - Date.parse(
|
|
214
|
+
function is_due(record2, options, now) {
|
|
215
|
+
return now.getTime() - Date.parse(record2.checked_at) >= options.interval_ms;
|
|
214
216
|
}
|
|
215
|
-
async function refresh(
|
|
217
|
+
async function refresh(record2, options, now, root) {
|
|
216
218
|
const fetched = await fetch_issue({
|
|
217
|
-
issue:
|
|
218
|
-
etag:
|
|
219
|
+
issue: record2.issue,
|
|
220
|
+
etag: record2.etag,
|
|
219
221
|
timeout_ms: options.timeout_ms
|
|
220
222
|
});
|
|
221
223
|
if (fetched.kind === "closed") {
|
|
222
224
|
clear(root);
|
|
223
225
|
return void 0;
|
|
224
226
|
}
|
|
225
|
-
return write_record(with_fetched(
|
|
227
|
+
return write_record(with_fetched(record2, fetched, now.toISOString()), root);
|
|
226
228
|
}
|
|
227
229
|
async function poll(options, root) {
|
|
228
|
-
const
|
|
230
|
+
const record2 = read_record(root);
|
|
229
231
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
230
|
-
if (
|
|
231
|
-
return await refresh(
|
|
232
|
+
if (record2 === void 0 || !is_due(record2, options, now)) return record2;
|
|
233
|
+
return await refresh(record2, options, now, root);
|
|
232
234
|
}
|
|
233
|
-
function mark_shown(
|
|
234
|
-
return write_record({ ...
|
|
235
|
+
function mark_shown(record2, root) {
|
|
236
|
+
return write_record({ ...record2, shown: record2.pending }, root);
|
|
235
237
|
}
|
|
236
238
|
async function acknowledge(root, now = /* @__PURE__ */ new Date()) {
|
|
237
|
-
const
|
|
238
|
-
if (
|
|
239
|
-
const fetched = await fetch_issue({ issue:
|
|
239
|
+
const record2 = read_record(root);
|
|
240
|
+
if (record2 === void 0) return void 0;
|
|
241
|
+
const fetched = await fetch_issue({ issue: record2.issue });
|
|
240
242
|
if (fetched.kind !== "read") return void 0;
|
|
241
|
-
const diff = issue_watch_diff.unread_diff(
|
|
242
|
-
const acknowledged_at = diff === void 0 ?
|
|
243
|
-
write_record(fresh_record(
|
|
244
|
-
return { issue:
|
|
243
|
+
const diff = issue_watch_diff.unread_diff(record2, fetched.snapshot);
|
|
244
|
+
const acknowledged_at = diff === void 0 ? record2.acknowledged_at : now.toISOString();
|
|
245
|
+
write_record(fresh_record(record2.issue, fetched, now, acknowledged_at), root);
|
|
246
|
+
return { issue: record2.issue, diff };
|
|
245
247
|
}
|
|
246
248
|
var issue_watch = {
|
|
247
249
|
acknowledge,
|
|
@@ -444,16 +446,16 @@ var EVERY_CALL_MS = 0;
|
|
|
444
446
|
function ack_command(issue) {
|
|
445
447
|
return `pnpm josh issue:ack ${issue}`;
|
|
446
448
|
}
|
|
447
|
-
function unread_message(
|
|
449
|
+
function unread_message(record2) {
|
|
448
450
|
return [
|
|
449
|
-
`A person updated issue ${session_cite.issue(
|
|
450
|
-
|
|
451
|
-
`Read it, compare it with the acceptance criteria, fix what it changes, then run \`${ack_command(
|
|
451
|
+
`A person updated issue ${session_cite.issue(record2.issue)} after this run read it, and the run has not taken the update in:`,
|
|
452
|
+
record2.pending ?? "",
|
|
453
|
+
`Read it, compare it with the acceptance criteria, fix what it changes, then run \`${ack_command(record2.issue)}\` to record that it was read.`
|
|
452
454
|
].join("\n\n");
|
|
453
455
|
}
|
|
454
|
-
function review_message(
|
|
456
|
+
function review_message(record2, briefed_at) {
|
|
455
457
|
return [
|
|
456
|
-
`Issue ${session_cite.issue(
|
|
458
|
+
`Issue ${session_cite.issue(record2.issue)} was updated after the review was briefed (taken in at ${record2.acknowledged_at}, briefed at ${briefed_at}), so the review read the earlier specification.`,
|
|
457
459
|
"Re-run `/code-review` with a fresh `pnpm josh review:brief`, so the review reads the change against the updated issue."
|
|
458
460
|
].join("\n");
|
|
459
461
|
}
|
|
@@ -461,16 +463,16 @@ async function polled(root) {
|
|
|
461
463
|
return await issue_watch.poll({ interval_ms: EVERY_CALL_MS }, root);
|
|
462
464
|
}
|
|
463
465
|
async function unread_refusal(root) {
|
|
464
|
-
const
|
|
465
|
-
return
|
|
466
|
+
const record2 = await polled(root);
|
|
467
|
+
return record2?.pending === void 0 ? void 0 : unread_message(record2);
|
|
466
468
|
}
|
|
467
469
|
async function review_refusal(root) {
|
|
468
|
-
const
|
|
469
|
-
if (
|
|
470
|
-
if (
|
|
470
|
+
const record2 = await polled(root);
|
|
471
|
+
if (record2 === void 0) return void 0;
|
|
472
|
+
if (record2.pending !== void 0) return unread_message(record2);
|
|
471
473
|
const pointer = review_attest.read_pointer(root);
|
|
472
|
-
if (pointer === void 0 ||
|
|
473
|
-
return review_message(
|
|
474
|
+
if (pointer === void 0 || record2.acknowledged_at <= pointer.taken_at) return void 0;
|
|
475
|
+
return review_message(record2, pointer.taken_at);
|
|
474
476
|
}
|
|
475
477
|
async function review_refusal_here() {
|
|
476
478
|
return await review_refusal(await git_command.repository_root());
|
|
@@ -490,18 +492,18 @@ var issue_watch_gate = {
|
|
|
490
492
|
// scripts/issue/issue-watch-hook.ts
|
|
491
493
|
var POLL_INTERVAL_MS = 18e4;
|
|
492
494
|
var POLL_TIMEOUT_MS = 5e3;
|
|
493
|
-
function is_new_to_run(
|
|
494
|
-
return
|
|
495
|
+
function is_new_to_run(record2) {
|
|
496
|
+
return record2?.pending !== void 0 && record2.pending !== record2.shown;
|
|
495
497
|
}
|
|
496
498
|
async function new_update_reason(now) {
|
|
497
|
-
const
|
|
499
|
+
const record2 = await issue_watch.poll({
|
|
498
500
|
interval_ms: POLL_INTERVAL_MS,
|
|
499
501
|
timeout_ms: POLL_TIMEOUT_MS,
|
|
500
502
|
now
|
|
501
503
|
});
|
|
502
|
-
if (!is_new_to_run(
|
|
503
|
-
issue_watch.mark_shown(
|
|
504
|
-
return issue_watch_gate.unread_message(
|
|
504
|
+
if (!is_new_to_run(record2)) return void 0;
|
|
505
|
+
issue_watch.mark_shown(record2);
|
|
506
|
+
return issue_watch_gate.unread_message(record2);
|
|
505
507
|
}
|
|
506
508
|
async function watch_reason(now = /* @__PURE__ */ new Date()) {
|
|
507
509
|
try {
|
|
@@ -541,7 +543,7 @@ async function mark_implement(directory = process.cwd(), source = process.env) {
|
|
|
541
543
|
var lane_phase = { mark_implement };
|
|
542
544
|
|
|
543
545
|
// scripts/rules/direct-filing.ts
|
|
544
|
-
var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2
|
|
546
|
+
var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2>`, never with `gh api \u2026/issues` or `gh issue create` \u2014 it runs the scout, the lint, the labels and `epic:bundle` itself. It fires on every occurrence (`docs/josh-commands-backlog.md` \u2192 "`josh issue:file`").';
|
|
545
547
|
function is_any_filing(command) {
|
|
546
548
|
return bash_triggers.is_direct_filing(command) || bash_triggers.is_issue_filing(command);
|
|
547
549
|
}
|
|
@@ -900,7 +902,7 @@ function decide(call, run2, can_record) {
|
|
|
900
902
|
if (can_record) ARM_RECORD.record(target, lands_ms);
|
|
901
903
|
return false;
|
|
902
904
|
}
|
|
903
|
-
var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own
|
|
905
|
+
var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own. Start `pnpm josh run:progress --wait` once in the background: it reports to the run's event stream on its own \u2014 relay nothing. When asked, `pnpm josh run:progress --once` \u2014 under `backlogrun`, `pnpm josh run:board --chat`; for CI, `pnpm josh followup`. It fires on every occurrence (`.claude/skills/workflow-commands/progress-watcher.md`).";
|
|
904
906
|
var PROGRESS_NAMES = /* @__PURE__ */ new Set(["run:progress"]);
|
|
905
907
|
var WATCH_FLAG = /(?:^|\s)--(?:wait|once)(?=\s|$)/u;
|
|
906
908
|
function is_progress_watch_segment(segment) {
|
|
@@ -998,7 +1000,7 @@ function carries_a_file_body(command, has_file = existsSync) {
|
|
|
998
1000
|
(line) => is_heredoc_write(line, has_file) || has_body_interpreter(line)
|
|
999
1001
|
);
|
|
1000
1002
|
}
|
|
1001
|
-
var FILE_BODY_REASON = "\u26D4 file body in a shell command: this carries a file's new text inline
|
|
1003
|
+
var FILE_BODY_REASON = "\u26D4 file body in a shell command: this carries a file's new text inline, which is re-read on every later request. Edit a region with the Edit tool, rewrite a whole file with the Write tool, and pass a body by path (`--body-file <path>`); a new-file `cat > <new-file> <<EOF` stays allowed. This rule fires on every occurrence (`prompts/collaboration-workflow/file-edits.md`).";
|
|
1002
1004
|
var ROW2 = {
|
|
1003
1005
|
id: "file-body",
|
|
1004
1006
|
is_trigger: bash_triggers.on_bash_command((command) => carries_a_file_body(command)),
|
|
@@ -1109,7 +1111,7 @@ function is_destructive_segment(segment) {
|
|
|
1109
1111
|
function is_force_or_delete(command) {
|
|
1110
1112
|
return shell_segments.segments_of(command).some((segment) => is_destructive_segment(segment));
|
|
1111
1113
|
}
|
|
1112
|
-
var GIT_FORCE_REASON = "\u26D4 force push or branch delete: this rewrites or removes shared history, which is Tier C and needs explicit current-turn user instruction
|
|
1114
|
+
var GIT_FORCE_REASON = "\u26D4 force push or branch delete: this rewrites or removes shared history, which is Tier C and needs explicit current-turn user instruction. Push with `pnpm josh git`; leave a force push or branch delete to the user's own terminal. This rule fires on every occurrence (`prompts/collaboration-workflow/operating-rules.md`).";
|
|
1113
1115
|
var ROW3 = {
|
|
1114
1116
|
id: "git-force",
|
|
1115
1117
|
is_trigger: bash_triggers.on_bash_command(is_force_or_delete),
|
|
@@ -1162,8 +1164,9 @@ function measurement_from(content, target, thread_id) {
|
|
|
1162
1164
|
return parsed.success ? [parsed.data.payload.info] : [];
|
|
1163
1165
|
});
|
|
1164
1166
|
const session = metadata.find((entry) => entry.payload.id === thread_id);
|
|
1165
|
-
if (session === void 0 || usages.length === 0
|
|
1166
|
-
|
|
1167
|
+
if (session === void 0 || usages.length === 0 || !same_project(session.payload.cwd, target)) {
|
|
1168
|
+
return void 0;
|
|
1169
|
+
}
|
|
1167
1170
|
return { billed_input_per_request: billed_per_request(usages) };
|
|
1168
1171
|
}
|
|
1169
1172
|
function rollout_files(home, thread_id) {
|
|
@@ -1234,8 +1237,8 @@ function owner_sets(corpus, meta) {
|
|
|
1234
1237
|
}
|
|
1235
1238
|
function pairs_with_inherited(session, inherited, is_delegated) {
|
|
1236
1239
|
return cost_attribute.group_by_issue(session.records).flatMap(
|
|
1237
|
-
(group) => group.records.map((
|
|
1238
|
-
record,
|
|
1240
|
+
(group) => group.records.map((record2) => ({
|
|
1241
|
+
record: record2,
|
|
1239
1242
|
issue: group.issue === cost_attribute.UNATTRIBUTED_KEY ? inherited : group.issue,
|
|
1240
1243
|
baseline_tokens: session.baseline_tokens,
|
|
1241
1244
|
session_id: session.session_id,
|
|
@@ -1354,8 +1357,7 @@ var FAILURE_EXIT_CODE2 = 1;
|
|
|
1354
1357
|
var USAGE = "Usage: josh cost (--cut | --over <tokens-per-request>) [--path <dir>]";
|
|
1355
1358
|
var UNMEASURABLE_VERDICT = "unmeasurable";
|
|
1356
1359
|
function to_threshold(raw) {
|
|
1357
|
-
if (raw === void 0) return void 0;
|
|
1358
|
-
if (raw.trim() === "") return void 0;
|
|
1360
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
1359
1361
|
const parsed = Number(raw);
|
|
1360
1362
|
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1361
1363
|
}
|
|
@@ -1400,7 +1402,7 @@ function provider_of(environment) {
|
|
|
1400
1402
|
function measurement_of(session) {
|
|
1401
1403
|
return {
|
|
1402
1404
|
billed_input_per_request: session.records.map(
|
|
1403
|
-
(
|
|
1405
|
+
(record2) => cost_usage.billed_input(record2.totals)
|
|
1404
1406
|
)
|
|
1405
1407
|
};
|
|
1406
1408
|
}
|
|
@@ -1508,8 +1510,71 @@ var cost_format = {
|
|
|
1508
1510
|
format_share
|
|
1509
1511
|
};
|
|
1510
1512
|
|
|
1511
|
-
// scripts/
|
|
1513
|
+
// scripts/run/cut/run-cut-decline.ts
|
|
1512
1514
|
import { z as z5 } from "zod";
|
|
1515
|
+
var DECLINE_PREFIX = "josh-run-cut-decline-";
|
|
1516
|
+
var decline_schema = z5.object({ issue: z5.string(), hold_taken_at: z5.string().optional() });
|
|
1517
|
+
function decline_path(git_directory) {
|
|
1518
|
+
return stamp_file.stamp_path(DECLINE_PREFIX, git_directory);
|
|
1519
|
+
}
|
|
1520
|
+
function record(git_directory, decline) {
|
|
1521
|
+
stamp_file.replace_stamp(decline_path(git_directory), decline);
|
|
1522
|
+
}
|
|
1523
|
+
function read(git_directory) {
|
|
1524
|
+
const raw = stamp_file.read_stamp_text(decline_path(git_directory));
|
|
1525
|
+
return raw === void 0 ? void 0 : json_value.parse_with(raw, decline_schema);
|
|
1526
|
+
}
|
|
1527
|
+
function matches(recorded, current) {
|
|
1528
|
+
return recorded?.issue === current.issue && recorded.hold_taken_at === current.hold_taken_at;
|
|
1529
|
+
}
|
|
1530
|
+
function is_declined_sync(issue, directory = run_cut.worktree_git_directory_sync()) {
|
|
1531
|
+
if (directory === void 0) return false;
|
|
1532
|
+
const hold_taken_at = run_cut.hold_of(directory)?.taken_at;
|
|
1533
|
+
return matches(read(directory), { issue, hold_taken_at });
|
|
1534
|
+
}
|
|
1535
|
+
async function declined(request2, state, code) {
|
|
1536
|
+
if (request2.phase !== run_cut.IMPLEMENTATION_PHASE) return code;
|
|
1537
|
+
const directory = await run_cut.worktree_directory();
|
|
1538
|
+
if (directory !== void 0) {
|
|
1539
|
+
record(directory, { issue: request2.issue, hold_taken_at: state.hold_taken_at });
|
|
1540
|
+
}
|
|
1541
|
+
return code;
|
|
1542
|
+
}
|
|
1543
|
+
var run_cut_decline = { decline_path, declined, is_declined_sync, read, record };
|
|
1544
|
+
|
|
1545
|
+
// scripts/run/cut/run-cut-ready.ts
|
|
1546
|
+
function is_ready(tree) {
|
|
1547
|
+
return tree.branch !== tree.default_branch && tree.is_dirty;
|
|
1548
|
+
}
|
|
1549
|
+
async function is_lane_branch(state) {
|
|
1550
|
+
const default_branch = await git_command.get_default_branch();
|
|
1551
|
+
return is_ready({ branch: state.branch, default_branch, is_dirty: state.is_dirty });
|
|
1552
|
+
}
|
|
1553
|
+
var STATUS_ARGUMENTS = ["status", "--porcelain=v2", "--branch", UNTRACKED_FILES_FLAG];
|
|
1554
|
+
var HEADER_PREFIX = "#";
|
|
1555
|
+
var BRANCH_HEADER = "# branch.head ";
|
|
1556
|
+
function tree_of(status, default_branch) {
|
|
1557
|
+
const lines = status.split("\n").filter((line) => line !== "");
|
|
1558
|
+
const header = lines.find((line) => line.startsWith(BRANCH_HEADER));
|
|
1559
|
+
if (header === void 0) return void 0;
|
|
1560
|
+
const branch = header.slice(BRANCH_HEADER.length);
|
|
1561
|
+
const is_dirty = lines.some((line) => !line.startsWith(HEADER_PREFIX));
|
|
1562
|
+
return { branch, default_branch, is_dirty };
|
|
1563
|
+
}
|
|
1564
|
+
function read_tree_sync() {
|
|
1565
|
+
const status = git_spawn_sync.read(STATUS_ARGUMENTS);
|
|
1566
|
+
if (status === void 0) return void 0;
|
|
1567
|
+
const reference = git_spawn_sync.read(git_diff_reads.DEFAULT_BRANCH_ARGUMENTS);
|
|
1568
|
+
return tree_of(status, git_diff_reads.default_branch_of(reference));
|
|
1569
|
+
}
|
|
1570
|
+
function is_ready_sync(read3 = read_tree_sync) {
|
|
1571
|
+
const tree = read3();
|
|
1572
|
+
return tree === void 0 || is_ready(tree);
|
|
1573
|
+
}
|
|
1574
|
+
var run_cut_ready = { is_lane_branch, is_ready, is_ready_sync, tree_of };
|
|
1575
|
+
|
|
1576
|
+
// scripts/rules/implementation-cut-verdict.ts
|
|
1577
|
+
import { z as z6 } from "zod";
|
|
1513
1578
|
var VERDICT_CACHE_PREFIX = "josh-impl-cut-verdict-";
|
|
1514
1579
|
var VERDICT_REUSE_MS = 5e3;
|
|
1515
1580
|
var VERDICT_VALUES = [
|
|
@@ -1517,7 +1582,7 @@ var VERDICT_VALUES = [
|
|
|
1517
1582
|
"under",
|
|
1518
1583
|
"unmeasurable"
|
|
1519
1584
|
];
|
|
1520
|
-
var cache_schema =
|
|
1585
|
+
var cache_schema = z6.object({ read_at_ms: z6.number(), verdict: z6.enum(VERDICT_VALUES) });
|
|
1521
1586
|
function cache_path(directory) {
|
|
1522
1587
|
return stamp_file.stamp_path(VERDICT_CACHE_PREFIX, directory);
|
|
1523
1588
|
}
|
|
@@ -1528,11 +1593,11 @@ function cached_verdict(target, now_ms) {
|
|
|
1528
1593
|
if (cached === void 0) return void 0;
|
|
1529
1594
|
return now_ms - cached.read_at_ms < VERDICT_REUSE_MS ? cached.verdict : void 0;
|
|
1530
1595
|
}
|
|
1531
|
-
function reused_verdict(
|
|
1596
|
+
function reused_verdict(read3, directory = process.cwd(), now_ms = Date.now()) {
|
|
1532
1597
|
const target = cache_path(directory);
|
|
1533
1598
|
const cached = cached_verdict(target, now_ms);
|
|
1534
1599
|
if (cached !== void 0) return cached;
|
|
1535
|
-
const value =
|
|
1600
|
+
const value = read3();
|
|
1536
1601
|
stamp_file.replace_stamp(target, { read_at_ms: now_ms, verdict: value });
|
|
1537
1602
|
return value;
|
|
1538
1603
|
}
|
|
@@ -1555,6 +1620,9 @@ function is_impl_cut_segment(segment) {
|
|
|
1555
1620
|
function takes_the_impl_cut(command) {
|
|
1556
1621
|
return shell_segments.segments_of(command).some((segment) => is_impl_cut_segment(segment));
|
|
1557
1622
|
}
|
|
1623
|
+
function can_cut_sync(issue) {
|
|
1624
|
+
return !run_cut_decline.is_declined_sync(issue) && run_cut_ready.is_ready_sync();
|
|
1625
|
+
}
|
|
1558
1626
|
function current_state() {
|
|
1559
1627
|
return {
|
|
1560
1628
|
directory: process.cwd(),
|
|
@@ -1564,7 +1632,8 @@ function current_state() {
|
|
|
1564
1632
|
// **Read through the short reuse window**. The row now fires per
|
|
1565
1633
|
// threshold crossing rather than once per run, so this predicate is a candidate on every edit;
|
|
1566
1634
|
// the window collapses one turn's burst of edits to a single whole-transcript price.
|
|
1567
|
-
verdict: () => implementation_cut_verdict.reused_verdict(() => cost_cli.session_verdict())
|
|
1635
|
+
verdict: () => implementation_cut_verdict.reused_verdict(() => cost_cli.session_verdict()),
|
|
1636
|
+
can_cut: can_cut_sync
|
|
1568
1637
|
};
|
|
1569
1638
|
}
|
|
1570
1639
|
function lane_child_issue(state) {
|
|
@@ -1590,11 +1659,13 @@ function warrants_the_cut(state) {
|
|
|
1590
1659
|
return verdict !== cost_verdict.UNDER_VERDICT;
|
|
1591
1660
|
}
|
|
1592
1661
|
function is_over_threshold_edit(call, state = current_state()) {
|
|
1593
|
-
if (!is_edit_tool(call.name)
|
|
1594
|
-
|
|
1662
|
+
if (!is_edit_tool(call.name)) return false;
|
|
1663
|
+
const issue = uncut_run_issue(state);
|
|
1664
|
+
if (issue === void 0) return false;
|
|
1665
|
+
return warrants_the_cut(state) && state.can_cut(issue);
|
|
1595
1666
|
}
|
|
1596
1667
|
var THRESHOLD_TEXT = `${cost_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token`;
|
|
1597
|
-
var IMPLEMENTATION_CUT_REASON = `\u26D4 implementation-phase cut:
|
|
1668
|
+
var IMPLEMENTATION_CUT_REASON = `\u26D4 implementation-phase cut: refused on every edit past the ${THRESHOLD_TEXT} line. Write \`${run_cut_handoff.HANDOFF_PATH}\` as ${run_cut_handoff.HANDOFF_FORMAT}, run \`pnpm josh run:cut --impl <N> --handoff <path>\`; \`cut\`: end the turn immediately, no Telegram is owed; else reissue the edit (\`.claude/skills/workflow-commands/pre-gate-cut.md\`).`;
|
|
1598
1669
|
var REISSUE_WINDOW_MS = 9e4;
|
|
1599
1670
|
function is_reissued_refusal(now_ms, delivered_at_ms) {
|
|
1600
1671
|
return now_ms - delivered_at_ms < REISSUE_WINDOW_MS;
|
|
@@ -1607,7 +1678,12 @@ var ROW4 = {
|
|
|
1607
1678
|
is_trigger: is_over_threshold_edit,
|
|
1608
1679
|
reason: IMPLEMENTATION_CUT_REASON,
|
|
1609
1680
|
decide: decide2,
|
|
1610
|
-
keeps: bash_triggers.on_bash_command(takes_the_impl_cut)
|
|
1681
|
+
keeps: bash_triggers.on_bash_command(takes_the_impl_cut),
|
|
1682
|
+
// The opening the reason carried before it was cut to the action and the next command.
|
|
1683
|
+
former_reasons: [
|
|
1684
|
+
"\u26D4 implementation-phase cut: this checkout is a lane dispatched",
|
|
1685
|
+
"\u26D4 implementation-phase cut: this run's context crossed the"
|
|
1686
|
+
]
|
|
1611
1687
|
};
|
|
1612
1688
|
var implementation_cut = {
|
|
1613
1689
|
IMPLEMENTATION_CUT_REASON,
|
|
@@ -1665,10 +1741,10 @@ var gh_api = {
|
|
|
1665
1741
|
// scripts/rules/prior-comment-read.ts
|
|
1666
1742
|
var ISSUE_PATH_NUMBER = /issues\/(\d+)/gu;
|
|
1667
1743
|
var ISSUE_VIEW_NUMBER = /\bissue\s+view\s+(?:-{1,2}\S+\s+)*(\d+)/u;
|
|
1668
|
-
var ISSUE_READ_ARGUMENTS = /\
|
|
1744
|
+
var ISSUE_READ_ARGUMENTS = /\b(?:issue:read|run:entry|run:prep)\b([\s\d]*)/u;
|
|
1669
1745
|
var COMMENTS_ENDPOINT = /issues\/\d+\/comments\b/u;
|
|
1670
1746
|
var VIEW_WITH_COMMENTS = /\bissue\s+view\b[^\n]*--comments\b/u;
|
|
1671
|
-
var ISSUE_READ_COMMAND = /\
|
|
1747
|
+
var ISSUE_READ_COMMAND = /\b(?:issue:read|run:entry|run:prep)\b/u;
|
|
1672
1748
|
function add_issue_read_numbers(command, numbers) {
|
|
1673
1749
|
const match = ISSUE_READ_ARGUMENTS.exec(command);
|
|
1674
1750
|
if (match === null) return;
|
|
@@ -1739,7 +1815,7 @@ function is_body_only_issue_read(command) {
|
|
|
1739
1815
|
function reads_issue_comments(command) {
|
|
1740
1816
|
return shell_segments.segments_of(command).some((segment) => fetches_issue_comments(segment));
|
|
1741
1817
|
}
|
|
1742
|
-
var ISSUE_COMMENTS_REASON = "\u26D4 issue comments: pnpm josh issue:read <N>\nRun that in place of this read
|
|
1818
|
+
var ISSUE_COMMENTS_REASON = "\u26D4 issue comments: pnpm josh issue:read <N>\nRun that in place of this read \u2014 an Issue's comments are part of it, and a later comment supersedes the body it contradicts; refused until that command is on the transcript. Without josh, read `gh api repos/{owner}/{repo}/issues/<N>/comments` beside the body (`.claude/skills/workflow-commands/issue-comments.md`).";
|
|
1743
1819
|
var ROW5 = {
|
|
1744
1820
|
id: "issue-comments",
|
|
1745
1821
|
is_trigger: bash_triggers.on_bash_command(is_body_only_issue_read),
|
|
@@ -1768,7 +1844,7 @@ function is_bare_segment(segment) {
|
|
|
1768
1844
|
function is_bare_josh_git(command) {
|
|
1769
1845
|
return shell_segments.segments_of(command).some((segment) => is_bare_segment(segment));
|
|
1770
1846
|
}
|
|
1771
|
-
var JOSH_GIT_BARE_REASON = '\u26D4 bare `pnpm josh git`: this prompts to confirm the staging, and with no TTY the prompt falls to its cancel branch
|
|
1847
|
+
var JOSH_GIT_BARE_REASON = '\u26D4 bare `pnpm josh git`: this prompts to confirm the staging, and with no TTY the prompt falls to its cancel branch. Run `pnpm josh git -y "<title> #<N>"`, or `pnpm josh git -y --skip-commit --skip-push` to open the PR for a push that already landed. It fires on every occurrence.';
|
|
1772
1848
|
var ROW6 = {
|
|
1773
1849
|
id: "josh-git-bare",
|
|
1774
1850
|
is_trigger: bash_triggers.on_bash_command(is_bare_josh_git),
|
|
@@ -1801,7 +1877,7 @@ function is_carry_conflict(command, is_lane_child = lane_child_marker.is_child_o
|
|
|
1801
1877
|
if (!invokes_budget_command(command)) return false;
|
|
1802
1878
|
return is_lane_child;
|
|
1803
1879
|
}
|
|
1804
|
-
var LANE_CARRY_CONFLICT_REASON =
|
|
1880
|
+
var LANE_CARRY_CONFLICT_REASON = "\u26D4 lane child carry conflict: this session is a dispatched lane child, and `run:merge` / `run:carry` are the parent budget commands; the live record belongs to the parent, not to a competing run. Continue implementing this Issue: no `needs-decision`, no Telegram. Live `run:carry` evidence takes a fresh `JOSH_TEMP_ROOT`; `run:merge` is refused under any root, on every occurrence.";
|
|
1805
1881
|
var ROW7 = {
|
|
1806
1882
|
id: "lane-carry-conflict",
|
|
1807
1883
|
is_trigger: bash_triggers.on_bash_command(is_carry_conflict),
|
|
@@ -1816,20 +1892,20 @@ var lane_carry_conflict = {
|
|
|
1816
1892
|
};
|
|
1817
1893
|
|
|
1818
1894
|
// scripts/agent/interactive-ask.ts
|
|
1819
|
-
import { z as
|
|
1895
|
+
import { z as z7 } from "zod";
|
|
1820
1896
|
var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1821
1897
|
function is_interactive_tool(name) {
|
|
1822
1898
|
return INTERACTIVE_TOOLS.has(name);
|
|
1823
1899
|
}
|
|
1824
|
-
var OPTION_SCHEMA =
|
|
1825
|
-
var QUESTION_SCHEMA =
|
|
1826
|
-
question:
|
|
1827
|
-
options:
|
|
1900
|
+
var OPTION_SCHEMA = z7.looseObject({ label: z7.string().optional() });
|
|
1901
|
+
var QUESTION_SCHEMA = z7.looseObject({
|
|
1902
|
+
question: z7.string().optional(),
|
|
1903
|
+
options: z7.array(OPTION_SCHEMA).optional()
|
|
1828
1904
|
});
|
|
1829
|
-
var ASK_INPUT_SCHEMA =
|
|
1830
|
-
var DENIAL_SCHEMA =
|
|
1831
|
-
tool_name:
|
|
1832
|
-
tool_input:
|
|
1905
|
+
var ASK_INPUT_SCHEMA = z7.looseObject({ questions: z7.array(QUESTION_SCHEMA).optional() });
|
|
1906
|
+
var DENIAL_SCHEMA = z7.looseObject({
|
|
1907
|
+
tool_name: z7.string().optional(),
|
|
1908
|
+
tool_input: z7.unknown().optional()
|
|
1833
1909
|
});
|
|
1834
1910
|
var UNKNOWN_QUESTION = "(question text unavailable)";
|
|
1835
1911
|
var OPTION_SEPARATOR = " / ";
|
|
@@ -1862,7 +1938,7 @@ function is_interactive_ask(call, is_lane_child = lane_child_marker.is_child_of(
|
|
|
1862
1938
|
if (!interactive_ask.is_interactive_tool(call.name)) return false;
|
|
1863
1939
|
return is_lane_child;
|
|
1864
1940
|
}
|
|
1865
|
-
var LANE_INTERACTIVE_ASK_REASON =
|
|
1941
|
+
var LANE_INTERACTIVE_ASK_REASON = "\u26D4 lane child interactive ask: this session is a dispatched lane child and cannot ask a person, so park instead: `gh api repos/{owner}/{repo}/issues/<N>/labels -f 'labels[]=needs-decision'`, `pnpm josh issue:comment <N> --body-file <path>`, the `confirmation` Telegram, stop. It fires on every occurrence (`.claude/skills/workflow-commands/pre-gate-cut.md`, `backlogrun-park.md`).";
|
|
1866
1942
|
var ROW8 = {
|
|
1867
1943
|
id: "lane-interactive-ask",
|
|
1868
1944
|
is_trigger: is_interactive_ask,
|
|
@@ -1918,7 +1994,7 @@ function decide3(_call, run2) {
|
|
|
1918
1994
|
const commands = tail_commands.prior_bash_commands(time_density_hook.read_tail(run2.transcript));
|
|
1919
1995
|
return issue !== void 0 && promoted_issues(commands).has(issue);
|
|
1920
1996
|
}
|
|
1921
|
-
var LANE_SPLIT_PARK_REASON = '\u26D4 lane split park: this session is a dispatched lane child that promoted its own Issue to an epic this run, and a split is not a park
|
|
1997
|
+
var LANE_SPLIT_PARK_REASON = '\u26D4 lane split park: this session is a dispatched lane child that promoted its own Issue to an epic this run, and a split is not a park: no `needs-decision` on the epic, no `confirmation` Telegram, on every occurrence. Park a child issue if the rest needs a person, else end the turn (`.claude/skills/workflow-commands/backlogrun-park.md` \u2192 "Splitting a child mid-run").';
|
|
1922
1998
|
var ROW9 = {
|
|
1923
1999
|
id: "lane-split-park",
|
|
1924
2000
|
is_trigger: bash_triggers.on_bash_command(is_candidate),
|
|
@@ -1944,8 +2020,9 @@ var NON_COLLIDING_FLAGS = /* @__PURE__ */ new Set([
|
|
|
1944
2020
|
var FLAG_PREFIX2 = "-";
|
|
1945
2021
|
function switch_target(segment) {
|
|
1946
2022
|
const call = git_argv.parse(segment);
|
|
1947
|
-
if (call?.subcommand !== SWITCH_SUBCOMMAND)
|
|
1948
|
-
|
|
2023
|
+
if (call?.subcommand !== SWITCH_SUBCOMMAND || call.args.some((argument) => NON_COLLIDING_FLAGS.has(argument))) {
|
|
2024
|
+
return void 0;
|
|
2025
|
+
}
|
|
1949
2026
|
return call.args.find((argument) => !argument.startsWith(FLAG_PREFIX2));
|
|
1950
2027
|
}
|
|
1951
2028
|
function switch_targets(command) {
|
|
@@ -1959,7 +2036,7 @@ function is_switch_away_from_lane(command, is_lane_child = lane_child_marker.is_
|
|
|
1959
2036
|
if (!is_lane_child || own_branch === void 0) return false;
|
|
1960
2037
|
return switch_targets(command).some((target) => target !== own_branch);
|
|
1961
2038
|
}
|
|
1962
|
-
var LANE_SWITCH_MAIN_REASON = "\u26D4 lane child on `git switch main`: this session is a dispatched lane child, and switching to the default branch here always fails
|
|
2039
|
+
var LANE_SWITCH_MAIN_REASON = "\u26D4 lane child on `git switch main`: this session is a dispatched lane child, and switching to the default branch here always fails (`already used by worktree`: the primary checkout holds it). Skip this step and keep implementing on the current branch; `pnpm josh main:merge` brings the default in during the gate. Refused on every occurrence (`backlogrun-lanes.md`, `backlogrun-child.md`).";
|
|
1963
2040
|
var ROW10 = {
|
|
1964
2041
|
id: "lane-switch-main",
|
|
1965
2042
|
is_trigger: bash_triggers.on_bash_command(is_switch_away_from_lane),
|
|
@@ -2471,7 +2548,7 @@ function command_line(oracle) {
|
|
|
2471
2548
|
return oracle.args ? `pnpm josh ${command} ${oracle.args}` : `pnpm josh ${command}`;
|
|
2472
2549
|
}
|
|
2473
2550
|
function reason_for(oracle, firing_point) {
|
|
2474
|
-
return `\u26D4 decision oracle not consulted: this is ${firing_point.describes}
|
|
2551
|
+
return `\u26D4 decision oracle not consulted: this is ${firing_point.describes}. Run \`${command_line(oracle)}\` first \u2014 it decides ${oracle.decision.toLowerCase()} and answers ${oracle.vocabulary.join(" | ")} (${oracle.single_source}). Every such call is refused until that command is on the transcript.`;
|
|
2475
2552
|
}
|
|
2476
2553
|
function row_for(oracle, firing_point) {
|
|
2477
2554
|
const names = command_names(oracle);
|
|
@@ -2537,12 +2614,14 @@ function is_destructive_segment2(segment) {
|
|
|
2537
2614
|
function is_destructive_command(command) {
|
|
2538
2615
|
return shell_segments.segments_of(command).some((segment) => is_destructive_segment2(segment));
|
|
2539
2616
|
}
|
|
2540
|
-
var DESTRUCTIVE_COMMAND_REASON = "\u26D4 destructive command: a recursive forced `rm
|
|
2617
|
+
var DESTRUCTIVE_COMMAND_REASON = "\u26D4 destructive command: a recursive forced `rm`, a `gh repo delete` / `archive` / visibility edit, `gh pr close` or a `gh api -X DELETE` cannot be undone, which is Tier C. Remove one path at a time without `-f`, or ask the user to run it. It fires on every occurrence (`prompts/collaboration-workflow/operating-rules.md`).";
|
|
2541
2618
|
var ROW11 = {
|
|
2542
2619
|
id: "destructive-command",
|
|
2543
2620
|
is_trigger: bash_triggers.on_bash_command(is_destructive_command),
|
|
2544
2621
|
reason: DESTRUCTIVE_COMMAND_REASON,
|
|
2545
|
-
decide: () => true
|
|
2622
|
+
decide: () => true,
|
|
2623
|
+
// The opening the reason carried before it was cut to the action and the next command.
|
|
2624
|
+
former_reasons: ["\u26D4 destructive command: a recursive forced `rm` (`rm -rf`"]
|
|
2546
2625
|
};
|
|
2547
2626
|
var destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW: ROW11, is_destructive_command };
|
|
2548
2627
|
|
|
@@ -2666,7 +2745,7 @@ function is_unauthorized_segment(segment) {
|
|
|
2666
2745
|
function is_unauthorized_worktree_change(command) {
|
|
2667
2746
|
return shell_segments.segments_of(command).some((segment) => is_unauthorized_segment(segment));
|
|
2668
2747
|
}
|
|
2669
|
-
var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout
|
|
2748
|
+
var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout --`, `git restore`, `git clean -f`, `git stash`. A documented flow stashes with `git stash push -u -m "<message>"`; a handed-over stash is `pnpm josh stash:pop "<message>"`; record the substitution on the Issue (Tier A) unless the plan says why the owner keeps the stash: then stop and confirm. It fires on every occurrence (`operating-rules.md`).';
|
|
2670
2749
|
var ROW13 = {
|
|
2671
2750
|
id: "worktree-mutation",
|
|
2672
2751
|
is_trigger: bash_triggers.on_bash_command(is_unauthorized_worktree_change),
|
|
@@ -2702,7 +2781,7 @@ function is_index_segment(segment) {
|
|
|
2702
2781
|
function is_index_mutation(command) {
|
|
2703
2782
|
return shell_segments.segments_of(command).some((segment) => is_index_segment(segment));
|
|
2704
2783
|
}
|
|
2705
|
-
var INDEX_MUTATION_REASON =
|
|
2784
|
+
var INDEX_MUTATION_REASON = "\u26D4 git index mutation: `git add` / `stage` / `commit` / `reset` / `rm` / `mv` and `git restore --staged` overwrite the user's staged snapshot. Commit with `pnpm josh git -y`; any other staging is the user's, on explicit instruction. It fires on every occurrence (`prompts/collaboration-workflow/operating-rules.md` \u2192 \"no-self-staging\").";
|
|
2706
2785
|
var ROW14 = {
|
|
2707
2786
|
id: "index-mutation",
|
|
2708
2787
|
is_trigger: bash_triggers.on_bash_command(is_index_mutation),
|
|
@@ -2722,20 +2801,20 @@ import path4 from "node:path";
|
|
|
2722
2801
|
var KIT_PACKAGE_NAME = "@joshuafolkken/kit";
|
|
2723
2802
|
|
|
2724
2803
|
// scripts/doctor/doctor-consumer.ts
|
|
2725
|
-
import { z as
|
|
2804
|
+
import { z as z8 } from "zod";
|
|
2726
2805
|
var NODE_MODULES = "node_modules";
|
|
2727
2806
|
var SETTINGS_PATH = path4.join(".claude", "settings.json");
|
|
2728
2807
|
var CLAUDE_MD = "CLAUDE.md";
|
|
2729
2808
|
var PLUGIN_ID = "kit@kit";
|
|
2730
2809
|
var CLAUDE_MD_POINTER = `@${NODE_MODULES}/${KIT_PACKAGE_NAME}/dist/${CLAUDE_MD}`;
|
|
2731
2810
|
var SECRETLINT_BIN = path4.join(NODE_MODULES, ".bin", "secretlint");
|
|
2732
|
-
var manifest_schema =
|
|
2733
|
-
name:
|
|
2734
|
-
dependencies:
|
|
2735
|
-
devDependencies:
|
|
2811
|
+
var manifest_schema = z8.object({
|
|
2812
|
+
name: z8.string().optional(),
|
|
2813
|
+
dependencies: z8.record(z8.string(), z8.string()).optional(),
|
|
2814
|
+
devDependencies: z8.record(z8.string(), z8.string()).optional()
|
|
2736
2815
|
});
|
|
2737
|
-
var settings_schema =
|
|
2738
|
-
enabledPlugins:
|
|
2816
|
+
var settings_schema = z8.object({
|
|
2817
|
+
enabledPlugins: z8.record(z8.string(), z8.boolean()).optional()
|
|
2739
2818
|
});
|
|
2740
2819
|
var STATE_OK = "ok";
|
|
2741
2820
|
var STATE_TARGET_MISSING = "target-missing";
|
|
@@ -2898,12 +2977,14 @@ function is_consumer_settings_edit(call, is_kit_consumer2) {
|
|
|
2898
2977
|
function is_protected_file_call(call, is_kit_consumer2 = doctor_consumer.is_kit_consumer) {
|
|
2899
2978
|
return is_environment_read(call) || is_consumer_settings_edit(call, is_kit_consumer2);
|
|
2900
2979
|
}
|
|
2901
|
-
var PROTECTED_FILE_REASON =
|
|
2980
|
+
var PROTECTED_FILE_REASON = "\u26D4 protected file: `.env`, a `.env.*` variant and `.dev.vars` hold secrets, and a consumer `.claude/settings.json` is owned by `josh sync` (a change belongs upstream in kit). Leave these files alone, or ask the user. It fires on every occurrence.";
|
|
2902
2981
|
var ROW15 = {
|
|
2903
2982
|
id: "protected-file",
|
|
2904
2983
|
is_trigger: is_protected_file_call,
|
|
2905
2984
|
reason: PROTECTED_FILE_REASON,
|
|
2906
|
-
decide: () => true
|
|
2985
|
+
decide: () => true,
|
|
2986
|
+
// The opening the reason carried before it was cut to the action and the next command.
|
|
2987
|
+
former_reasons: ["\u26D4 protected file: `.env` holds the Telegram bot token"]
|
|
2907
2988
|
};
|
|
2908
2989
|
var protected_files = { ROW: ROW15, is_protected_file_call };
|
|
2909
2990
|
|
|
@@ -2940,7 +3021,7 @@ function is_verification_command(segment) {
|
|
|
2940
3021
|
function is_masked_verification(command) {
|
|
2941
3022
|
return time_shell.discarded_commands(command).some((segment) => is_verification_command(segment));
|
|
2942
3023
|
}
|
|
2943
|
-
var PIPED_VERIFICATION_REASON = "\u26D4 piped verification: a pipeline exits with its last command's status, so `pnpm josh gate | tail` reports success on a gate that failed
|
|
3024
|
+
var PIPED_VERIFICATION_REASON = "\u26D4 piped verification: a pipeline exits with its last command's status, so `pnpm josh gate | tail` reports success on a gate that failed. Reissue this call with no pipe (josh prints its verdict last), or redirect it to a file and read ranges from that file, or prefix `set -o pipefail`; read the verdict line, never the exit code alone (`prompts/collaboration-workflow/output-bounds.md`).";
|
|
2944
3025
|
function pipelines_of(command) {
|
|
2945
3026
|
return shell_segments.segments_of(time_shell.unquoted(command)).map((segment) => segment.split("|").map((piece) => piece.trim()));
|
|
2946
3027
|
}
|
|
@@ -2953,12 +3034,15 @@ function runs_verification(command) {
|
|
|
2953
3034
|
function keeps_verdict_intact(command) {
|
|
2954
3035
|
return runs_verification(command) && !is_masked_verification(command);
|
|
2955
3036
|
}
|
|
2956
|
-
var
|
|
3037
|
+
var PIPEFAIL_OPEN = "(set -o pipefail; ";
|
|
3038
|
+
var PIPEFAIL_CLOSE = ")";
|
|
3039
|
+
var COMMENT_START = /(?:^|\s)#/u;
|
|
2957
3040
|
var FULL_READING_FILTER = /^(?:tail|grep)\b/u;
|
|
2958
3041
|
var EARLY_EXIT_GREP = /^grep\b.*\s(?:-[a-zA-Z]*[lLmq]|--(?:quiet|silent|max-count|files-with(?:out)?-match))/u;
|
|
2959
3042
|
var ALLOWED_OPERATORS = /2>&1|&&/gu;
|
|
2960
3043
|
var SIDE_EFFECT_SYNTAX = /[&<>`]|\$\(/u;
|
|
2961
|
-
var
|
|
3044
|
+
var GROUP_SYNTAX = /[()]/u;
|
|
3045
|
+
var PIPEFAIL_NOTE = "\u21BB piped verification: the josh check was piped, so its pipeline was wrapped in `(set -o pipefail; \u2026)` to carry the check's status, and the rest of the line ran as typed. Read the printed verdict, never the exit code alone \u2014 `prompts/collaboration-workflow/output-bounds.md`.";
|
|
2962
3046
|
function reads_to_the_end(piece) {
|
|
2963
3047
|
return FULL_READING_FILTER.test(piece) && !EARLY_EXIT_GREP.test(piece);
|
|
2964
3048
|
}
|
|
@@ -2969,14 +3053,40 @@ function is_filtered_check(pipeline) {
|
|
|
2969
3053
|
function has_side_effect_syntax(command) {
|
|
2970
3054
|
return SIDE_EFFECT_SYNTAX.test(command.replaceAll(ALLOWED_OPERATORS, " "));
|
|
2971
3055
|
}
|
|
2972
|
-
function
|
|
2973
|
-
|
|
3056
|
+
function is_rewritable_part(raw, judged) {
|
|
3057
|
+
const pipeline = judged.split("|").map((piece) => piece.trim());
|
|
3058
|
+
return !has_side_effect_syntax(raw) && !GROUP_SYNTAX.test(judged) && is_filtered_check(pipeline);
|
|
3059
|
+
}
|
|
3060
|
+
function code_end(judged) {
|
|
3061
|
+
const comment = COMMENT_START.exec(judged);
|
|
3062
|
+
return comment === null ? judged.length : comment.index;
|
|
3063
|
+
}
|
|
3064
|
+
function wrapped(raw, judged) {
|
|
3065
|
+
const code = raw.slice(0, code_end(judged));
|
|
3066
|
+
const core = code.trim();
|
|
3067
|
+
const lead = code.slice(0, code.indexOf(core));
|
|
3068
|
+
return `${lead}${PIPEFAIL_OPEN}${core}${PIPEFAIL_CLOSE}${raw.slice(lead.length + core.length)}`;
|
|
3069
|
+
}
|
|
3070
|
+
function rewritten_part(raw, judged) {
|
|
3071
|
+
if (!is_masked_verification(judged)) return raw;
|
|
3072
|
+
return is_rewritable_part(raw, judged) ? wrapped(raw, judged) : void 0;
|
|
3073
|
+
}
|
|
3074
|
+
function pipefail_command(command) {
|
|
3075
|
+
const judged = time_shell.blanked(command);
|
|
3076
|
+
if (judged === void 0 || !is_masked_verification(command)) return void 0;
|
|
3077
|
+
const offset = { at: 0 };
|
|
3078
|
+
const parts = shell_segments.parts_of(judged).map((part) => {
|
|
3079
|
+
const raw = command.slice(offset.at, offset.at + part.length);
|
|
3080
|
+
offset.at += part.length;
|
|
3081
|
+
return rewritten_part(raw, part);
|
|
3082
|
+
});
|
|
3083
|
+
const rewritten = parts.includes(void 0) ? void 0 : parts.join("");
|
|
3084
|
+
return rewritten === command ? void 0 : rewritten;
|
|
2974
3085
|
}
|
|
2975
3086
|
function pipefail_input(call) {
|
|
2976
3087
|
if (call.name !== cost_blocks.BASH_TOOL || !json_value.is_record(call.input)) return void 0;
|
|
2977
|
-
const command = time_shell.bash_command(call.input);
|
|
2978
|
-
|
|
2979
|
-
return { ...call.input, command: `${PIPEFAIL_PREFIX}${command}` };
|
|
3088
|
+
const command = pipefail_command(time_shell.bash_command(call.input));
|
|
3089
|
+
return command === void 0 ? void 0 : { ...call.input, command };
|
|
2980
3090
|
}
|
|
2981
3091
|
var piped_verification = {
|
|
2982
3092
|
PIPED_VERIFICATION_REASON,
|
|
@@ -3013,7 +3123,7 @@ function is_poll_loop(command) {
|
|
|
3013
3123
|
if (is_state_wait(plain)) return true;
|
|
3014
3124
|
return LOOP_KEYWORD2.test(plain) && SLEEP_COMMAND.test(plain);
|
|
3015
3125
|
}
|
|
3016
|
-
var POLL_LOOP_REASON =
|
|
3126
|
+
var POLL_LOOP_REASON = "\u26D4 output poll loop: this hand-writes a `while`/`until` wait loop over a command's output, a marker file or a process, and the loop does not know when the command finished. Issue the long command with `run_in_background` set and end the turn \u2014 its exit re-invokes you; for CI, `pnpm josh followup` (`.claude/skills/workflow-commands/background-commands.md`). It fires on every occurrence.";
|
|
3017
3127
|
var ROW16 = {
|
|
3018
3128
|
id: "poll-loop",
|
|
3019
3129
|
is_trigger: bash_triggers.on_bash_command(is_poll_loop),
|
|
@@ -3063,8 +3173,7 @@ function dispatched_issue(state) {
|
|
|
3063
3173
|
}
|
|
3064
3174
|
function uncut_lane_issue(state) {
|
|
3065
3175
|
const issue = lane_paths.lane_issue_of(state.directory);
|
|
3066
|
-
if (issue === void 0) return void 0;
|
|
3067
|
-
if (dispatched_issue(state) !== issue) return void 0;
|
|
3176
|
+
if (issue === void 0 || dispatched_issue(state) !== issue) return void 0;
|
|
3068
3177
|
return state.carried()?.issue === issue ? void 0 : issue;
|
|
3069
3178
|
}
|
|
3070
3179
|
function warrants_the_cut2(verdict) {
|
|
@@ -3074,7 +3183,7 @@ function is_uncut_gate(command, state = current_state2()) {
|
|
|
3074
3183
|
if (!runs_the_gate(command) || uncut_lane_issue(state) === void 0) return false;
|
|
3075
3184
|
return warrants_the_cut2(state.context_verdict());
|
|
3076
3185
|
}
|
|
3077
|
-
var PRE_GATE_CUT_REASON = "\u26D4 pre-gate cut: this checkout is a lane dispatched for this issue and the gate is the boundary to cut at
|
|
3186
|
+
var PRE_GATE_CUT_REASON = "\u26D4 pre-gate cut: this checkout is a lane dispatched for this issue and the gate is the boundary to cut at. Issue `pnpm josh run:cut <N>`: on `cut`, end the turn immediately \u2014 no Telegram is owed; on any other verdict (`not-a-lane`, `busy`, \u2026), reissue the gate \u2014 this fires once per run (`.claude/skills/workflow-commands/pre-gate-cut.md`).";
|
|
3078
3187
|
function reaches_the_pre_gate_boundary(call, _turn, run2) {
|
|
3079
3188
|
if (!bash_triggers.on_bash_command(asks_about_the_cut)(call)) return false;
|
|
3080
3189
|
return run2.some((issued) => bash_triggers.on_bash_command(claims_the_hold)(issued));
|
|
@@ -3095,7 +3204,7 @@ var RAW_FIELD_BODY_AT = /(?:^|\s)(?:-f|--raw-field)[\s=]+['"]?body=['"]?@/u;
|
|
|
3095
3204
|
function posts_at_path_literally(command) {
|
|
3096
3205
|
return RAW_FIELD_BODY_AT.test(command);
|
|
3097
3206
|
}
|
|
3098
|
-
var RAW_FIELD_BODY_REASON = "\u26D4 literal @path body: this passes `body=@<path>` to `gh api` with a raw field flag (`-f` / `--raw-field`), which
|
|
3207
|
+
var RAW_FIELD_BODY_REASON = "\u26D4 literal @path body: this passes `body=@<path>` to `gh api` with a raw field flag (`-f` / `--raw-field`), which posts the string `@<path>` rather than the file. Post the comment with `pnpm josh issue:comment <N> --body-file <path>`; this rule fires on every occurrence (`prompts/collaboration-workflow/shell-body.md`).";
|
|
3099
3208
|
var ROW17 = {
|
|
3100
3209
|
id: "raw-field-body",
|
|
3101
3210
|
is_trigger: bash_triggers.on_bash_command(posts_at_path_literally),
|
|
@@ -3129,10 +3238,10 @@ function string_field2(input, key) {
|
|
|
3129
3238
|
function read_existing(file_path) {
|
|
3130
3239
|
return file_reader.read_file_or_empty(file_path);
|
|
3131
3240
|
}
|
|
3132
|
-
function texts_of(name, input,
|
|
3241
|
+
function texts_of(name, input, read3) {
|
|
3133
3242
|
if (name === WRITE_TOOL) {
|
|
3134
3243
|
return {
|
|
3135
|
-
old_text:
|
|
3244
|
+
old_text: read3(string_field2(input, "file_path")),
|
|
3136
3245
|
new_text: string_field2(input, "content")
|
|
3137
3246
|
};
|
|
3138
3247
|
}
|
|
@@ -3148,13 +3257,13 @@ function rule_document_input(call) {
|
|
|
3148
3257
|
if (!is_edit_tool2(call.name) || !json_value.is_record(call.input)) return void 0;
|
|
3149
3258
|
return is_rule_document(string_field2(call.input, "file_path")) ? call.input : void 0;
|
|
3150
3259
|
}
|
|
3151
|
-
function writes_rule_prose(call,
|
|
3260
|
+
function writes_rule_prose(call, read3 = read_existing) {
|
|
3152
3261
|
const input = rule_document_input(call);
|
|
3153
3262
|
if (input === void 0) return false;
|
|
3154
|
-
const { old_text, new_text } = texts_of(call.name, input,
|
|
3263
|
+
const { old_text, new_text } = texts_of(call.name, input, read3);
|
|
3155
3264
|
return adds_rule_prose(old_text, new_text);
|
|
3156
3265
|
}
|
|
3157
|
-
var RULE_BODY_REASON = "\u26D4 rule written into prose: this edit adds rule text to CLAUDE.md, a `prompts/**` doc or a skill body.
|
|
3266
|
+
var RULE_BODY_REASON = "\u26D4 rule written into prose: this edit adds rule text to CLAUDE.md, a `prompts/**` doc or a skill body. Answer question 0 (`pnpm josh oracle:list`) and the ordering question (`pnpm josh run:step`) of `prompts/collaboration-workflow/residency.md`; refused until both commands are on the transcript, then reissue this as a trigger-plus-pointer line (`prompts/collaboration-workflow/rule-delivery.md`).";
|
|
3158
3267
|
var PLACEMENT_ORACLES = [
|
|
3159
3268
|
/* @__PURE__ */ new Set(["oracle:list"]),
|
|
3160
3269
|
/* @__PURE__ */ new Set(["run:step", "run:next"])
|
|
@@ -3190,7 +3299,7 @@ var rule_body_guard = {
|
|
|
3190
3299
|
|
|
3191
3300
|
// scripts/rules/shell-body-trigger.ts
|
|
3192
3301
|
var FIELD_FLAGS = "(?:-f|-F|--field|--raw-field)";
|
|
3193
|
-
var MESSAGE_FLAGS = "(?:--body|--notify-message)";
|
|
3302
|
+
var MESSAGE_FLAGS = "(?:--body|--notify-message|--recommended|--alternative)";
|
|
3194
3303
|
var FIELD_OPENING = String.raw`${FIELD_FLAGS}[\s=]*(?:'?body="|"body=)`;
|
|
3195
3304
|
var MESSAGE_OPENING = String.raw`${MESSAGE_FLAGS}[\s=]+"`;
|
|
3196
3305
|
var NESTED_SUBSTITUTION = String.raw`\$\([^()]*\)`;
|
|
@@ -3250,7 +3359,7 @@ function carries_a_body(command) {
|
|
|
3250
3359
|
if (BODY_FLAG.test(command.replaceAll(QUOTED_SPAN, " "))) return true;
|
|
3251
3360
|
return inline_body_literals(command).length > 0;
|
|
3252
3361
|
}
|
|
3253
|
-
var SHELL_BODY_REASON = "\u26D4 shell-evaluated body: this command carries a body inline in double quotes, and that body contains a backtick or a `$`, so the shell
|
|
3362
|
+
var SHELL_BODY_REASON = "\u26D4 shell-evaluated body: this command carries a body inline in double quotes, and that body contains a backtick or a `$`, so the shell executes it. Reissue this call once the body is in a file, passed by path (`pnpm josh issue:comment <N> --body-file <path>`, `--notify-message-file <path>`), or use `$'\u2026'` quoting (`prompts/collaboration-workflow/shell-body.md`).";
|
|
3254
3363
|
var shell_body_trigger = {
|
|
3255
3364
|
SHELL_BODY_REASON,
|
|
3256
3365
|
carries_a_body,
|
|
@@ -3283,9 +3392,9 @@ import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync5 }
|
|
|
3283
3392
|
import path12 from "node:path";
|
|
3284
3393
|
|
|
3285
3394
|
// scripts/safe-chain/pack-hook.ts
|
|
3286
|
-
import { z as
|
|
3395
|
+
import { z as z9 } from "zod";
|
|
3287
3396
|
var PACK_HOOK_FILE = ".pnpmfile.mjs";
|
|
3288
|
-
var manifest_schema2 =
|
|
3397
|
+
var manifest_schema2 = z9.looseObject({ private: z9.boolean().optional() });
|
|
3289
3398
|
var MESSAGES = {
|
|
3290
3399
|
written: ` \u2714 synced ${PACK_HOOK_FILE} (run \`pnpm install\` to refresh pnpmfileChecksum)`,
|
|
3291
3400
|
unchanged: ` \u2714 unchanged ${PACK_HOOK_FILE}`,
|
|
@@ -3321,15 +3430,15 @@ var yaml_document = { is_mapping_document, parse_yaml, parse_yaml_documents };
|
|
|
3321
3430
|
|
|
3322
3431
|
// scripts/version/release-age.ts
|
|
3323
3432
|
import semver from "semver";
|
|
3324
|
-
import { z as
|
|
3325
|
-
var workspace_age_schema =
|
|
3326
|
-
var release_times_schema =
|
|
3433
|
+
import { z as z10 } from "zod";
|
|
3434
|
+
var workspace_age_schema = z10.object({ minimumReleaseAge: z10.number().int().nonnegative() });
|
|
3435
|
+
var release_times_schema = z10.record(z10.string(), z10.string());
|
|
3327
3436
|
|
|
3328
3437
|
// scripts/safe-chain/project-config.ts
|
|
3329
3438
|
import { dump } from "js-yaml";
|
|
3330
|
-
import { z as
|
|
3439
|
+
import { z as z11 } from "zod";
|
|
3331
3440
|
var PROJECT_CONFIG_FILE = ".aikido";
|
|
3332
|
-
var workspace_schema =
|
|
3441
|
+
var workspace_schema = z11.object({ minimumReleaseAgeExclude: z11.array(z11.string()).optional() });
|
|
3333
3442
|
|
|
3334
3443
|
// scripts/config-merge/json-format.ts
|
|
3335
3444
|
var PRINT_WIDTH = 100;
|
|
@@ -3518,8 +3627,9 @@ function patch_deploy_vps_pnpm(content) {
|
|
|
3518
3627
|
PNPM_INSTALL_PATTERN,
|
|
3519
3628
|
(command) => replace_outdated_install(command)
|
|
3520
3629
|
);
|
|
3521
|
-
if (with_pnpm12.includes(VERSION_CHECK_MARKER)
|
|
3522
|
-
|
|
3630
|
+
if (with_pnpm12.includes(VERSION_CHECK_MARKER) || !OLD_PNPM_CHECK_PATTERN.test(with_pnpm12)) {
|
|
3631
|
+
return with_pnpm12;
|
|
3632
|
+
}
|
|
3523
3633
|
return with_pnpm12.replace(OLD_MAJOR_LINE_PATTERN, "").replace(OLD_PNPM_CHECK_PATTERN, (_, indent) => build_version_check(indent));
|
|
3524
3634
|
}
|
|
3525
3635
|
var init_logic_deploy_vps = { patch_deploy_vps_pnpm };
|
|
@@ -4272,11 +4382,11 @@ var init_logic_json_merge = {
|
|
|
4272
4382
|
|
|
4273
4383
|
// scripts/init/kit-development-versions.ts
|
|
4274
4384
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
4275
|
-
import { z as
|
|
4385
|
+
import { z as z12 } from "zod";
|
|
4276
4386
|
var PACKAGE_JSON = "package.json";
|
|
4277
|
-
var kit_manifest_schema =
|
|
4278
|
-
peerDependencies:
|
|
4279
|
-
devDependencies:
|
|
4387
|
+
var kit_manifest_schema = z12.object({
|
|
4388
|
+
peerDependencies: z12.record(z12.string(), z12.string()).default({}),
|
|
4389
|
+
devDependencies: z12.record(z12.string(), z12.string())
|
|
4280
4390
|
});
|
|
4281
4391
|
function read_kit_manifest() {
|
|
4282
4392
|
const content = readFileSync3(package_path(PACKAGE_JSON), "utf8");
|
|
@@ -5133,8 +5243,8 @@ var KEY_LINE_PATTERN = new RegExp(
|
|
|
5133
5243
|
import { findNodeAtLocation as findNodeAtLocation2, getNodeValue as getNodeValue2, parseTree as parseTree3 } from "jsonc-parser";
|
|
5134
5244
|
|
|
5135
5245
|
// scripts/init/vscode-tasks.ts
|
|
5136
|
-
import { z as
|
|
5137
|
-
var task_array_schema =
|
|
5246
|
+
import { z as z13 } from "zod";
|
|
5247
|
+
var task_array_schema = z13.array(json_object_schema);
|
|
5138
5248
|
|
|
5139
5249
|
// scripts/init/init-actions.ts
|
|
5140
5250
|
var BASIC_PRETTIER_CONFIG = "prettier.config.mjs";
|
|
@@ -5461,7 +5571,7 @@ var SKIP_MARKER = "\u2014 skipping";
|
|
|
5461
5571
|
var NOT_USED_MARKER = "which this project does not use";
|
|
5462
5572
|
|
|
5463
5573
|
// scripts/gate/project-checks.ts
|
|
5464
|
-
import { z as
|
|
5574
|
+
import { z as z14 } from "zod";
|
|
5465
5575
|
var PACKAGE_JSON2 = "package.json";
|
|
5466
5576
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
5467
5577
|
"node_modules",
|
|
@@ -5496,7 +5606,7 @@ var CSPELL_CONFIGS = [
|
|
|
5496
5606
|
];
|
|
5497
5607
|
var TYPE_CONFIGS = ["tsconfig.json", "jsconfig.json"];
|
|
5498
5608
|
var DEPENDENCY_FIELDS = ["dependencies", "devDependencies"];
|
|
5499
|
-
var object_schema =
|
|
5609
|
+
var object_schema = z14.record(z14.string(), z14.unknown());
|
|
5500
5610
|
function project_root(directory) {
|
|
5501
5611
|
return ancestor_directories.nearest(
|
|
5502
5612
|
directory,
|
|
@@ -5709,7 +5819,7 @@ function is_untested_commit(call) {
|
|
|
5709
5819
|
if (!run_tail_rule.is_push_step_call(call)) return false;
|
|
5710
5820
|
return test_declared_changed.current_verdict() === "required";
|
|
5711
5821
|
}
|
|
5712
|
-
var REASON =
|
|
5822
|
+
var REASON = "\u26D4 test declared: this commits a runtime code change with no test beside it \u2014 `pnpm josh test:declared` reads it `required` and names the files. Tests are required for ALL code changes: add the test and reissue, or, for a change that touches no runtime path, declare the non-runtime exception in your Step 0 work summary and reissue. It fires once per run (`CLAUDE.md` \u2192 Code Change Rules).";
|
|
5713
5823
|
var ROW19 = { id: "test-declared", is_trigger: is_untested_commit, reason: REASON };
|
|
5714
5824
|
var test_declared_commit = { REASON, ROW: ROW19 };
|
|
5715
5825
|
|
|
@@ -5748,7 +5858,7 @@ function writes_third_party(command, resolve_owner = repo_party.current_owner, r
|
|
|
5748
5858
|
)
|
|
5749
5859
|
);
|
|
5750
5860
|
}
|
|
5751
|
-
var THIRD_PARTY_WRITE_REASON =
|
|
5861
|
+
var THIRD_PARTY_WRITE_REASON = "\u26D4 third-party write: this `gh api` call writes to a repository whose owner is not this session, which is Tier C and needs explicit current-turn user instruction. Check with `pnpm josh repo:party <owner/repo>`, then record the finding on our own Issue and draft the artifact for a person to post. This rule fires on every occurrence (`prompts/collaboration-workflow/upstream-interrupt.md`).";
|
|
5752
5862
|
var ROW20 = {
|
|
5753
5863
|
id: "third-party-write",
|
|
5754
5864
|
is_trigger: bash_triggers.on_bash_command((command) => writes_third_party(command)),
|
|
@@ -5949,8 +6059,8 @@ function format_holder(issue, repo, ages) {
|
|
|
5949
6059
|
function format_holders(issues, repo, ages) {
|
|
5950
6060
|
return issues.map((issue) => format_holder(issue, repo, ages)).join(", ");
|
|
5951
6061
|
}
|
|
5952
|
-
function occupied_lanes(
|
|
5953
|
-
return
|
|
6062
|
+
function occupied_lanes(read3) {
|
|
6063
|
+
return read3.kind === "busy" ? read3.issues.length : 0;
|
|
5954
6064
|
}
|
|
5955
6065
|
function occupancy_message(issues, repo, limit, ages = NO_AGES) {
|
|
5956
6066
|
return `${String(issues.length)} of ${String(limit)} lanes in use in ${repo}: ${format_holders(issues, repo, ages)}.`;
|
|
@@ -5968,18 +6078,18 @@ var BUSY_REASONS = {
|
|
|
5968
6078
|
unreadable: unreadable_message,
|
|
5969
6079
|
truncated: truncated_message
|
|
5970
6080
|
};
|
|
5971
|
-
function busy_reason(
|
|
5972
|
-
if (
|
|
5973
|
-
if (
|
|
5974
|
-
return BUSY_REASONS[
|
|
6081
|
+
function busy_reason(read3, repo, limit, ages = NO_AGES) {
|
|
6082
|
+
if (read3.kind === "busy") return lanes_full_message(read3.issues, repo, limit, ages);
|
|
6083
|
+
if (read3.kind === "idle") return "";
|
|
6084
|
+
return BUSY_REASONS[read3.kind](repo);
|
|
5975
6085
|
}
|
|
5976
6086
|
function is_parked(issue) {
|
|
5977
6087
|
return has_any_label(issue.labels, PARKED_LABELS);
|
|
5978
6088
|
}
|
|
5979
6089
|
function parse_listing(raw, is_capped) {
|
|
5980
|
-
const
|
|
5981
|
-
if (
|
|
5982
|
-
const holders =
|
|
6090
|
+
const read3 = read_json_listing(raw, open_issue_schema);
|
|
6091
|
+
if (read3.kind !== "read") return { kind: "unreadable" };
|
|
6092
|
+
const holders = read3.rows.filter((row) => !is_parked(row));
|
|
5983
6093
|
if (holders.length > 0) return { kind: "busy", issues: holders };
|
|
5984
6094
|
return { kind: is_capped ? "truncated" : "idle" };
|
|
5985
6095
|
}
|
|
@@ -6011,24 +6121,24 @@ import path14 from "node:path";
|
|
|
6011
6121
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
6012
6122
|
|
|
6013
6123
|
// scripts/agent/agent-event.ts
|
|
6014
|
-
import { z as
|
|
6124
|
+
import { z as z16 } from "zod";
|
|
6015
6125
|
|
|
6016
6126
|
// scripts/agent/claude-result-event.ts
|
|
6017
|
-
import { z as
|
|
6018
|
-
var RESULT_EVENT_SCHEMA =
|
|
6019
|
-
type:
|
|
6020
|
-
is_error:
|
|
6021
|
-
subtype:
|
|
6022
|
-
num_turns:
|
|
6023
|
-
permission_denials:
|
|
6024
|
-
result:
|
|
6025
|
-
session_id:
|
|
6026
|
-
usage:
|
|
6127
|
+
import { z as z15 } from "zod";
|
|
6128
|
+
var RESULT_EVENT_SCHEMA = z15.looseObject({
|
|
6129
|
+
type: z15.literal("result"),
|
|
6130
|
+
is_error: z15.unknown().optional(),
|
|
6131
|
+
subtype: z15.unknown().optional(),
|
|
6132
|
+
num_turns: z15.unknown().optional(),
|
|
6133
|
+
permission_denials: z15.unknown().optional(),
|
|
6134
|
+
result: z15.unknown().optional(),
|
|
6135
|
+
session_id: z15.unknown().optional(),
|
|
6136
|
+
usage: z15.unknown().optional()
|
|
6027
6137
|
});
|
|
6028
|
-
var USAGE_SCHEMA =
|
|
6029
|
-
input_tokens:
|
|
6030
|
-
cache_read_input_tokens:
|
|
6031
|
-
output_tokens:
|
|
6138
|
+
var USAGE_SCHEMA = z15.looseObject({
|
|
6139
|
+
input_tokens: z15.unknown().optional(),
|
|
6140
|
+
cache_read_input_tokens: z15.unknown().optional(),
|
|
6141
|
+
output_tokens: z15.unknown().optional()
|
|
6032
6142
|
});
|
|
6033
6143
|
function usable_reason(value) {
|
|
6034
6144
|
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
@@ -6067,31 +6177,31 @@ function decode(value) {
|
|
|
6067
6177
|
var claude_result_event = { decode };
|
|
6068
6178
|
|
|
6069
6179
|
// scripts/agent/agent-event.ts
|
|
6070
|
-
var TEXT_BLOCK_SCHEMA =
|
|
6071
|
-
var CLAUDE_MESSAGE_SCHEMA =
|
|
6072
|
-
var CLAUDE_INIT_SCHEMA =
|
|
6073
|
-
var CLAUDE_ASSISTANT_SCHEMA =
|
|
6074
|
-
type:
|
|
6180
|
+
var TEXT_BLOCK_SCHEMA = z16.looseObject({ type: z16.literal("text"), text: z16.string() });
|
|
6181
|
+
var CLAUDE_MESSAGE_SCHEMA = z16.looseObject({ content: z16.array(z16.unknown()).optional() });
|
|
6182
|
+
var CLAUDE_INIT_SCHEMA = z16.looseObject({ type: z16.literal("system"), subtype: z16.literal("init") });
|
|
6183
|
+
var CLAUDE_ASSISTANT_SCHEMA = z16.looseObject({
|
|
6184
|
+
type: z16.literal("assistant"),
|
|
6075
6185
|
message: CLAUDE_MESSAGE_SCHEMA
|
|
6076
6186
|
});
|
|
6077
|
-
var USAGE_SCHEMA2 =
|
|
6078
|
-
input_tokens:
|
|
6079
|
-
cached_input_tokens:
|
|
6080
|
-
output_tokens:
|
|
6187
|
+
var USAGE_SCHEMA2 = z16.looseObject({
|
|
6188
|
+
input_tokens: z16.number().optional(),
|
|
6189
|
+
cached_input_tokens: z16.number().optional(),
|
|
6190
|
+
output_tokens: z16.number().optional()
|
|
6081
6191
|
});
|
|
6082
|
-
var CODEX_START_SCHEMA =
|
|
6083
|
-
var CODEX_PROGRESS_SCHEMA =
|
|
6084
|
-
type:
|
|
6085
|
-
item:
|
|
6192
|
+
var CODEX_START_SCHEMA = z16.looseObject({ type: z16.enum(["thread.started", "turn.started"]) });
|
|
6193
|
+
var CODEX_PROGRESS_SCHEMA = z16.looseObject({
|
|
6194
|
+
type: z16.enum(["item.started", "item.updated", "item.completed"]),
|
|
6195
|
+
item: z16.looseObject({ type: z16.string(), text: z16.string().optional() }).optional()
|
|
6086
6196
|
});
|
|
6087
|
-
var CODEX_COMPLETE_SCHEMA =
|
|
6088
|
-
type:
|
|
6197
|
+
var CODEX_COMPLETE_SCHEMA = z16.looseObject({
|
|
6198
|
+
type: z16.literal("turn.completed"),
|
|
6089
6199
|
usage: USAGE_SCHEMA2.optional()
|
|
6090
6200
|
});
|
|
6091
|
-
var CODEX_FAILURE_SCHEMA =
|
|
6092
|
-
type:
|
|
6093
|
-
error:
|
|
6094
|
-
message:
|
|
6201
|
+
var CODEX_FAILURE_SCHEMA = z16.looseObject({
|
|
6202
|
+
type: z16.enum(["turn.failed", "error"]),
|
|
6203
|
+
error: z16.looseObject({ message: z16.string().optional() }).optional(),
|
|
6204
|
+
message: z16.string().optional()
|
|
6095
6205
|
});
|
|
6096
6206
|
var EMPTY_STATE = {
|
|
6097
6207
|
provider: void 0,
|
|
@@ -6169,7 +6279,7 @@ function next_state2(line, state) {
|
|
|
6169
6279
|
if (is_header) return EMPTY_STATE;
|
|
6170
6280
|
return normalized(json_value.parse_or_undefined(line), state);
|
|
6171
6281
|
}
|
|
6172
|
-
function
|
|
6282
|
+
function read2(transcript) {
|
|
6173
6283
|
let state = EMPTY_STATE;
|
|
6174
6284
|
for (const line of transcript.split("\n")) state = next_state2(line, state);
|
|
6175
6285
|
return state;
|
|
@@ -6179,10 +6289,10 @@ function describe(state) {
|
|
|
6179
6289
|
const reason = state.reason === void 0 ? "" : ` reason=${state.reason}`;
|
|
6180
6290
|
return `launch=${state.launch} result=${state.result}${progress}${reason}`;
|
|
6181
6291
|
}
|
|
6182
|
-
var agent_event = { describe, read };
|
|
6292
|
+
var agent_event = { describe, read: read2 };
|
|
6183
6293
|
|
|
6184
6294
|
// scripts/issue/issue-state.ts
|
|
6185
|
-
import { z as
|
|
6295
|
+
import { z as z17 } from "zod";
|
|
6186
6296
|
var NO_LABELS = "(none)";
|
|
6187
6297
|
var LABEL_SEPARATOR = ", ";
|
|
6188
6298
|
var STATE_LABEL = "state: ";
|
|
@@ -6192,9 +6302,9 @@ var YES = "yes";
|
|
|
6192
6302
|
var NO = "no";
|
|
6193
6303
|
var ISSUE_LABEL = "issue: ";
|
|
6194
6304
|
var HUMAN_REVIEW_LABELS = /* @__PURE__ */ new Set([NEEDS_HUMAN_REVIEW_LABEL]);
|
|
6195
|
-
var label_schema =
|
|
6196
|
-
var issue_state_schema =
|
|
6197
|
-
state:
|
|
6305
|
+
var label_schema = z17.looseObject({ name: z17.string() });
|
|
6306
|
+
var issue_state_schema = z17.looseObject({
|
|
6307
|
+
state: z17.string(),
|
|
6198
6308
|
labels: label_schema.array().optional()
|
|
6199
6309
|
});
|
|
6200
6310
|
function parse_issue_state(json) {
|
|
@@ -6462,7 +6572,7 @@ var lane_report = {
|
|
|
6462
6572
|
};
|
|
6463
6573
|
|
|
6464
6574
|
// scripts/run/run-preflight.ts
|
|
6465
|
-
import { z as
|
|
6575
|
+
import { z as z18 } from "zod";
|
|
6466
6576
|
var CLEAN_VERDICT = "clean";
|
|
6467
6577
|
var RECLAIM_VERDICT = "reclaim";
|
|
6468
6578
|
var RESUME_VERDICT = "resume";
|
|
@@ -6472,7 +6582,7 @@ var OPEN_PR = "open";
|
|
|
6472
6582
|
var MERGED_PR = "merged";
|
|
6473
6583
|
var CLOSED_PR = "closed";
|
|
6474
6584
|
var NO_CHILD_WORK = { branch_name: void 0, pr_state: NO_PR };
|
|
6475
|
-
var pr_info_schema =
|
|
6585
|
+
var pr_info_schema = z18.object({ state: z18.string().optional() });
|
|
6476
6586
|
var GH_PR_STATES = /* @__PURE__ */ new Map([
|
|
6477
6587
|
["CLOSED", CLOSED_PR],
|
|
6478
6588
|
["MERGED", MERGED_PR],
|
|
@@ -6577,8 +6687,8 @@ async function read_pr_of_branch(branch_name) {
|
|
|
6577
6687
|
return { branch_name, pr_state: await read_pr_state(branch_name) };
|
|
6578
6688
|
}
|
|
6579
6689
|
function pick_child_state(reads) {
|
|
6580
|
-
const decided = reads.find((
|
|
6581
|
-
const open = reads.find((
|
|
6690
|
+
const decided = reads.find((read3) => is_pr_decided(read3.pr_state));
|
|
6691
|
+
const open = reads.find((read3) => is_pr_open(read3.pr_state));
|
|
6582
6692
|
return decided ?? open ?? { branch_name: reads[0]?.branch_name, pr_state: NO_PR };
|
|
6583
6693
|
}
|
|
6584
6694
|
var ISSUE_BRANCH_SUFFIX = "-*";
|
|
@@ -6617,8 +6727,7 @@ async function is_held_dirty(name, lane) {
|
|
|
6617
6727
|
}
|
|
6618
6728
|
async function read_candidate(name, references, context) {
|
|
6619
6729
|
const state = await read_pr_of_branch(name);
|
|
6620
|
-
if (state.pr_state !== NO_PR) return state;
|
|
6621
|
-
if (await has_commits_beyond(context.base, references)) return state;
|
|
6730
|
+
if (state.pr_state !== NO_PR || await has_commits_beyond(context.base, references)) return state;
|
|
6622
6731
|
return await is_held_dirty(name, context.lane) ? state : void 0;
|
|
6623
6732
|
}
|
|
6624
6733
|
async function read_child_state(issue) {
|
|
@@ -6633,7 +6742,7 @@ async function read_child_state(issue) {
|
|
|
6633
6742
|
async ([name, references]) => await read_candidate(name, references, { base, lane })
|
|
6634
6743
|
)
|
|
6635
6744
|
);
|
|
6636
|
-
return pick_child_state(reads.filter((
|
|
6745
|
+
return pick_child_state(reads.filter((read3) => read3 !== void 0));
|
|
6637
6746
|
}
|
|
6638
6747
|
async function check3(issue) {
|
|
6639
6748
|
require_issue_number(issue);
|
|
@@ -6680,10 +6789,10 @@ async function to_child(issue) {
|
|
|
6680
6789
|
return { issue: number, title: issue.title, labels: to_labels(issue), pr_state: child.pr_state };
|
|
6681
6790
|
}
|
|
6682
6791
|
async function read_children(repo) {
|
|
6683
|
-
const
|
|
6684
|
-
if (
|
|
6685
|
-
if (
|
|
6686
|
-
return await Promise.all(
|
|
6792
|
+
const read3 = await epic_busy.read_repository(repo);
|
|
6793
|
+
if (read3.kind === "idle") return [];
|
|
6794
|
+
if (read3.kind !== "busy") return void 0;
|
|
6795
|
+
return await Promise.all(read3.issues.map(async (issue) => await to_child(issue)));
|
|
6687
6796
|
}
|
|
6688
6797
|
async function read_lanes() {
|
|
6689
6798
|
const lanes = await lane_registry.list_lanes();
|
|
@@ -6697,11 +6806,11 @@ function read_record_age(paths, now_ms) {
|
|
|
6697
6806
|
if (times.length === 0) return void 0;
|
|
6698
6807
|
return now_ms - Math.max(...times);
|
|
6699
6808
|
}
|
|
6700
|
-
function is_hold_present(
|
|
6701
|
-
return
|
|
6809
|
+
function is_hold_present(read3) {
|
|
6810
|
+
return read3.kind === "held" || read3.kind === "stale";
|
|
6702
6811
|
}
|
|
6703
|
-
function is_carry_present(
|
|
6704
|
-
return
|
|
6812
|
+
function is_carry_present(read3) {
|
|
6813
|
+
return read3.kind === "carried";
|
|
6705
6814
|
}
|
|
6706
6815
|
function hold_present(worktree) {
|
|
6707
6816
|
return worktree !== void 0 && is_hold_present(run_hold.read_hold(run_hold.hold_path(worktree)));
|
|
@@ -6745,7 +6854,7 @@ var run_progress_read = {
|
|
|
6745
6854
|
};
|
|
6746
6855
|
|
|
6747
6856
|
// scripts/run/run-watcher-hook.ts
|
|
6748
|
-
import { z as
|
|
6857
|
+
import { z as z19 } from "zod";
|
|
6749
6858
|
|
|
6750
6859
|
// scripts/run/run-watcher-guard.ts
|
|
6751
6860
|
var WATCHER_TICK_MS = 3e4;
|
|
@@ -6760,8 +6869,9 @@ async function owes_watcher() {
|
|
|
6760
6869
|
return await lane_registry.has_lanes_in_flight();
|
|
6761
6870
|
}
|
|
6762
6871
|
async function check4(life_target) {
|
|
6763
|
-
if (!await owes_watcher())
|
|
6764
|
-
|
|
6872
|
+
if (!await owes_watcher() || run_progress_clock.is_life_fresh(life_target, STALE_THRESHOLD_MS)) {
|
|
6873
|
+
return OK_RESULT;
|
|
6874
|
+
}
|
|
6765
6875
|
return { kind: "stale", note: STALE_NOTE };
|
|
6766
6876
|
}
|
|
6767
6877
|
var run_watcher_guard = {
|
|
@@ -6773,7 +6883,7 @@ var run_watcher_guard = {
|
|
|
6773
6883
|
// scripts/run/run-watcher-hook.ts
|
|
6774
6884
|
var SWITCH_ENV_KEY2 = "JOSH_WATCHER_GUARD";
|
|
6775
6885
|
var STAMP_PREFIX2 = "josh-watcher-guard-";
|
|
6776
|
-
var payload_schema =
|
|
6886
|
+
var payload_schema = z19.object({ transcript_path: z19.string().min(1) });
|
|
6777
6887
|
function transcript_of(raw_payload) {
|
|
6778
6888
|
return json_value.parse_with(raw_payload, payload_schema)?.transcript_path;
|
|
6779
6889
|
}
|
|
@@ -6810,7 +6920,7 @@ function current_state3() {
|
|
|
6810
6920
|
};
|
|
6811
6921
|
}
|
|
6812
6922
|
var THRESHOLD_TEXT2 = `${cost_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token`;
|
|
6813
|
-
var PARENT_CUT_REASON = `\u26D4 backlogrun parent hand-off: this session drives a \`backlogrun\`
|
|
6923
|
+
var PARENT_CUT_REASON = `\u26D4 backlogrun parent hand-off: this session drives a \`backlogrun\` and its recent-context cost crossed the ${THRESHOLD_TEXT2} threshold between merges. Take the hand-off now: open no new lane, follow \`backlogrun-progress.md\` \u2192 "The hand-off" (\`pnpm josh run:carry --cut --owner "$PPID"\`, then \`pnpm josh run:wake\` unless \`capped\`) and end the turn. Reissue this call once done or if it cannot be taken.`;
|
|
6814
6924
|
async function is_due3(state) {
|
|
6815
6925
|
const carry = await state.carry();
|
|
6816
6926
|
if (carry === void 0 || run_headless.is_cut_capped(carry)) return false;
|
|
@@ -6882,26 +6992,22 @@ function notice(raw_payload, root = process.cwd()) {
|
|
|
6882
6992
|
const transcript = is_candidate2(raw_payload, root);
|
|
6883
6993
|
if (transcript === void 0) return void 0;
|
|
6884
6994
|
const target = STAMP.path(transcript);
|
|
6885
|
-
if (STAMP.last_ms(target) !== hook_decision.NEVER_MS
|
|
6886
|
-
|
|
6995
|
+
if (STAMP.last_ms(target) !== hook_decision.NEVER_MS || !STAMP.record(target, Date.now())) {
|
|
6996
|
+
return void 0;
|
|
6997
|
+
}
|
|
6887
6998
|
return NOTICE;
|
|
6888
6999
|
}
|
|
6889
7000
|
var step_zero_notice = { NOTICE, notice, stamp_path: STAMP.path };
|
|
6890
7001
|
|
|
6891
7002
|
// scripts/hooks/pretool-guard.ts
|
|
6892
|
-
|
|
6893
|
-
if (batch.reason !== void 0) return batch;
|
|
6894
|
-
if (extra_reason !== void 0) {
|
|
6895
|
-
return { reason: extra_reason, notice: void 0, fault: void 0 };
|
|
6896
|
-
}
|
|
6897
|
-
return batch;
|
|
6898
|
-
}
|
|
7003
|
+
var CLEAR = { reason: void 0, notice: void 0, fault: void 0 };
|
|
6899
7004
|
function is_clear(outcome) {
|
|
6900
7005
|
return outcome.reason === void 0 && outcome.notice === void 0 && outcome.fault === void 0;
|
|
6901
7006
|
}
|
|
6902
|
-
function
|
|
6903
|
-
|
|
6904
|
-
|
|
7007
|
+
function combine_outcomes(outcomes, rule_reason) {
|
|
7008
|
+
const reason = outcomes.find((outcome) => outcome.reason !== void 0)?.reason ?? rule_reason;
|
|
7009
|
+
if (reason !== void 0) return { reason, notice: void 0, fault: void 0 };
|
|
7010
|
+
return outcomes.find((outcome) => !is_clear(outcome)) ?? CLEAR;
|
|
6905
7011
|
}
|
|
6906
7012
|
function with_step_zero_notice(outcome, raw_payload) {
|
|
6907
7013
|
if (!is_clear(outcome)) return outcome;
|
|
@@ -6909,13 +7015,12 @@ function with_step_zero_notice(outcome, raw_payload) {
|
|
|
6909
7015
|
return notice2 === void 0 ? outcome : { reason: void 0, notice: notice2, fault: void 0 };
|
|
6910
7016
|
}
|
|
6911
7017
|
function guard_outcome(raw_payload) {
|
|
6912
|
-
const
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
return with_duplicate_notice(combined, duplicate.notice);
|
|
7018
|
+
const outcomes = [
|
|
7019
|
+
batch_outcome(raw_payload),
|
|
7020
|
+
investigation_outcome(raw_payload),
|
|
7021
|
+
duplicate_read_outcome(raw_payload)
|
|
7022
|
+
];
|
|
7023
|
+
return combine_outcomes(outcomes, delivered_rules.delivery(raw_payload));
|
|
6919
7024
|
}
|
|
6920
7025
|
function pretool_outcome(raw_payload) {
|
|
6921
7026
|
return with_step_zero_notice(guard_outcome(raw_payload), raw_payload);
|
|
@@ -6968,7 +7073,7 @@ function pipefail_rewrite(raw_payload) {
|
|
|
6968
7073
|
}
|
|
6969
7074
|
function pipefail_envelope(outcome, input) {
|
|
6970
7075
|
if (input === void 0 || outcome.reason !== void 0) return void 0;
|
|
6971
|
-
return hook_decision.
|
|
7076
|
+
return hook_decision.flow_rewrite_envelope(
|
|
6972
7077
|
input,
|
|
6973
7078
|
rewrite_context(piped_verification.PIPEFAIL_NOTE, outcome)
|
|
6974
7079
|
);
|