@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.
Files changed (84) hide show
  1. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
  2. package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -4
  3. package/.claude/skills/workflow-commands/retrospective.md +1 -2
  4. package/dist/hooks/batch-guard.js +6 -6
  5. package/dist/hooks/{chunk-RW4XMF47.js → chunk-2YSW3CXH.js} +133 -234
  6. package/dist/hooks/{chunk-4RWRP3FF.js → chunk-DCY2GWHC.js} +5 -5
  7. package/dist/hooks/{chunk-DHSKBAQ2.js → chunk-EAQEGME7.js} +1 -1
  8. package/dist/hooks/{chunk-E7LZL5AN.js → chunk-EBSHN25W.js} +3 -3
  9. package/dist/hooks/{chunk-HGA4EG5S.js → chunk-GJ7JPIHN.js} +15 -15
  10. package/dist/hooks/{chunk-TG2AB3W6.js → chunk-GNDJ7NJ7.js} +88 -501
  11. package/dist/hooks/{chunk-546X4PX3.js → chunk-IYVOLN6A.js} +3 -3
  12. package/dist/hooks/{chunk-NBEAGPS4.js → chunk-J3KSS7II.js} +1 -1
  13. package/dist/hooks/{chunk-7ZM464OW.js → chunk-LMWBRJIP.js} +3 -3
  14. package/dist/hooks/{chunk-TORRSNDJ.js → chunk-SL4GQ2XP.js} +3 -3
  15. package/dist/hooks/{chunk-PV3FWDSQ.js → chunk-STDSEPWU.js} +2 -2
  16. package/dist/hooks/{chunk-YSDAH73S.js → chunk-U32VSRNG.js} +420 -4
  17. package/dist/hooks/{chunk-QARPP36N.js → chunk-WNFJLBXI.js} +3 -3
  18. package/dist/hooks/codex-hook-adapter.js +13 -13
  19. package/dist/hooks/duplicate-read-guard.js +7 -7
  20. package/dist/hooks/format-edited.js +3 -3
  21. package/dist/hooks/inputs.json +213 -212
  22. package/dist/hooks/investigation-guard.js +7 -7
  23. package/dist/hooks/pretool-guard.js +12 -12
  24. package/dist/hooks/session-lang.js +65 -9
  25. package/dist/hooks/stop-guard.js +104 -32
  26. package/dist/josh.js +2 -2
  27. package/package.json +1 -1
  28. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  29. package/scripts/backlog/backlog-budget-cli.ts +2 -20
  30. package/scripts/backlog/backlog-budget.ts +72 -109
  31. package/scripts/backlog/backlog-drive-cli.ts +12 -7
  32. package/scripts/backlog/backlog-drive-launch.ts +2 -0
  33. package/scripts/backlog/backlog-drive-owner.ts +72 -5
  34. package/scripts/backlog/backlog-drive.ts +5 -2
  35. package/scripts/backlog/backlog-offer-cli.ts +1 -15
  36. package/scripts/backlog/backlogrun-launch.ts +56 -5
  37. package/scripts/document/document-byte-budget.ts +1 -1
  38. package/scripts/epic/epic-candidate-confirm.ts +1 -1
  39. package/scripts/epic/epic-cross-repo.ts +4 -4
  40. package/scripts/epic/epic-next.ts +1 -1
  41. package/scripts/hooks/stop-guard.ts +20 -9
  42. package/scripts/init/start-plan.ts +15 -4
  43. package/scripts/init/start-steps.ts +31 -3
  44. package/scripts/init/start.ts +20 -13
  45. package/scripts/josh/josh-commands-ai.ts +1 -1
  46. package/scripts/josh/josh-commands-project.ts +1 -1
  47. package/scripts/lane/lane-cli.ts +1 -3
  48. package/scripts/run/board/run-board-header.ts +137 -88
  49. package/scripts/run/board/run-board-labels.ts +18 -17
  50. package/scripts/run/board/run-board-machine.ts +21 -8
  51. package/scripts/run/board/run-board-read.ts +9 -2
  52. package/scripts/run/board/run-board-render.ts +1 -5
  53. package/scripts/run/board/run-board-setup.ts +73 -0
  54. package/scripts/run/board/run-board-span.ts +49 -8
  55. package/scripts/run/board/run-board-status.ts +10 -23
  56. package/scripts/run/board/run-board-tick.ts +11 -2
  57. package/scripts/run/carry/run-carry-added.ts +1 -1
  58. package/scripts/run/carry/run-carry-change.ts +1 -1
  59. package/scripts/run/carry/run-carry-cli.ts +36 -60
  60. package/scripts/run/carry/run-carry-ended.ts +10 -2
  61. package/scripts/run/carry/run-carry.ts +38 -68
  62. package/scripts/run/cut/run-cut.ts +4 -4
  63. package/scripts/run/event/run-event-render.ts +1 -1
  64. package/scripts/run/event/run-event-scope.ts +4 -8
  65. package/scripts/run/event/run-event-setup.ts +47 -0
  66. package/scripts/run/event/run-event-stream-emit.ts +0 -25
  67. package/scripts/run/event/run-event-stream.ts +41 -28
  68. package/scripts/run/merge/run-merge-collect.ts +1 -1
  69. package/scripts/run/merge/run-merge-steps.ts +1 -1
  70. package/scripts/run/progress/run-progress-read.ts +1 -1
  71. package/scripts/run/run-headless.ts +2 -2
  72. package/scripts/run/run-status-cli.ts +1 -5
  73. package/scripts/run/run-step.ts +2 -9
  74. package/scripts/run/run-stop-notify.ts +1 -1
  75. package/scripts/run/run-stranded-detect.ts +61 -15
  76. package/scripts/run/run-stranded.ts +25 -17
  77. package/scripts/run/wake/run-wake-cli.ts +58 -15
  78. package/scripts/run/wake/run-wake-describe.ts +5 -5
  79. package/scripts/run/wake/run-wake-driver.ts +13 -4
  80. package/scripts/run/wake/run-wake-handoff.ts +1 -1
  81. package/scripts/run/wake/run-wake-loop.ts +4 -21
  82. package/scripts/run/wake/run-wake-restart.ts +1 -1
  83. package/scripts/run/wake/run-wake.ts +6 -7
  84. package/scripts/backlog/backlog-idle.ts +0 -88
