@joshuafolkken/kit 1.953.0 → 1.972.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/workflow-commands/background-commands.md +3 -0
- package/.claude/skills/workflow-commands/backlogrun-child.md +75 -120
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +78 -115
- package/.claude/skills/workflow-commands/backlogrun-progress.md +82 -146
- package/.claude/skills/workflow-commands/backlogrun-steps.md +173 -229
- package/.claude/skills/workflow-commands/backlogrun.md +3 -1
- package/.claude/skills/workflow-commands/followup.md +3 -0
- package/.claude/skills/workflow-commands/fullrun.md +3 -4
- package/.claude/skills/workflow-commands/observation-filing.md +31 -25
- package/.claude/skills/workflow-commands/pre-gate-cut.md +96 -161
- package/.github/workflows/pr-classification.yml +12 -1
- package/CLAUDE.md +3 -3
- package/README.md +5 -3
- package/dist/CLAUDE.md +3 -3
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-OM5VDM6F.js → chunk-2K52BRWV.js} +2 -2
- package/dist/hooks/{chunk-Z5TVZ4AP.js → chunk-BNWIOJFU.js} +29 -16
- package/dist/hooks/{chunk-NKVLBB65.js → chunk-BVMSPG3M.js} +3 -3
- package/dist/hooks/{chunk-IA7WC4NS.js → chunk-CRGJTD6E.js} +1 -1
- package/dist/hooks/{chunk-M4U4YNRE.js → chunk-F6OM6SIG.js} +3 -3
- package/dist/hooks/{chunk-O3PEDF3M.js → chunk-KQG4776P.js} +1 -1
- package/dist/hooks/{chunk-V7RH56HU.js → chunk-NXL3SBXY.js} +2 -2
- package/dist/hooks/{chunk-452OKRQX.js → chunk-WWTMHHZU.js} +120 -18
- package/dist/hooks/{chunk-EYFJ74MJ.js → chunk-ZPLXLJ7O.js} +21 -7
- package/dist/hooks/{chunk-IBFC25IX.js → chunk-ZYYSBNR6.js} +4 -4
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +9 -9
- package/dist/hooks/stop-guard.js +206 -176
- package/dist/josh.js +14 -6
- package/package.json +3 -3
- package/prompts/collaboration-workflow/wip-cap.md +1 -1
- package/scripts/backlog/backlog-arrival.ts +11 -1
- package/scripts/backlog/backlog-budget.ts +25 -8
- package/scripts/backlog/backlog-drive-cli.ts +5 -1
- package/scripts/backlog/backlog-drive-retrospective.ts +20 -0
- package/scripts/backlog/backlog-drive.ts +7 -3
- package/scripts/backlog/backlog-next.ts +45 -2
- package/scripts/backlog/backlog-offer.ts +1 -0
- package/scripts/backlog/backlog-plan-cli.ts +66 -27
- package/scripts/backlog/backlog-plan.ts +30 -2
- package/scripts/backlog/backlog-stalled.ts +9 -0
- package/scripts/backlog/backlog-waves.ts +169 -0
- package/scripts/document/document-byte-budget.ts +1 -1
- package/scripts/document/entry-read-budget.ts +7 -5
- package/scripts/epic/epic-lane-offer.ts +69 -4
- package/scripts/epic/epic-next.ts +2 -2
- package/scripts/epic/epic-solo.ts +147 -0
- package/scripts/epic/epic-triage.ts +47 -0
- package/scripts/gate/hook-gate-reuse.ts +7 -8
- package/scripts/git/git-closes-keyword.ts +15 -0
- package/scripts/git/git-followup-flush.ts +5 -6
- package/scripts/git/git-followup-issue-close.ts +75 -0
- package/scripts/git/git-pr-followup-wrapup.ts +36 -6
- package/scripts/git/git-pr-followup.ts +9 -16
- package/scripts/git/git-staging.ts +33 -20
- package/scripts/git/issue-labels.ts +42 -0
- package/scripts/hooks/stop-guard.ts +1 -0
- package/scripts/init/init-install.ts +64 -0
- package/scripts/init/init.ts +38 -11
- package/scripts/init/project-profile.ts +9 -5
- package/scripts/init/start-plan.ts +145 -0
- package/scripts/init/start-prompt.ts +55 -0
- package/scripts/init/start-steps.ts +167 -0
- package/scripts/init/start.ts +92 -16
- package/scripts/issue/issue-closing-pr.ts +93 -0
- package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +4 -2
- package/scripts/josh/josh-commands-project.ts +11 -3
- package/scripts/josh/josh-commands-workflow.ts +3 -3
- package/scripts/observations/observation-ledger-prepare.ts +31 -0
- package/scripts/observations/observation-ledger.ts +5 -5
- package/scripts/observations/observations-flush.ts +11 -30
- package/scripts/rules/implementation-cut.ts +49 -16
- package/scripts/rules/lane-background.ts +25 -5
- package/scripts/rules/stop-rules.ts +16 -4
- package/scripts/run/run-carry-cli.ts +21 -0
- package/scripts/run/run-cut-cli.ts +92 -110
- package/scripts/run/run-cut-report.ts +167 -0
- package/scripts/run/run-cut.ts +23 -7
- package/scripts/run/run-entry-cli.ts +36 -2
- package/scripts/run/run-headless.ts +1 -0
- package/scripts/run/run-hold-cli.ts +36 -15
- package/scripts/run/run-hold.ts +15 -4
- package/scripts/run/run-merge-cli.ts +28 -14
- package/scripts/run/run-merge-steps.ts +38 -2
- package/scripts/run/run-merge.ts +41 -3
- package/scripts/run/run-prep-cli.ts +8 -2
- package/scripts/run/run-prep-locate.ts +165 -0
- package/scripts/run/run-prep.ts +12 -1
- package/scripts/run/run-retrospective.ts +34 -0
- package/scripts/run/run-step-cli.ts +19 -5
- package/scripts/run/run-step.ts +31 -19
- package/scripts/run/run-tail-cli.ts +4 -2
- package/scripts/run/run-wake-work.ts +4 -0
- package/scripts/safe-chain/ci-installer-pin.ts +8 -4
- package/scripts/time-runtime/time-background.ts +11 -0
- package/scripts/time-runtime/time-transcript-line.ts +4 -0
- package/templates/pnpm-workspace.static.yaml +2 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import {
|
|
3
3
|
pretool_guard
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-BNWIOJFU.js";
|
|
5
|
+
import "./chunk-WWTMHHZU.js";
|
|
6
6
|
import {
|
|
7
7
|
build_envelope,
|
|
8
8
|
compose_context,
|
|
9
9
|
format_edited_payload
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CRGJTD6E.js";
|
|
11
11
|
import "./chunk-3V37IID6.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-NXL3SBXY.js";
|
|
13
|
+
import "./chunk-BVMSPG3M.js";
|
|
14
|
+
import "./chunk-ZYYSBNR6.js";
|
|
15
|
+
import "./chunk-F6OM6SIG.js";
|
|
16
|
+
import "./chunk-2K52BRWV.js";
|
|
17
17
|
import {
|
|
18
18
|
hook_decision
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-KQG4776P.js";
|
|
20
20
|
import {
|
|
21
21
|
time_density_hook
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-ZPLXLJ7O.js";
|
|
23
23
|
import "./chunk-WPALEIRX.js";
|
|
24
24
|
import "./chunk-RKUAD3I6.js";
|
|
25
25
|
|
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
is_enabled,
|
|
10
10
|
notice_refusal_path,
|
|
11
11
|
refusal_path
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-ZYYSBNR6.js";
|
|
13
|
+
import "./chunk-F6OM6SIG.js";
|
|
14
|
+
import "./chunk-2K52BRWV.js";
|
|
15
|
+
import "./chunk-KQG4776P.js";
|
|
16
|
+
import "./chunk-ZPLXLJ7O.js";
|
|
17
17
|
import "./chunk-WPALEIRX.js";
|
|
18
18
|
import "./chunk-RKUAD3I6.js";
|
|
19
19
|
export {
|
|
@@ -15,9 +15,9 @@ import {
|
|
|
15
15
|
relative_to_root,
|
|
16
16
|
resolve_invocations,
|
|
17
17
|
select_invocation
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-CRGJTD6E.js";
|
|
19
19
|
import "./chunk-3V37IID6.js";
|
|
20
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-ZPLXLJ7O.js";
|
|
21
21
|
import "./chunk-RKUAD3I6.js";
|
|
22
22
|
export {
|
|
23
23
|
ESLINT_DAEMON,
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
is_enabled,
|
|
11
11
|
load_environment_file,
|
|
12
12
|
refusal_path
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-BVMSPG3M.js";
|
|
14
|
+
import "./chunk-F6OM6SIG.js";
|
|
15
|
+
import "./chunk-2K52BRWV.js";
|
|
16
|
+
import "./chunk-KQG4776P.js";
|
|
17
|
+
import "./chunk-ZPLXLJ7O.js";
|
|
18
18
|
import "./chunk-WPALEIRX.js";
|
|
19
19
|
import "./chunk-RKUAD3I6.js";
|
|
20
20
|
export {
|
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
pretool_guard,
|
|
4
4
|
pretool_outcome,
|
|
5
5
|
pretool_outcome_async
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-BNWIOJFU.js";
|
|
7
|
+
import "./chunk-WWTMHHZU.js";
|
|
8
8
|
import "./chunk-3V37IID6.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-NXL3SBXY.js";
|
|
10
|
+
import "./chunk-BVMSPG3M.js";
|
|
11
|
+
import "./chunk-ZYYSBNR6.js";
|
|
12
|
+
import "./chunk-F6OM6SIG.js";
|
|
13
|
+
import "./chunk-2K52BRWV.js";
|
|
14
|
+
import "./chunk-KQG4776P.js";
|
|
15
|
+
import "./chunk-ZPLXLJ7O.js";
|
|
16
16
|
import "./chunk-WPALEIRX.js";
|
|
17
17
|
import "./chunk-RKUAD3I6.js";
|
|
18
18
|
export {
|
package/dist/hooks/stop-guard.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import {
|
|
3
|
+
RUN_LANE_LABEL,
|
|
4
|
+
RUN_SOLO_LABEL,
|
|
3
5
|
agent_role_profile,
|
|
4
6
|
backlog_budget,
|
|
5
7
|
filing_cap,
|
|
6
8
|
git_gh_api_path,
|
|
7
9
|
git_gh_exec,
|
|
10
|
+
has_label_name,
|
|
8
11
|
lane_background,
|
|
9
12
|
lane_child_invocation,
|
|
10
13
|
lane_park,
|
|
@@ -16,20 +19,20 @@ import {
|
|
|
16
19
|
run_hold,
|
|
17
20
|
run_invocation,
|
|
18
21
|
run_watcher_guard
|
|
19
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-WWTMHHZU.js";
|
|
20
23
|
import {
|
|
21
24
|
session_language
|
|
22
25
|
} from "./chunk-6V5OPIUU.js";
|
|
23
26
|
import {
|
|
24
27
|
hook_decision,
|
|
25
28
|
lane_child_marker
|
|
26
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-KQG4776P.js";
|
|
27
30
|
import {
|
|
28
31
|
PROJECT_ROOT,
|
|
29
32
|
stamp_file,
|
|
30
33
|
time_density_hook,
|
|
31
34
|
time_hook_transcript
|
|
32
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-ZPLXLJ7O.js";
|
|
33
36
|
import "./chunk-WPALEIRX.js";
|
|
34
37
|
import "./chunk-RKUAD3I6.js";
|
|
35
38
|
|
|
@@ -208,9 +211,181 @@ var run_headless = {
|
|
|
208
211
|
environment,
|
|
209
212
|
is_backlog_parent,
|
|
210
213
|
is_headless,
|
|
214
|
+
is_owned_here,
|
|
211
215
|
must_keep_waiting
|
|
212
216
|
};
|
|
213
217
|
|
|
218
|
+
// scripts/issue/issue-cite.ts
|
|
219
|
+
var GITHUB_URL_PREFIX = "https://github.com/";
|
|
220
|
+
var ISSUE_PATH = "/issues/";
|
|
221
|
+
var SUMMARY_SEPARATOR = " \u2014 ";
|
|
222
|
+
var REPO_QUALIFIED = /^([^\s/#]+\/[^\s/#]+)#(\d+)$/u;
|
|
223
|
+
var BARE_NUMBER = /^#?(\d+)$/u;
|
|
224
|
+
function issue_url(slug, number) {
|
|
225
|
+
return `${GITHUB_URL_PREFIX}${slug}${ISSUE_PATH}${number}`;
|
|
226
|
+
}
|
|
227
|
+
function citation_line(slug, number, summary) {
|
|
228
|
+
return `[#${number}](${issue_url(slug, number)})${SUMMARY_SEPARATOR}${summary}`;
|
|
229
|
+
}
|
|
230
|
+
function qualified_target(token) {
|
|
231
|
+
const match = REPO_QUALIFIED.exec(token);
|
|
232
|
+
if (match === null) return void 0;
|
|
233
|
+
const [, repo = "", number = ""] = match;
|
|
234
|
+
return { number, repo };
|
|
235
|
+
}
|
|
236
|
+
function bare_target(token, default_repo) {
|
|
237
|
+
const match = BARE_NUMBER.exec(token);
|
|
238
|
+
if (match === null) return void 0;
|
|
239
|
+
const [, number = ""] = match;
|
|
240
|
+
return { number, repo: default_repo };
|
|
241
|
+
}
|
|
242
|
+
function parse_target(token, default_repo) {
|
|
243
|
+
return qualified_target(token) ?? bare_target(token, default_repo);
|
|
244
|
+
}
|
|
245
|
+
function label(target) {
|
|
246
|
+
return target.repo === void 0 ? `#${target.number}` : `${target.repo}#${target.number}`;
|
|
247
|
+
}
|
|
248
|
+
function missing_line(target) {
|
|
249
|
+
return `\u2716 ${label(target)}: issue does not resolve \u2014 check the number and the repository`;
|
|
250
|
+
}
|
|
251
|
+
function unreadable_line(target) {
|
|
252
|
+
return `\u2716 ${label(target)}: could not be read \u2014 a rate limit, expired auth, or a dropped connection`;
|
|
253
|
+
}
|
|
254
|
+
function no_repo_line(target) {
|
|
255
|
+
return `\u2716 ${label(target)}: could not read this repository \u2014 check gh auth and the origin remote`;
|
|
256
|
+
}
|
|
257
|
+
var issue_cite = {
|
|
258
|
+
SUMMARY_SEPARATOR,
|
|
259
|
+
citation_line,
|
|
260
|
+
issue_url,
|
|
261
|
+
label,
|
|
262
|
+
missing_line,
|
|
263
|
+
no_repo_line,
|
|
264
|
+
parse_target,
|
|
265
|
+
unreadable_line
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// scripts/rules/issue-citation.ts
|
|
269
|
+
var ISSUE_NUMBER = /#\d+/gu;
|
|
270
|
+
var REFERENCE_BOUNDARY = /[\s#()[\]<>|]/u;
|
|
271
|
+
var OWNER_REPO = /^[^\s/#]+\/[^\s/#]+$/u;
|
|
272
|
+
var MARKDOWN_LINK = /\[([^[\]]*)\]\([^()]*\)/gu;
|
|
273
|
+
var FENCE_MARKER = /^\s*(?:`{3,}|~{3,})/u;
|
|
274
|
+
var QUOTE_LINE = /^\s*>/u;
|
|
275
|
+
var PR_PREFIX = /\b(?:pr|pull request)\s*$/iu;
|
|
276
|
+
var BACKTICK_PAIR = 2;
|
|
277
|
+
function text_span_covers(link, index) {
|
|
278
|
+
const start = (link.index ?? 0) + 1;
|
|
279
|
+
const end = start + (link[1] ?? "").length;
|
|
280
|
+
return index >= start && index < end;
|
|
281
|
+
}
|
|
282
|
+
function is_linked_at(line, index) {
|
|
283
|
+
for (const link of line.matchAll(MARKDOWN_LINK)) {
|
|
284
|
+
if (text_span_covers(link, index)) return true;
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function repo_prefix(message2, hash_index) {
|
|
289
|
+
let start = hash_index;
|
|
290
|
+
while (start > 0 && !REFERENCE_BOUNDARY.test(message2.charAt(start - 1))) start -= 1;
|
|
291
|
+
const token = message2.slice(start, hash_index);
|
|
292
|
+
return OWNER_REPO.test(token) ? token : "";
|
|
293
|
+
}
|
|
294
|
+
function is_inline_code_at(line, index) {
|
|
295
|
+
const backticks = line.slice(0, index).split("`").length - 1;
|
|
296
|
+
return backticks % BACKTICK_PAIR === 1;
|
|
297
|
+
}
|
|
298
|
+
function is_bare_at(line, index) {
|
|
299
|
+
if (is_linked_at(line, index) || is_inline_code_at(line, index)) return false;
|
|
300
|
+
return !PR_PREFIX.test(line.slice(0, index));
|
|
301
|
+
}
|
|
302
|
+
function line_references(line) {
|
|
303
|
+
const references = [];
|
|
304
|
+
for (const match of line.matchAll(ISSUE_NUMBER)) {
|
|
305
|
+
const { index } = match;
|
|
306
|
+
if (is_bare_at(line, index)) {
|
|
307
|
+
references.push({ index, prefix: repo_prefix(line, index), text: match[0] });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return references;
|
|
311
|
+
}
|
|
312
|
+
function collect_line_references(line, found) {
|
|
313
|
+
for (const reference of line_references(line)) found.push(`${reference.prefix}${reference.text}`);
|
|
314
|
+
}
|
|
315
|
+
function lines_outside_fences(message2) {
|
|
316
|
+
const lines = [];
|
|
317
|
+
let is_in_fence = false;
|
|
318
|
+
for (const line of message2.split("\n")) {
|
|
319
|
+
if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
|
|
320
|
+
else if (!is_in_fence) lines.push(line);
|
|
321
|
+
}
|
|
322
|
+
return lines;
|
|
323
|
+
}
|
|
324
|
+
function prose_lines(message2) {
|
|
325
|
+
return lines_outside_fences(message2).filter((line) => !QUOTE_LINE.test(line));
|
|
326
|
+
}
|
|
327
|
+
function bare_references(message2) {
|
|
328
|
+
const found = [];
|
|
329
|
+
for (const line of prose_lines(message2)) collect_line_references(line, found);
|
|
330
|
+
return [...new Set(found)];
|
|
331
|
+
}
|
|
332
|
+
function has_bare_reference(message2) {
|
|
333
|
+
return bare_references(message2).length > 0;
|
|
334
|
+
}
|
|
335
|
+
function cite_argument(reference) {
|
|
336
|
+
return reference.startsWith("#") ? reference.slice(1) : reference;
|
|
337
|
+
}
|
|
338
|
+
function cite_arguments(references) {
|
|
339
|
+
return references.map((reference) => cite_argument(reference));
|
|
340
|
+
}
|
|
341
|
+
function reference_link(reference, default_slug) {
|
|
342
|
+
const slug = reference.prefix === "" ? default_slug : reference.prefix;
|
|
343
|
+
const number = reference.text.slice(1);
|
|
344
|
+
return `[${reference.prefix}${reference.text}](${issue_cite.issue_url(slug, number)})`;
|
|
345
|
+
}
|
|
346
|
+
function linkify_line(line, slug) {
|
|
347
|
+
let result = "";
|
|
348
|
+
let cursor = 0;
|
|
349
|
+
for (const reference of line_references(line)) {
|
|
350
|
+
const start = reference.index - reference.prefix.length;
|
|
351
|
+
result += line.slice(cursor, start) + reference_link(reference, slug);
|
|
352
|
+
cursor = reference.index + reference.text.length;
|
|
353
|
+
}
|
|
354
|
+
return result + line.slice(cursor);
|
|
355
|
+
}
|
|
356
|
+
function rewrite_line(line, slug, is_in_fence) {
|
|
357
|
+
if (is_in_fence || FENCE_MARKER.test(line) || QUOTE_LINE.test(line)) return line;
|
|
358
|
+
return linkify_line(line, slug);
|
|
359
|
+
}
|
|
360
|
+
function linkify(message2, slug) {
|
|
361
|
+
const out = [];
|
|
362
|
+
let is_in_fence = false;
|
|
363
|
+
for (const line of message2.split("\n")) {
|
|
364
|
+
if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
|
|
365
|
+
out.push(rewrite_line(line, slug, is_in_fence));
|
|
366
|
+
}
|
|
367
|
+
return out.join("\n");
|
|
368
|
+
}
|
|
369
|
+
var issue_citation = { bare_references, cite_arguments, has_bare_reference, linkify, prose_lines };
|
|
370
|
+
|
|
371
|
+
// scripts/epic/epic-triage.ts
|
|
372
|
+
var TRIAGE_VERDICT = "triage";
|
|
373
|
+
function is_triaged(child) {
|
|
374
|
+
const { labels } = child;
|
|
375
|
+
return has_label_name(labels, RUN_SOLO_LABEL) || has_label_name(labels, RUN_LANE_LABEL);
|
|
376
|
+
}
|
|
377
|
+
function untriaged(children) {
|
|
378
|
+
return children.filter((child) => !is_triaged(child));
|
|
379
|
+
}
|
|
380
|
+
function message(children, repo) {
|
|
381
|
+
const numbers = children.map((child) => `#${String(child.number)}`).join(", ");
|
|
382
|
+
return issue_citation.linkify(
|
|
383
|
+
`Untriaged: ${numbers} carry neither \`${RUN_SOLO_LABEL}\` nor \`${RUN_LANE_LABEL}\` in ${repo}, so nothing is offered until each is judged. Read each one, record its blocked-by order and one of the two labels with a comment saying why, then ask again.`,
|
|
384
|
+
repo
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
var epic_triage = { TRIAGE_VERDICT, is_triaged, message, untriaged };
|
|
388
|
+
|
|
214
389
|
// scripts/run/run-event-stream.ts
|
|
215
390
|
import { z } from "zod";
|
|
216
391
|
var EVENT_PREFIX = "josh-run-events-";
|
|
@@ -392,6 +567,9 @@ function ready_tokens(out) {
|
|
|
392
567
|
function count_ready_tokens(out) {
|
|
393
568
|
return ready_tokens(out).length;
|
|
394
569
|
}
|
|
570
|
+
function needs_triage(out) {
|
|
571
|
+
return out.split("\n").some((token) => token.trim() === epic_triage.TRIAGE_VERDICT);
|
|
572
|
+
}
|
|
395
573
|
var backlog_stalled = {
|
|
396
574
|
STALLED,
|
|
397
575
|
OK,
|
|
@@ -402,6 +580,7 @@ var backlog_stalled = {
|
|
|
402
580
|
describe,
|
|
403
581
|
dispatch_age_ms,
|
|
404
582
|
is_stalled,
|
|
583
|
+
needs_triage,
|
|
405
584
|
ready_tokens
|
|
406
585
|
};
|
|
407
586
|
|
|
@@ -862,159 +1041,6 @@ var backlog_stalled_detect = { DEFAULT_PORTS: DEFAULT_PORTS2, detect_and_report,
|
|
|
862
1041
|
// scripts/rules/stop-rules.ts
|
|
863
1042
|
import { z as z3 } from "zod";
|
|
864
1043
|
|
|
865
|
-
// scripts/issue/issue-cite.ts
|
|
866
|
-
var GITHUB_URL_PREFIX = "https://github.com/";
|
|
867
|
-
var ISSUE_PATH = "/issues/";
|
|
868
|
-
var SUMMARY_SEPARATOR = " \u2014 ";
|
|
869
|
-
var REPO_QUALIFIED = /^([^\s/#]+\/[^\s/#]+)#(\d+)$/u;
|
|
870
|
-
var BARE_NUMBER = /^#?(\d+)$/u;
|
|
871
|
-
function issue_url(slug, number) {
|
|
872
|
-
return `${GITHUB_URL_PREFIX}${slug}${ISSUE_PATH}${number}`;
|
|
873
|
-
}
|
|
874
|
-
function citation_line(slug, number, summary) {
|
|
875
|
-
return `[#${number}](${issue_url(slug, number)})${SUMMARY_SEPARATOR}${summary}`;
|
|
876
|
-
}
|
|
877
|
-
function qualified_target(token) {
|
|
878
|
-
const match = REPO_QUALIFIED.exec(token);
|
|
879
|
-
if (match === null) return void 0;
|
|
880
|
-
const [, repo = "", number = ""] = match;
|
|
881
|
-
return { number, repo };
|
|
882
|
-
}
|
|
883
|
-
function bare_target(token, default_repo) {
|
|
884
|
-
const match = BARE_NUMBER.exec(token);
|
|
885
|
-
if (match === null) return void 0;
|
|
886
|
-
const [, number = ""] = match;
|
|
887
|
-
return { number, repo: default_repo };
|
|
888
|
-
}
|
|
889
|
-
function parse_target(token, default_repo) {
|
|
890
|
-
return qualified_target(token) ?? bare_target(token, default_repo);
|
|
891
|
-
}
|
|
892
|
-
function label(target) {
|
|
893
|
-
return target.repo === void 0 ? `#${target.number}` : `${target.repo}#${target.number}`;
|
|
894
|
-
}
|
|
895
|
-
function missing_line(target) {
|
|
896
|
-
return `\u2716 ${label(target)}: issue does not resolve \u2014 check the number and the repository`;
|
|
897
|
-
}
|
|
898
|
-
function unreadable_line(target) {
|
|
899
|
-
return `\u2716 ${label(target)}: could not be read \u2014 a rate limit, expired auth, or a dropped connection`;
|
|
900
|
-
}
|
|
901
|
-
function no_repo_line(target) {
|
|
902
|
-
return `\u2716 ${label(target)}: could not read this repository \u2014 check gh auth and the origin remote`;
|
|
903
|
-
}
|
|
904
|
-
var issue_cite = {
|
|
905
|
-
SUMMARY_SEPARATOR,
|
|
906
|
-
citation_line,
|
|
907
|
-
issue_url,
|
|
908
|
-
label,
|
|
909
|
-
missing_line,
|
|
910
|
-
no_repo_line,
|
|
911
|
-
parse_target,
|
|
912
|
-
unreadable_line
|
|
913
|
-
};
|
|
914
|
-
|
|
915
|
-
// scripts/rules/issue-citation.ts
|
|
916
|
-
var ISSUE_NUMBER = /#\d+/gu;
|
|
917
|
-
var REFERENCE_BOUNDARY = /[\s#()[\]<>|]/u;
|
|
918
|
-
var OWNER_REPO = /^[^\s/#]+\/[^\s/#]+$/u;
|
|
919
|
-
var MARKDOWN_LINK = /\[([^[\]]*)\]\([^()]*\)/gu;
|
|
920
|
-
var FENCE_MARKER = /^\s*(?:`{3,}|~{3,})/u;
|
|
921
|
-
var QUOTE_LINE = /^\s*>/u;
|
|
922
|
-
var PR_PREFIX = /\b(?:pr|pull request)\s*$/iu;
|
|
923
|
-
var BACKTICK_PAIR = 2;
|
|
924
|
-
function text_span_covers(link, index) {
|
|
925
|
-
const start = (link.index ?? 0) + 1;
|
|
926
|
-
const end = start + (link[1] ?? "").length;
|
|
927
|
-
return index >= start && index < end;
|
|
928
|
-
}
|
|
929
|
-
function is_linked_at(line, index) {
|
|
930
|
-
for (const link of line.matchAll(MARKDOWN_LINK)) {
|
|
931
|
-
if (text_span_covers(link, index)) return true;
|
|
932
|
-
}
|
|
933
|
-
return false;
|
|
934
|
-
}
|
|
935
|
-
function repo_prefix(message, hash_index) {
|
|
936
|
-
let start = hash_index;
|
|
937
|
-
while (start > 0 && !REFERENCE_BOUNDARY.test(message.charAt(start - 1))) start -= 1;
|
|
938
|
-
const token = message.slice(start, hash_index);
|
|
939
|
-
return OWNER_REPO.test(token) ? token : "";
|
|
940
|
-
}
|
|
941
|
-
function is_inline_code_at(line, index) {
|
|
942
|
-
const backticks = line.slice(0, index).split("`").length - 1;
|
|
943
|
-
return backticks % BACKTICK_PAIR === 1;
|
|
944
|
-
}
|
|
945
|
-
function is_bare_at(line, index) {
|
|
946
|
-
if (is_linked_at(line, index) || is_inline_code_at(line, index)) return false;
|
|
947
|
-
return !PR_PREFIX.test(line.slice(0, index));
|
|
948
|
-
}
|
|
949
|
-
function line_references(line) {
|
|
950
|
-
const references = [];
|
|
951
|
-
for (const match of line.matchAll(ISSUE_NUMBER)) {
|
|
952
|
-
const { index } = match;
|
|
953
|
-
if (is_bare_at(line, index)) {
|
|
954
|
-
references.push({ index, prefix: repo_prefix(line, index), text: match[0] });
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
return references;
|
|
958
|
-
}
|
|
959
|
-
function collect_line_references(line, found) {
|
|
960
|
-
for (const reference of line_references(line)) found.push(`${reference.prefix}${reference.text}`);
|
|
961
|
-
}
|
|
962
|
-
function lines_outside_fences(message) {
|
|
963
|
-
const lines = [];
|
|
964
|
-
let is_in_fence = false;
|
|
965
|
-
for (const line of message.split("\n")) {
|
|
966
|
-
if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
|
|
967
|
-
else if (!is_in_fence) lines.push(line);
|
|
968
|
-
}
|
|
969
|
-
return lines;
|
|
970
|
-
}
|
|
971
|
-
function prose_lines(message) {
|
|
972
|
-
return lines_outside_fences(message).filter((line) => !QUOTE_LINE.test(line));
|
|
973
|
-
}
|
|
974
|
-
function bare_references(message) {
|
|
975
|
-
const found = [];
|
|
976
|
-
for (const line of prose_lines(message)) collect_line_references(line, found);
|
|
977
|
-
return [...new Set(found)];
|
|
978
|
-
}
|
|
979
|
-
function has_bare_reference(message) {
|
|
980
|
-
return bare_references(message).length > 0;
|
|
981
|
-
}
|
|
982
|
-
function cite_argument(reference) {
|
|
983
|
-
return reference.startsWith("#") ? reference.slice(1) : reference;
|
|
984
|
-
}
|
|
985
|
-
function cite_arguments(references) {
|
|
986
|
-
return references.map((reference) => cite_argument(reference));
|
|
987
|
-
}
|
|
988
|
-
function reference_link(reference, default_slug) {
|
|
989
|
-
const slug = reference.prefix === "" ? default_slug : reference.prefix;
|
|
990
|
-
const number = reference.text.slice(1);
|
|
991
|
-
return `[${reference.prefix}${reference.text}](${issue_cite.issue_url(slug, number)})`;
|
|
992
|
-
}
|
|
993
|
-
function linkify_line(line, slug) {
|
|
994
|
-
let result = "";
|
|
995
|
-
let cursor = 0;
|
|
996
|
-
for (const reference of line_references(line)) {
|
|
997
|
-
const start = reference.index - reference.prefix.length;
|
|
998
|
-
result += line.slice(cursor, start) + reference_link(reference, slug);
|
|
999
|
-
cursor = reference.index + reference.text.length;
|
|
1000
|
-
}
|
|
1001
|
-
return result + line.slice(cursor);
|
|
1002
|
-
}
|
|
1003
|
-
function rewrite_line(line, slug, is_in_fence) {
|
|
1004
|
-
if (is_in_fence || FENCE_MARKER.test(line) || QUOTE_LINE.test(line)) return line;
|
|
1005
|
-
return linkify_line(line, slug);
|
|
1006
|
-
}
|
|
1007
|
-
function linkify(message, slug) {
|
|
1008
|
-
const out = [];
|
|
1009
|
-
let is_in_fence = false;
|
|
1010
|
-
for (const line of message.split("\n")) {
|
|
1011
|
-
if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
|
|
1012
|
-
out.push(rewrite_line(line, slug, is_in_fence));
|
|
1013
|
-
}
|
|
1014
|
-
return out.join("\n");
|
|
1015
|
-
}
|
|
1016
|
-
var issue_citation = { bare_references, cite_arguments, has_bare_reference, linkify, prose_lines };
|
|
1017
|
-
|
|
1018
1044
|
// scripts/rules/filing-offer.ts
|
|
1019
1045
|
var OFFER_PATTERNS = [
|
|
1020
1046
|
/起票(?:して)?(?:も)?(?:よければ|よろしければ|よいですか|良いですか|よろしいですか|いいですか)/u,
|
|
@@ -1029,21 +1055,21 @@ var OWNER_SEPARATOR = "/";
|
|
|
1029
1055
|
function is_offer_line(line) {
|
|
1030
1056
|
return OFFER_PATTERNS.some((pattern) => pattern.test(line));
|
|
1031
1057
|
}
|
|
1032
|
-
function offers_filing(
|
|
1033
|
-
return issue_citation.prose_lines(
|
|
1058
|
+
function offers_filing(message2) {
|
|
1059
|
+
return issue_citation.prose_lines(message2).some((line) => is_offer_line(line));
|
|
1034
1060
|
}
|
|
1035
|
-
function url_owners(
|
|
1036
|
-
return [...
|
|
1061
|
+
function url_owners(message2) {
|
|
1062
|
+
return [...message2.matchAll(GITHUB_URL_OWNER)].map((match) => match[1] ?? "");
|
|
1037
1063
|
}
|
|
1038
|
-
function qualified_owners(
|
|
1039
|
-
return issue_citation.bare_references(
|
|
1064
|
+
function qualified_owners(message2) {
|
|
1065
|
+
return issue_citation.bare_references(message2).filter((reference) => reference.includes(OWNER_SEPARATOR)).map((reference) => reference.split(OWNER_SEPARATOR)[0] ?? "");
|
|
1040
1066
|
}
|
|
1041
|
-
function mentioned_owners(
|
|
1042
|
-
return [...url_owners(
|
|
1067
|
+
function mentioned_owners(message2) {
|
|
1068
|
+
return [...url_owners(message2), ...qualified_owners(message2)];
|
|
1043
1069
|
}
|
|
1044
|
-
function is_first_party_target(
|
|
1070
|
+
function is_first_party_target(message2, session_owner) {
|
|
1045
1071
|
if (session_owner === void 0) return false;
|
|
1046
|
-
return mentioned_owners(
|
|
1072
|
+
return mentioned_owners(message2).every(
|
|
1047
1073
|
(owner) => repo_party.classify(session_owner, owner) === repo_party.FIRST_PARTY
|
|
1048
1074
|
);
|
|
1049
1075
|
}
|
|
@@ -1085,8 +1111,8 @@ function letter_pattern(script) {
|
|
|
1085
1111
|
return void 0;
|
|
1086
1112
|
}
|
|
1087
1113
|
}
|
|
1088
|
-
function prose_of(
|
|
1089
|
-
let text2 =
|
|
1114
|
+
function prose_of(message2) {
|
|
1115
|
+
let text2 = message2;
|
|
1090
1116
|
for (const pattern of CODE_PATTERNS) text2 = text2.replaceAll(pattern, " ");
|
|
1091
1117
|
return text2.replaceAll(ASCII_RUN_PATTERN, (run) => run.includes("/") ? " " : run);
|
|
1092
1118
|
}
|
|
@@ -1107,12 +1133,12 @@ function matches_share(prose, script, pattern) {
|
|
|
1107
1133
|
const matched = lines.filter((line) => is_line_in_script(line, script, pattern));
|
|
1108
1134
|
return matched.length / lines.length;
|
|
1109
1135
|
}
|
|
1110
|
-
function is_mismatch(
|
|
1136
|
+
function is_mismatch(message2, lang) {
|
|
1111
1137
|
const script = script_of(lang);
|
|
1112
1138
|
if (script === void 0) return false;
|
|
1113
1139
|
const pattern = letter_pattern(script);
|
|
1114
1140
|
if (pattern === void 0) return false;
|
|
1115
|
-
const prose = prose_of(
|
|
1141
|
+
const prose = prose_of(message2);
|
|
1116
1142
|
if (letter_count(prose) < MIN_PROSE_LETTERS) return false;
|
|
1117
1143
|
return matches_share(prose, script, pattern) < MATCH_SHARE_FLOOR;
|
|
1118
1144
|
}
|
|
@@ -1144,8 +1170,8 @@ var HEADLESS_WAIT_REASON = `${HEADLESS_WAIT_MARKER}${HEADLESS_WAIT_BODY}`;
|
|
|
1144
1170
|
var INDEX_COMMAND_PATTERN = /git (?:add|stage|rm --cached|restore --staged|restore -S)\b/u;
|
|
1145
1171
|
var PERMISSION_PATTERN = /許可|承認|permission|approve|approval|authorization/iu;
|
|
1146
1172
|
var LANE_INDEX_REASON = '\u26D4 lane index permission: this is a dispatched lane child (`JOSH_LANE_CHILD`) and your reply asks a person for permission to change the git index. A lane is a per-run work tree with no person\'s staging to protect, and the sanctioned commit flow is already authorized: remove any conflict markers, then run `pnpm josh git -y`, which stages and commits them \u2014 a conflicted merge included. This is Tier A (`.claude/skills/workflow-commands/chain-rule.md` \u2192 "origin/main is merged in before the gate"). Do it and continue the run \u2014 do not repeat your previous reply.';
|
|
1147
|
-
function asks_index_permission(
|
|
1148
|
-
return INDEX_COMMAND_PATTERN.test(
|
|
1173
|
+
function asks_index_permission(message2) {
|
|
1174
|
+
return INDEX_COMMAND_PATTERN.test(message2) && PERMISSION_PATTERN.test(message2);
|
|
1149
1175
|
}
|
|
1150
1176
|
function needs_index_route(context) {
|
|
1151
1177
|
return context.lane_child && asks_index_permission(context.message);
|
|
@@ -1164,14 +1190,17 @@ function needs_filing(context) {
|
|
|
1164
1190
|
if (context.filed || !filing_offer.offers_filing(context.message)) return false;
|
|
1165
1191
|
return filing_offer.is_first_party_target(context.message, context.session_owner);
|
|
1166
1192
|
}
|
|
1193
|
+
function is_held_idle(context) {
|
|
1194
|
+
return context.hold_present && !context.agent_pending;
|
|
1195
|
+
}
|
|
1167
1196
|
function needs_notify(context) {
|
|
1168
|
-
return context
|
|
1197
|
+
return is_held_idle(context) && !context.notified;
|
|
1169
1198
|
}
|
|
1170
1199
|
function needs_release(context) {
|
|
1171
|
-
return context
|
|
1200
|
+
return is_held_idle(context) && context.tree_clean;
|
|
1172
1201
|
}
|
|
1173
|
-
function citation_reason(
|
|
1174
|
-
const references = issue_citation.bare_references(
|
|
1202
|
+
function citation_reason(message2) {
|
|
1203
|
+
const references = issue_citation.bare_references(message2);
|
|
1175
1204
|
if (references.length === 0) return void 0;
|
|
1176
1205
|
return build_citation_reason(references);
|
|
1177
1206
|
}
|
|
@@ -1564,6 +1593,7 @@ async function build_context(transcript_path, payload_tail) {
|
|
|
1564
1593
|
headless_refusals: stop_rules.count_headless_refusals(tail),
|
|
1565
1594
|
lane_child: lane_child_marker.is_child_of(process.cwd()),
|
|
1566
1595
|
background_pending: lane_background.pending_background_ids(tail).length > 0,
|
|
1596
|
+
agent_pending: lane_background.pending_agent_ids(tail).length > 0,
|
|
1567
1597
|
session_lang: session_lang()
|
|
1568
1598
|
};
|
|
1569
1599
|
}
|
package/dist/josh.js
CHANGED
|
@@ -1173,15 +1173,23 @@ var PROJECT_COMMANDS = {
|
|
|
1173
1173
|
},
|
|
1174
1174
|
start: {
|
|
1175
1175
|
script: "scripts/init/start.ts",
|
|
1176
|
-
description: "
|
|
1176
|
+
description: "Create a new project for the GitHub Issue workflow, from git init to labels",
|
|
1177
1177
|
category: "Project",
|
|
1178
|
-
reference: [
|
|
1178
|
+
reference: [
|
|
1179
|
+
`${PROFILE_ARGUMENTS} [--yes] [--github] [--public]`,
|
|
1180
|
+
"developer",
|
|
1181
|
+
["files", "git", "network", "processes"]
|
|
1182
|
+
]
|
|
1179
1183
|
},
|
|
1180
1184
|
init: {
|
|
1181
1185
|
script: "scripts/init/init.ts",
|
|
1182
1186
|
description: "Initialize config in a new project",
|
|
1183
1187
|
category: "Project",
|
|
1184
|
-
reference: [
|
|
1188
|
+
reference: [
|
|
1189
|
+
`${PROFILE_ARGUMENTS} [--no-install]`,
|
|
1190
|
+
"developer",
|
|
1191
|
+
["files", "network", "processes"]
|
|
1192
|
+
]
|
|
1185
1193
|
},
|
|
1186
1194
|
sync: {
|
|
1187
1195
|
script: "scripts/sync/sync.ts",
|
|
@@ -1322,9 +1330,9 @@ var WORKFLOW_COMMANDS = {
|
|
|
1322
1330
|
reference: ["--task-type <type> --body <text>", "automation", ["notifications"]],
|
|
1323
1331
|
tsx_arguments: OPTIONAL_ENV_FILE_FLAGS
|
|
1324
1332
|
},
|
|
1325
|
-
// The observation ledger's
|
|
1326
|
-
//
|
|
1327
|
-
//
|
|
1333
|
+
// The observation ledger's commit path for the lines no run's own commit carried
|
|
1334
|
+
// (joshuafolkken/kit#1756, joshuafolkken/kit#2763): a lane's lines sit in the primary checkout, which
|
|
1335
|
+
// its commit cannot see, and the recurrence count the promotion rule reads is a count of main.
|
|
1328
1336
|
"observations:flush": {
|
|
1329
1337
|
script: "scripts/observations/observations-flush-cli.ts",
|
|
1330
1338
|
description: "Commit the observation ledger as a pull request of its own, and merge it",
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.972.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": [
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
201
201
|
"eslint-plugin-import-x": "^4.17.1",
|
|
202
202
|
"eslint-plugin-promise": "^7.3.0",
|
|
203
|
-
"eslint-plugin-sonarjs": "^4.2.
|
|
203
|
+
"eslint-plugin-sonarjs": "^4.2.2",
|
|
204
204
|
"eslint-plugin-unicorn": "^76.0.0",
|
|
205
205
|
"eslint_d": "^15.0.3",
|
|
206
206
|
"globals": "^17.12.0",
|
|
@@ -212,7 +212,7 @@
|
|
|
212
212
|
"rollup-plugin-dts": "^6.5.1",
|
|
213
213
|
"secretlint": "^13.0.6",
|
|
214
214
|
"typescript": "^6.0.3",
|
|
215
|
-
"typescript-eslint": "^8.
|
|
215
|
+
"typescript-eslint": "^8.71.0",
|
|
216
216
|
"vitest": "^5.0.2"
|
|
217
217
|
},
|
|
218
218
|
"dependencies": {
|
|
@@ -92,7 +92,7 @@ gh api "repos/{owner}/{repo}/issues?state=open&per_page=100" --paginate \
|
|
|
92
92
|
- **push 時のフック**
|
|
93
93
|
- **マージ時のチェック**
|
|
94
94
|
|
|
95
|
-
**いずれかに当たれば単独実行。**
|
|
95
|
+
**いずれかに当たれば単独実行。** その Issue に `run:solo` を付け、強制はそれを読む `backlog:next` と `epic:next --lanes` が行う(joshuafolkken/kit#2776)。当たらなければ(機能追加、文書修正など)`run:lane` を付け、並列バッチの一員として走らせてよい。どちらもなければ `triage` が返り何も始まらない(joshuafolkken/kit#2779)ので、run が起票する Issue(割り込み・分割・前提)は起票時にどちらかを付ける。**「重大だと感じるか」は判定条件ではない** — 3 条件と同じ理由で、深刻さの自己申告を条件に加えた瞬間、この区分も抜け道になる。
|
|
96
96
|
|
|
97
97
|
**理由は 2 つあり、どちらか一方だけでも単独実行の根拠として十分である。**
|
|
98
98
|
|