@@ -6,17 +6,23 @@ import {
6
6
  agent_role_profile,
7
7
  detached_launch,
8
8
  git_common_directory,
9
+ issue_cite,
10
+ run_event_stream,
11
+ run_event_stream_emit,
9
12
  run_headless
10
- } from "./chunk-YSDAH73S.js";
13
+ } from "./chunk-U32VSRNG.js";
14
+ import {
15
+ error_text
16
+ } from "./chunk-CDY4NFQG.js";
11
17
  import {
12
18
  josh_environment_file
13
- } from "./chunk-NBEAGPS4.js";
19
+ } from "./chunk-J3KSS7II.js";
14
20
  import {
15
21
  agent_session_environment,
16
22
  json_value,
17
23
  process_identity,
18
24
  run_carry
19
- } from "./chunk-RW4XMF47.js";
25
+ } from "./chunk-2YSW3CXH.js";
20
26
  import {
21
27
  stamp_file
22
28
  } from "./chunk-NEC4AT4Z.js";
@@ -298,6 +304,32 @@ var agent_argv = {
298
304
  with_resume_in
299
305
  };
300
306
 
307
+ // scripts/run/event/run-event-setup.ts
308
+ var STAGE = {
309
+ // `josh backlogrun` started the parent session, which is reading its procedure.
310
+ STARTING: "starting session",
311
+ // `run:carry --begin` claimed the run, and the parent is planning it.
312
+ PLANNING: "planning",
313
+ // The supervisor took the run over from the parent and is asking for the first offer.
314
+ HANDING_OFF: "handing off"
315
+ };
316
+ var OPENING = "opening lane";
317
+ function opening_lane(issue) {
318
+ return `${OPENING} ${issue_cite.plain(issue)}`;
319
+ }
320
+ async function emit(text) {
321
+ await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.SETUP, text);
322
+ }
323
+ function emit_in(repository, text, at) {
324
+ try {
325
+ const target = run_event_stream.target_of(repository);
326
+ run_event_stream.append(target, run_event_stream.EVENT_KIND.SETUP, text, at.toISOString());
327
+ } catch (error) {
328
+ error_text.trace_swallowed("run_event_setup.emit_in", error);
329
+ }
330
+ }
331
+ var run_event_setup = { STAGE, emit, emit_in, opening_lane };
332
+
301
333
  // scripts/backlog/backlogrun-launch.ts
302
334
  import { z } from "zod";
303
335
  var LAUNCH_PREFIX = "josh-backlogrun-launch-";
@@ -306,7 +338,11 @@ var LOG_SUFFIX = ".log";
306
338
  var launch_schema = z.object({
307
339
  pid: z.number(),
308
340
  start: z.string().optional(),
309
- session: z.string().optional()
341
+ session: z.string().optional(),
342
+ // What the parent was started to run and when, so `run:board` has a run to draw and a clock to count
343
+ // before the parent claims the carry record. Absent on a record an earlier version wrote.
344
+ invocation: z.string().optional(),
345
+ started_at: z.string().optional()
310
346
  });
311
347
  function launch_path(git_directory) {
312
348
  return stamp_file.stamp_path(LAUNCH_PREFIX, git_directory);
@@ -348,9 +384,27 @@ function argv_of(invocation, provider, worktree, session) {
348
384
  function note_to_stderr(note) {
349
385
  console.error(`backlogrun: ${note}`);
350
386
  }
351
- function record_launch(git_directory, pid, session) {
352
- const started = process_identity.read_start(pid);
353
- stamp_file.replace_stamp(launch_path(git_directory), { pid, start: started, session });
387
+ function record_launch(git_directory, launch) {
388
+ const now = /* @__PURE__ */ new Date();
389
+ const identity = process_identity.read_start(launch.pid);
390
+ const record = { ...launch, start: identity, started_at: now.toISOString() };
391
+ stamp_file.replace_stamp(launch_path(git_directory), record);
392
+ run_event_setup.emit_in(git_directory, run_event_setup.STAGE.STARTING, now);
393
+ }
394
+ function live_launch(git_directory) {
395
+ const record = read_launch(launch_path(git_directory));
396
+ return is_launch_live(record) ? record : void 0;
397
+ }
398
+ function pending_launch(git_directory) {
399
+ const { invocation, started_at } = live_launch(git_directory) ?? {};
400
+ if (invocation === void 0 || started_at === void 0) return void 0;
401
+ return { invocation, started_at };
402
+ }
403
+ function started_for(git_directory, owner_pid) {
404
+ const record = live_launch(git_directory);
405
+ if (record?.started_at === void 0 || record.pid !== owner_pid) return void 0;
406
+ const started_ms = Date.parse(record.started_at);
407
+ return Number.isNaN(started_ms) ? void 0 : new Date(started_ms);
354
408
  }
355
409
  function spawn_parent(argv, provider, target) {
356
410
  const environment = {
@@ -376,7 +430,7 @@ function start(invocation, provider, target) {
376
430
  if (built.kind === "rejected") return { kind: "failed", note: built.note };
377
431
  const result = spawn_parent(built, provider, target);
378
432
  if (result.kind === "failed") return result;
379
- record_launch(target.git_directory, result.pid, session);
433
+ record_launch(target.git_directory, { pid: result.pid, session, invocation });
380
434
  const launched = { pid: result.pid, session, log_path: log_path(target.git_directory) };
381
435
  return { kind: "launched", launched };
382
436
  }
@@ -384,7 +438,9 @@ var backlogrun_launch = {
384
438
  argv_of,
385
439
  chosen_environment,
386
440
  is_running,
387
- start
441
+ pending_launch,
442
+ start,
443
+ started_for
388
444
  };
389
445
 
390
446
  // scripts/josh/session-language-cli.ts
@@ -13,10 +13,8 @@ import {
13
13
  lane_park,
14
14
  repo_party,
15
15
  run_cut,
16
- run_event_stream,
17
- run_event_stream_emit,
18
16
  run_hold
19
- } from "./chunk-TG2AB3W6.js";
17
+ } from "./chunk-GNDJ7NJ7.js";
20
18
  import {
21
19
  session_language
22
20
  } from "./chunk-6V5OPIUU.js";
@@ -25,23 +23,25 @@ import {
25
23
  agent_role_profile,
26
24
  issue_cite,
27
25
  lane_registry,
26
+ run_event_stream,
27
+ run_event_stream_emit,
28
28
  run_headless
29
- } from "./chunk-YSDAH73S.js";
29
+ } from "./chunk-U32VSRNG.js";
30
30
  import {
31
31
  timed_fetch
32
32
  } from "./chunk-FZ6FUSBM.js";
33
33
  import "./chunk-CDY4NFQG.js";
34
34
  import {
35
35
  hook_decision
36
- } from "./chunk-E7LZL5AN.js";
36
+ } from "./chunk-EBSHN25W.js";
37
37
  import {
38
38
  time_density_hook,
39
39
  time_hook_transcript,
40
40
  time_reported_failure
41
- } from "./chunk-TORRSNDJ.js";
41
+ } from "./chunk-SL4GQ2XP.js";
42
42
  import {
43
43
  lane_child_marker
44
- } from "./chunk-NBEAGPS4.js";
44
+ } from "./chunk-J3KSS7II.js";
45
45
  import {
46
46
  backlog_budget,
47
47
  issue_number_shape,
@@ -50,7 +50,7 @@ import {
50
50
  process_owner_schema,
51
51
  run_carry,
52
52
  run_invocation
53
- } from "./chunk-RW4XMF47.js";
53
+ } from "./chunk-2YSW3CXH.js";
54
54
  import {
55
55
  PROJECT_ROOT,
56
56
  stamp_file
@@ -964,8 +964,53 @@ var run_halfrun_resume = {
964
964
  take_over
965
965
  };
966
966
 
967
- // scripts/run/wake/run-wake.ts
967
+ // scripts/run/carry/run-carry-ended.ts
968
+ import path from "node:path";
968
969
  import { z as z4 } from "zod";
970
+ var ENDED_PREFIX = "josh-run-ended-";
971
+ var TRANSCRIPT_SUFFIX = ".jsonl";
972
+ var ended_run_schema = z4.object({
973
+ invocation: z4.string(),
974
+ started_at: z4.string(),
975
+ ended_at: z4.string(),
976
+ stopped: z4.string().optional(),
977
+ session: z4.string().optional()
978
+ });
979
+ function ended_path(git_directory) {
980
+ return stamp_file.stamp_path(ENDED_PREFIX, git_directory);
981
+ }
982
+ function session_of(transcript) {
983
+ return transcript === void 0 ? void 0 : path.basename(transcript, TRANSCRIPT_SUFFIX);
984
+ }
985
+ function stop_of(transcript, stopped) {
986
+ return stopped === void 0 ? {} : { stopped, session: session_of(transcript) };
987
+ }
988
+ function record_ended(target, read, now = /* @__PURE__ */ new Date(), stopped) {
989
+ if (read.kind !== "carried") return;
990
+ const { invocation, started_at, owner_transcript } = read.carry;
991
+ const ended_at = now.toISOString();
992
+ stamp_file.replace_stamp(target, {
993
+ invocation,
994
+ started_at,
995
+ ended_at,
996
+ ...stop_of(owner_transcript, stopped)
997
+ });
998
+ }
999
+ function parse_ended(raw) {
1000
+ return json_value.parse_with(raw, ended_run_schema);
1001
+ }
1002
+ function read_ended(target) {
1003
+ const raw = stamp_file.read_stamp_text(target);
1004
+ return raw === void 0 ? void 0 : parse_ended(raw);
1005
+ }
1006
+ function has_ended(target, started_at) {
1007
+ const ended = read_ended(target);
1008
+ return ended !== void 0 && ended.started_at === started_at;
1009
+ }
1010
+ var run_carry_ended = { ended_path, has_ended, read_ended, record_ended };
1011
+
1012
+ // scripts/run/wake/run-wake.ts
1013
+ import { z as z5 } from "zod";
969
1014
  var WAKE_PREFIX = "josh-run-wake-";
970
1015
  var WAKE_LOG_PREFIX = "josh-run-wake-log-";
971
1016
  var WAKE_LOG_SUFFIX = ".log";
@@ -981,19 +1026,18 @@ var PENDING_DECISION = { kind: "pending" };
981
1026
  var FAILED_DECISION = { kind: "failed" };
982
1027
  var STOP_REASONS = {
983
1028
  none: "ended",
984
- expired: "expired",
985
1029
  unreadable: "unreadable"
986
1030
  };
987
1031
  var run_wake_schema = process_owner_schema.extend({
988
- invocation: z4.string(),
989
- started_at: z4.string(),
990
- woke: z4.number(),
991
- woke_at: z4.string().optional(),
1032
+ invocation: z5.string(),
1033
+ started_at: z5.string(),
1034
+ woke: z5.number(),
1035
+ woke_at: z5.string().optional(),
992
1036
  // Every optional `RunWake` field must be listed: `z.object` strips undeclared ones on the round trip.
993
- attempts: z4.number().optional(),
994
- woke_pid: z4.number().optional(),
995
- spawned: z4.array(z4.string()).optional(),
996
- idle_since: z4.string().optional(),
1037
+ attempts: z5.number().optional(),
1038
+ woke_pid: z5.number().optional(),
1039
+ spawned: z5.array(z5.string()).optional(),
1040
+ idle_since: z5.string().optional(),
997
1041
  profile: agent_role_profile.PROFILE_SCHEMA.optional()
998
1042
  });
999
1043
  function is_overdue(marked_at, now, limit_ms = WAKE_GRACE_MS) {
@@ -1157,14 +1201,17 @@ function supervisor_liveness(wake, same_process = process_identity.is_same_proce
1157
1201
  if (is_same === void 0) return UNKNOWN;
1158
1202
  return is_same ? LIVE : GONE;
1159
1203
  }
1204
+ function had_driver(carry) {
1205
+ return carry.is_handed_off === true || carry.owner_pid !== void 0;
1206
+ }
1160
1207
  function is_stranded(input) {
1161
- if (input.read.kind !== "carried" || input.read.carry.is_handed_off !== true || input.is_owner_live) {
1208
+ if (input.read.kind !== "carried" || input.is_owner_live || !had_driver(input.read.carry)) {
1162
1209
  return false;
1163
1210
  }
1164
1211
  return input.supervisor === GONE;
1165
1212
  }
1166
1213
  function describe2(carry) {
1167
- return `Run stranded \u2014 ${run_carry.describe_carry(carry)}. The owner is gone, no cut successor claimed the budget, and no supervisor is watching.`;
1214
+ return `Run stranded \u2014 ${run_carry.describe_carry(carry)}. The owner is gone, no successor holds the budget, and no supervisor is watching.`;
1168
1215
  }
1169
1216
  function verdict_of(is_run_stranded) {
1170
1217
  return is_run_stranded ? STRANDED : OK2;
@@ -1184,10 +1231,12 @@ var run_stranded = {
1184
1231
 
1185
1232
  // scripts/run/run-stranded-detect.ts
1186
1233
  var STRAND_RECOVERY = `Restart supervision with \`${run_stranded.RECOVERY_COMMAND}\` \u2014 it wakes a fresh successor to claim the budget; the cutting session must not resume it itself.`;
1234
+ function targets_of(directory) {
1235
+ return { carry: run_carry.carry_path(directory), wake: run_wake.wake_path(directory) };
1236
+ }
1187
1237
  async function real_resolve_targets() {
1188
1238
  const directory = await run_carry.repository_directory();
1189
- if (directory === void 0) return void 0;
1190
- return { carry: run_carry.carry_path(directory), wake: run_wake.wake_path(directory) };
1239
+ return directory === void 0 ? void 0 : targets_of(directory);
1191
1240
  }
1192
1241
  async function real_emit_stranded(text2) {
1193
1242
  return await run_event_stream_emit.emit_once(run_event_stream.EVENT_KIND.STRANDED, text2);
@@ -1199,14 +1248,13 @@ var DEFAULT_PORTS3 = {
1199
1248
  resolve_targets: real_resolve_targets,
1200
1249
  read_carry: (target) => run_carry.read_carry(target),
1201
1250
  is_owner_live: run_carry.is_owner_live,
1251
+ has_ended: run_carry_ended.has_ended,
1202
1252
  read_wake: (target) => run_wake.read_wake(target),
1203
1253
  supervisor_liveness: (wake) => run_stranded.supervisor_liveness(wake),
1204
1254
  emit_stranded: real_emit_stranded,
1205
1255
  notify_stranded: real_notify_stranded
1206
1256
  };
1207
- async function gather2(ports) {
1208
- const targets = await ports.resolve_targets();
1209
- if (targets === void 0) return void 0;
1257
+ function input_at(ports, targets) {
1210
1258
  const read = ports.read_carry(targets.carry);
1211
1259
  if (read.kind !== "carried") return void 0;
1212
1260
  return {
@@ -1215,6 +1263,10 @@ async function gather2(ports) {
1215
1263
  supervisor: ports.supervisor_liveness(ports.read_wake(targets.wake))
1216
1264
  };
1217
1265
  }
1266
+ async function gather2(ports) {
1267
+ const targets = await ports.resolve_targets();
1268
+ return targets === void 0 ? void 0 : input_at(ports, targets);
1269
+ }
1218
1270
  async function report2(ports, input) {
1219
1271
  if (input.read.kind !== "carried") return;
1220
1272
  const text2 = run_stranded.describe(input.read.carry);
@@ -1233,7 +1285,25 @@ async function run_stranded_check() {
1233
1285
  } catch {
1234
1286
  }
1235
1287
  }
1236
- var run_stranded_detect = { detect_and_report: detect_and_report2, run_stranded_check };
1288
+ function is_stranded_at(directory, ports = DEFAULT_PORTS3) {
1289
+ const input = input_at(ports, targets_of(directory));
1290
+ return input !== void 0 && run_stranded.is_stranded(input);
1291
+ }
1292
+ function is_left_stranded(run, ports = DEFAULT_PORTS3) {
1293
+ const read = ports.read_carry(run.carry_target);
1294
+ if (read.kind !== "carried") return !ports.has_ended(run.ended_target, run.started_at);
1295
+ return run_stranded.is_stranded({
1296
+ read,
1297
+ is_owner_live: run_carry.is_held_by_another(read.carry, ports.is_owner_live),
1298
+ supervisor: run_stranded.GONE
1299
+ });
1300
+ }
1301
+ var run_stranded_detect = {
1302
+ detect_and_report: detect_and_report2,
1303
+ is_left_stranded,
1304
+ is_stranded_at,
1305
+ run_stranded_check
1306
+ };
1237
1307
 
1238
1308
  // scripts/hooks/stop-guard.ts
1239
1309
  async function hold_facts() {
@@ -1295,18 +1365,20 @@ async function outcome_of(raw_payload) {
1295
1365
  return stop_rules.NO_OUTCOME;
1296
1366
  }
1297
1367
  }
1298
- async function has_run_record() {
1368
+ async function carried_owner_live() {
1299
1369
  try {
1300
1370
  const directory = await run_carry.repository_directory();
1301
- if (directory === void 0) return false;
1302
- return run_carry.read_carry(run_carry.carry_path(directory)).kind === "carried";
1371
+ if (directory === void 0) return void 0;
1372
+ const read = run_carry.read_carry(run_carry.carry_path(directory));
1373
+ return read.kind === "carried" ? run_carry.is_owner_live(read.carry) : void 0;
1303
1374
  } catch {
1304
- return false;
1375
+ return void 0;
1305
1376
  }
1306
1377
  }
1307
1378
  async function run_report_checks() {
1308
- if (!await has_run_record()) return;
1309
- await backlog_stalled_detect.run_stall_check(backlog_ready.DEFAULT_PORTS);
1379
+ const is_owner_live = await carried_owner_live();
1380
+ if (is_owner_live === void 0) return;
1381
+ if (is_owner_live) await backlog_stalled_detect.run_stall_check(backlog_ready.DEFAULT_PORTS);
1310
1382
  await run_stranded_detect.run_stranded_check();
1311
1383
  }
1312
1384
  async function write_stop_decision(raw_payload) {
package/dist/josh.js CHANGED
@@ -1867,7 +1867,7 @@ var AI_COMMANDS = {
1867
1867
  // `.env` rather than the ambient environment: the strand notification needs the Telegram
1868
1868
  // credentials, the same reason `run:wake` carries these flags.
1869
1869
  tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
1870
- description: "Report whether the run is stranded \u2014 budget handed off, owner gone, and no supervisor watching",
1870
+ description: "Report whether the run is stranded \u2014 owner gone, no successor holding the budget, and no supervisor watching",
1871
1871
  category: "AI tools",
1872
1872
  reference: ["", "automation", ["processes", "notifications"]]
1873
1873
  },
@@ -2501,7 +2501,7 @@ var PROJECT_COMMANDS = {
2501
2501
  description: "Set a project up for the GitHub Issue workflow, from git init to the setup PR",
2502
2502
  category: "Project",
2503
2503
  reference: [
2504
- `${PROFILE_ARGUMENTS} [--yes] [--github] [--public] [--init-command <command>]`,
2504
+ `${PROFILE_ARGUMENTS} [--yes] [--github] [--public] [--init-command <command>] [--push-preflight-command <command>]`,
2505
2505
  "developer",
2506
2506
  ["files", "git", "network", "processes"]
2507
2507
  ]
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1379.0",
2
+ "version": "1.1387.0",
3
3
  "name": "@joshuafolkken/kit",
4
4
  "description": "Development toolkit for AI-assisted projects: formatting, AI assistant rules and a Git/GitHub Issue workflow for any repository, plus lint, type check, tests and hooks for Node projects",
5
5
  "keywords": [
@@ -18,7 +18,7 @@
18
18
  1. **起票する** — `pnpm josh issue:file "<title>" --body-file <path> --depth <n> --route interrupt --label priority:high`。上限は効かない(`wip-cap.md` →「割り込み起票 — 上限が効かない側」の条件 2)
19
19
  2. **止まらずに直す** — 壊れた機構を迂回しない(回避策の禁止と、検証ゲートを緩めない規則はここでも変わらない)。`backlogrun` の中では、その割り込みを次の子にし、修正が着地してから塞がれていた子へ戻る。プールから選ぶランでは `priority:high` が先頭に並べ、epic の下では `wip-cap.md` の手順 3 で挿入する。名前を指定したランのドライバーは指定された Issue しか出さないので、`pnpm josh lane:launch <N>` で自分で dispatch する。バッチの外では `wip-cap.md` の手順 4 が変わらず効く — 起票まで済ませ、打つべき `fullrun #<N>` を報告して止まる
20
20
  3. **再開できるなら自分で再開し、動くことを確かめる** — 修正のマージ後、再開の手段がある答えには人の打ち直しを求めない。手渡し済みの記録、所有者が死んだ記録、監督プロセスの停止(`warning` Telegram)には `pnpm josh run:wake --start`、`run:carry` の `standing` には `pnpm josh run:carry --resume "<invocation>" --owner "$PPID"` を自分で打つ。そのあと `pnpm josh run:wake --list` が監督プロセスを示し、そのログに次の子の dispatch が現れることを確かめて報告する
21
- 4. **人に打ち直しを求めるのは再開の手段が無いときだけ** — `expired`(8 時間の上限を使い切った)、`mismatch`(別の起動の記録)、別の生きた所有者の `busy`。新しい承認を宣言するのは人だけ、という規則も変わらない
21
+ 4. **人に打ち直しを求めるのは再開の手段が無いときだけ** — `mismatch`(別の起動の記録)、別の生きた所有者の `busy`。新しい承認を宣言するのは人だけ、という規則も変わらない
22
22
  5. **`needs-decision` を付けない** — ランが自分で直せる不具合は人の判断を要さない(`.claude/skills/workflow-commands/backlogrun-park.md` → "Only a person's judgement carries `needs-decision`")
23
23
 
24
24
  手順:
@@ -8,7 +8,6 @@ import {
8
8
  type BudgetDecision,
9
9
  type BudgetInput,
10
10
  } from './backlog-budget'
11
- import { backlog_idle } from './backlog-idle'
12
11
 
13
12
  // The thin half of `josh backlog:budget` (joshuafolkken/kit#1632): read the loop's state off the
14
13
  // command line, hand it to the pure decision, print the verdict on stdout and the reason on stderr
@@ -18,7 +17,6 @@ const ARGV_OFFSET = 2
18
17
  const SUCCESS_EXIT_CODE = 0
19
18
  const FAILURE_EXIT_CODE = 1
20
19
  const JSON_KEY = 'budget'
21
- const EXHAUSTED_ANSWER: BacklogAnswer = 'exhausted'
22
20
 
23
21
  const 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]`
24
22
 
@@ -71,7 +69,7 @@ function to_count(raw: string | undefined): number | undefined {
71
69
 
72
70
  // A flag that was given but could not be read makes the whole invocation unreadable. Falling back to
73
71
  // the default instead would answer a question nobody asked — a mistyped `--idle 0` would read as the
74
- // default 30-minute watch and hold a run open that was asked to finish at its first empty backlog.
72
+ // default watch and hold a run open that was asked to finish at its first empty backlog.
75
73
  function is_readable(raw: string | undefined, parsed: number | undefined): boolean {
76
74
  return raw === undefined || parsed !== undefined
77
75
  }
@@ -165,27 +163,11 @@ function build_input(values: ParsedValues, now_ms: number): BudgetInput | undefi
165
163
  return input_of(values, { answer, now_ms, started_at_ms })
166
164
  }
167
165
 
168
- // The idle window, carried only on the watch an empty backlog opens — the one `idle_decision` reaches,
169
- // not the draining watch a reached bound returns while children still run — so `backlog:offer` can
170
- // record when that wait ends (joshuafolkken/kit#3430).
171
- function idle_of(input: BudgetInput, verdict: string): string | undefined {
172
- const is_idle_watch =
173
- verdict === backlog_budget.WATCH_VERDICT &&
174
- input.answer === EXHAUSTED_ANSWER &&
175
- backlog_budget.is_finish(input)
176
- const window = is_idle_watch ? backlog_idle.window_of(input) : undefined
177
-
178
- return window === undefined ? undefined : backlog_idle.text_of(window)
179
- }
180
-
181
166
  function print_json(input: BudgetInput, decision: BudgetDecision): void {
182
167
  const { verdict, reason } = decision
183
- const idle = idle_of(input, verdict)
184
168
  const is_finish = backlog_budget.is_finish(input)
185
169
 
186
- console.info(
187
- JSON.stringify({ [JSON_KEY]: verdict, reason, is_finish, ...(idle !== undefined && { idle }) }),
188
- )
170
+ console.info(JSON.stringify({ [JSON_KEY]: verdict, reason, is_finish }))
189
171
  }
190
172
 
191
173
  function refuse(): number {