@joshuafolkken/kit 1.1136.0 → 1.1178.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +4 -4
- package/.claude/skills/epic-commands/SKILL.md +27 -239
- package/.claude/skills/epic-commands/epic-bundle.md +115 -0
- package/.claude/skills/epic-commands/execution-waves.md +126 -0
- package/.claude/skills/workflow-commands/SKILL.md +48 -194
- package/.claude/skills/workflow-commands/background-commands.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-child.md +12 -123
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +14 -63
- package/.claude/skills/workflow-commands/backlogrun-park.md +16 -15
- package/.claude/skills/workflow-commands/backlogrun-progress.md +17 -173
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +155 -0
- package/.claude/skills/workflow-commands/backlogrun-steps.md +65 -144
- package/.claude/skills/workflow-commands/backlogrun.md +5 -4
- package/.claude/skills/workflow-commands/chain-rule.md +3 -2
- package/.claude/skills/workflow-commands/delegation.md +2 -2
- package/.claude/skills/workflow-commands/entry-sequence.md +62 -0
- package/.claude/skills/workflow-commands/followup.md +104 -181
- package/.claude/skills/workflow-commands/fullrun-steps.md +8 -9
- package/.claude/skills/workflow-commands/fullrun.md +16 -73
- package/.claude/skills/workflow-commands/halfrun.md +10 -36
- package/.claude/skills/workflow-commands/into-target.md +4 -4
- package/.claude/skills/workflow-commands/issue-comments.md +7 -8
- package/.claude/skills/workflow-commands/issue-scout.md +6 -6
- package/.claude/skills/workflow-commands/kickoff.md +6 -6
- package/.claude/skills/workflow-commands/needs-human-review.md +6 -6
- package/.claude/skills/workflow-commands/observation-filing.md +21 -172
- package/.claude/skills/workflow-commands/observation-ledger.md +150 -0
- package/.claude/skills/workflow-commands/pre-gate-cut.md +35 -95
- package/.claude/skills/workflow-commands/prerequisite.md +6 -6
- package/.claude/skills/workflow-commands/progress-watcher.md +90 -0
- package/.claude/skills/workflow-commands/prrun.md +5 -5
- package/.claude/skills/workflow-commands/retrospective.md +9 -9
- package/.claude/skills/workflow-commands/split-assessment.md +2 -2
- package/.claude/skills/workflow-commands/target-repository.md +2 -2
- package/.claude/skills/workflow-commands/working-tree-hold.md +7 -5
- package/.codex/hooks.json +4 -4
- package/.github/workflows/ci.yml +15 -2
- package/AGENTS.md +1 -6
- package/CLAUDE.md +58 -120
- package/GEMINI.md +1 -6
- package/dist/CLAUDE.md +58 -120
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-NFZGFGOR.js → chunk-32GQTL4F.js} +14 -1
- package/dist/hooks/{chunk-HBKZLITF.js → chunk-DO6NWWHU.js} +4 -4
- package/dist/hooks/{chunk-KBXZLMRH.js → chunk-G6KRCKEC.js} +216 -76
- package/dist/hooks/{chunk-JKKTVDAG.js → chunk-GDS5N2KB.js} +186 -309
- package/dist/hooks/chunk-I4XSL4TT.js +56 -0
- package/dist/hooks/{chunk-GDU26K3J.js → chunk-S6X6WYKR.js} +886 -174
- package/dist/hooks/{chunk-FO2I7UT7.js → chunk-UAGLLIGZ.js} +1 -1
- package/dist/hooks/{chunk-RFWWUI5F.js → chunk-VESKRQOF.js} +3 -3
- package/dist/hooks/{chunk-KOKOAV6D.js → chunk-VQLLNFNT.js} +6 -4
- package/dist/hooks/{chunk-LJBLGHEH.js → chunk-ZAL3NRGL.js} +4 -6
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/inputs.json +178 -177
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +11 -10
- package/dist/hooks/stop-guard.js +20 -6
- package/dist/josh.js +29 -3
- package/dist/version/index.js +5 -1
- package/package.json +2 -1
- package/prompts/collaboration-workflow/file-edits.md +11 -10
- package/prompts/collaboration-workflow/gh-rest.md +2 -4
- package/prompts/collaboration-workflow/glossary.md +1 -1
- package/prompts/collaboration-workflow/issue-citation.md +5 -9
- package/prompts/collaboration-workflow/issue-template.md +40 -115
- package/prompts/collaboration-workflow/operating-rules.md +4 -5
- package/prompts/collaboration-workflow/output-bounds.md +12 -78
- package/prompts/collaboration-workflow/overview.md +7 -13
- package/prompts/collaboration-workflow/plan-comment.md +11 -39
- package/prompts/collaboration-workflow/principles.md +3 -4
- package/prompts/collaboration-workflow/report-format.md +28 -74
- package/prompts/collaboration-workflow/residency.md +12 -109
- package/prompts/collaboration-workflow/rule-delivery.md +98 -97
- package/prompts/collaboration-workflow/shell-body.md +3 -13
- package/prompts/collaboration-workflow/turn-batching.md +14 -88
- package/prompts/collaboration-workflow/upstream-interrupt.md +12 -14
- package/prompts/collaboration-workflow/wip-cap.md +6 -45
- package/prompts/collaboration-workflow.md +1 -13
- package/prompts/review-rubric.md +8 -71
- package/prompts/review.md +25 -55
- package/prompts/testing-guide.md +18 -67
- package/scripts/agent/agent-role-profile.ts +1 -1
- package/scripts/agent/codex-hooks.ts +3 -12
- package/scripts/backlog/backlog-budget.ts +1 -1
- package/scripts/backlog/backlog-drive-cli.ts +4 -3
- package/scripts/backlog/backlog-drive-offer-argv.ts +10 -1
- package/scripts/backlog/backlog-next.ts +15 -4
- package/scripts/backlog/backlog-offer.ts +6 -6
- package/scripts/backlog/backlog-plan-cli.ts +6 -5
- package/scripts/backlog/backlog-rank.ts +18 -9
- package/scripts/backlog/backlog-restructure.ts +152 -0
- package/scripts/backlog/backlog-waves.ts +15 -17
- package/scripts/behavior/behavior-rules.ts +11 -4
- package/scripts/cost-runtime/context-cut-threshold.ts +1 -9
- package/scripts/cost-runtime/cost-verdict.ts +15 -28
- package/scripts/delegation/investigation-reads.ts +5 -5
- package/scripts/discovery/repo-discovery.ts +21 -7
- package/scripts/discovery/repo-origin.ts +26 -0
- package/scripts/discovery/repo-party.ts +42 -1
- package/scripts/document/backlogrun-parent-read-set.ts +14 -15
- package/scripts/document/document-byte-budget.ts +34 -20
- package/scripts/document/entry-read-budget.ts +21 -9
- package/scripts/document/lane-child-read-set.ts +12 -14
- package/scripts/document/read-set-cli.ts +4 -4
- package/scripts/document/read-set-point-of-use.ts +10 -2
- package/scripts/document/resident-budget.ts +47 -0
- package/scripts/epic/epic-shape.ts +10 -13
- package/scripts/epic/epic-solo.ts +1 -1
- package/scripts/exports/unused-members-cli.ts +7 -3
- package/scripts/followup/git-followup-stages.ts +9 -0
- package/scripts/followup/git-pr-followup.ts +1 -1
- package/scripts/gh/git-gh-api-path.ts +7 -0
- package/scripts/gh/git-gh-issue.ts +5 -3
- package/scripts/gh/git-gh-pr-read.ts +4 -0
- package/scripts/gh/git-pr-checks-eval.ts +8 -0
- package/scripts/gh/git-pr-checks.ts +11 -1
- package/scripts/git/constants.ts +10 -0
- package/scripts/git/main-merge.ts +57 -21
- package/scripts/git/schemas.ts +2 -0
- package/scripts/hooks/pretool-guard-cli.ts +2 -2
- package/scripts/hooks/pretool-guard.ts +45 -2
- package/scripts/hooks/run-hook.sh +41 -0
- package/scripts/init/hook-command-rewrite.ts +18 -35
- package/scripts/init/hook-launch.ts +21 -32
- package/scripts/issue/issue-auto-ok.ts +95 -0
- package/scripts/issue/issue-file-cli.ts +53 -7
- package/scripts/issue/issue-file.ts +28 -5
- package/scripts/issue/issue-labels.ts +12 -12
- package/scripts/issue/issue-rank.ts +1 -1
- package/scripts/issue/issue-read-cli.ts +3 -3
- package/scripts/issue/issue-read.ts +2 -2
- package/scripts/issue/issue-scout-cli.ts +2 -2
- package/scripts/issue/issue-state-cli.ts +1 -1
- package/scripts/issue/issue-state.ts +2 -2
- package/scripts/issue/issue-wip.ts +70 -0
- package/scripts/josh/hook-decision.ts +17 -0
- package/scripts/josh/josh-commands-development.ts +11 -1
- package/scripts/josh/josh-commands-issue.ts +2 -2
- package/scripts/lane/lane-launch-cli.ts +21 -3
- package/scripts/lines/bytes-command.ts +29 -6
- package/scripts/notify/telegram-notify.ts +26 -1
- package/scripts/observations/observation-ledger-line.ts +1 -1
- package/scripts/release/release-progress.ts +167 -0
- package/scripts/release/release-publish.ts +19 -8
- package/scripts/release/release-tag.ts +22 -8
- package/scripts/rules/decision-oracle-stage.ts +1 -1
- package/scripts/rules/decision-oracle.ts +6 -6
- package/scripts/rules/delivered-rules.ts +11 -11
- package/scripts/rules/direct-pr-create.ts +110 -0
- package/scripts/rules/file-body.ts +98 -42
- package/scripts/rules/filing-cap.ts +2 -2
- package/scripts/rules/filing-offer.ts +1 -1
- package/scripts/rules/gh-api.ts +18 -1
- package/scripts/rules/implementation-cut.ts +3 -1
- package/scripts/rules/lane-background.ts +67 -10
- package/scripts/rules/permission-guards.ts +10 -2
- package/scripts/rules/pre-gate-cut.ts +2 -2
- package/scripts/rules/stop-rules.ts +4 -4
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +56 -12
- package/scripts/run/run-carry.ts +11 -5
- package/scripts/run/run-cut-cli.ts +1 -1
- package/scripts/run/run-cut-handoff.ts +21 -1
- package/scripts/run/run-cut-report.ts +2 -2
- package/scripts/run/run-entry-cli.ts +11 -3
- package/scripts/run/run-hold-cli.ts +16 -2
- package/scripts/run/run-label.ts +50 -0
- package/scripts/run/run-merge-steps.ts +8 -3
- package/scripts/run/run-merge.ts +1 -1
- package/scripts/run/run-prep-cli.ts +6 -2
- package/scripts/run/run-prep.ts +17 -0
- package/scripts/run/run-ship-cli.ts +27 -6
- package/scripts/run/run-ship-next.ts +13 -0
- package/scripts/run/run-ship-pre-detach.ts +66 -0
- package/scripts/run/run-ship-preflight.ts +34 -3
- package/scripts/run/run-ship-return.ts +7 -4
- package/scripts/run/run-ship-review-steps.ts +1 -1
- package/scripts/run/run-ship-review.ts +26 -5
- package/scripts/run/run-ship-stage.ts +13 -0
- package/scripts/run/run-ship-steps.ts +10 -2
- package/scripts/run/run-ship-sync.ts +114 -0
- package/scripts/run/run-ship.ts +6 -0
- package/scripts/run/run-step-cli.ts +20 -7
- package/scripts/run/run-wake-cli.ts +8 -1
- package/scripts/run/run-wake-driver.ts +62 -8
- package/scripts/run/run-wake-session.ts +2 -1
- package/scripts/test/test-declared-logic.ts +1 -1
- package/scripts/test/test-red-logic.ts +17 -2
- package/scripts/test/test-red.ts +8 -7
- package/scripts/time-runtime/time-batch-guard.ts +52 -16
- package/scripts/time-runtime/time-density-hook.ts +20 -2
- package/scripts/time-runtime/time-density.ts +4 -3
- package/scripts/time-runtime/time-markers.ts +15 -4
- package/scripts/time-runtime/time-transcript-line.ts +27 -1
- package/scripts/version/npm-registry.ts +11 -1
- package/templates/workflows/ci.yml +9 -1
- package/.claude/skills/workflow-commands/followup-reference.md +0 -118
- package/dist/hooks/chunk-HANSKHES.js +0 -464
|
@@ -297,10 +297,10 @@ var ISSUE_COMMANDS = {
|
|
|
297
297
|
},
|
|
298
298
|
"issue:file": {
|
|
299
299
|
script: "scripts/issue/issue-file-cli.ts",
|
|
300
|
-
description: "File an Issue with every filing step: lint, Origin, duplicate scout, labels, then epic:bundle",
|
|
300
|
+
description: "File an Issue with every filing step: lint, Origin, WIP cap, duplicate scout, labels, then epic:bundle",
|
|
301
301
|
category: "AI tools",
|
|
302
302
|
reference: [
|
|
303
|
-
"<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>]",
|
|
303
|
+
"<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok]",
|
|
304
304
|
"automation",
|
|
305
305
|
["network"]
|
|
306
306
|
]
|
|
@@ -811,6 +811,15 @@ var DEV_COMMANDS = {
|
|
|
811
811
|
// `UserPromptSubmit`, so it must stay eligible for in-process dispatch rather than pay a second
|
|
812
812
|
// tsx start each turn. It calls `process.loadEnvFile` itself through the shared loader.
|
|
813
813
|
},
|
|
814
|
+
"codex:hook-adapter": {
|
|
815
|
+
script: "scripts/hooks/codex-hook-adapter.ts",
|
|
816
|
+
description: "Codex hook: run the pretool or posttool guard on a Codex payload (reads the tool call on stdin)",
|
|
817
|
+
category: "Development",
|
|
818
|
+
reference: ["<pretool|posttool>", "automation", ["none"]]
|
|
819
|
+
// The live-source fallback `scripts/hooks/run-hook.sh` derives from the `codex-hook-adapter`
|
|
820
|
+
// bundle name (joshuafolkken/kit#3184). **No `tsx_arguments`**, the same as `pretool:guard`
|
|
821
|
+
// above: it runs before every guarded Codex call.
|
|
822
|
+
},
|
|
814
823
|
"cspell:dot": {
|
|
815
824
|
script: "scripts/lint/cspell-cached.ts",
|
|
816
825
|
description: "Run spell check including dotfiles",
|
|
@@ -849,7 +858,7 @@ var DEV_COMMANDS = {
|
|
|
849
858
|
},
|
|
850
859
|
"test:red": {
|
|
851
860
|
script: "scripts/test/test-red.ts",
|
|
852
|
-
description: "Run the changed unit tests against the pre-fix tree (merge-base worktree) and report red/green/no-test",
|
|
861
|
+
description: "Run the changed unit tests against the pre-fix tree (merge-base worktree) and report red/green/no-test/test-only",
|
|
853
862
|
category: "Development",
|
|
854
863
|
reference: ["", "developer", ["git", "processes"]]
|
|
855
864
|
},
|
|
@@ -1855,6 +1864,252 @@ var time_bundle_call = {
|
|
|
1855
1864
|
READ_JOSH_SUBCOMMANDS
|
|
1856
1865
|
};
|
|
1857
1866
|
|
|
1867
|
+
// scripts/git/schemas.ts
|
|
1868
|
+
import { z as z2 } from "zod";
|
|
1869
|
+
var package_name_schema = z2.object({ name: z2.string().min(1) });
|
|
1870
|
+
var rollup_item_schema = z2.looseObject({
|
|
1871
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention -- GraphQL field name from GitHub API
|
|
1872
|
+
__typename: z2.string().optional(),
|
|
1873
|
+
state: z2.string().optional(),
|
|
1874
|
+
status: z2.string().optional(),
|
|
1875
|
+
conclusion: z2.string().optional(),
|
|
1876
|
+
name: z2.string().optional(),
|
|
1877
|
+
context: z2.string().optional()
|
|
1878
|
+
});
|
|
1879
|
+
var pr_raw_schema = z2.object({
|
|
1880
|
+
statusCheckRollup: z2.array(rollup_item_schema).optional(),
|
|
1881
|
+
mergeStateStatus: z2.string().optional(),
|
|
1882
|
+
reviewDecision: z2.string().optional()
|
|
1883
|
+
});
|
|
1884
|
+
var pull_comment_schema = z2.object({
|
|
1885
|
+
body: z2.string().optional(),
|
|
1886
|
+
html_url: z2.string().optional(),
|
|
1887
|
+
user: z2.object({ login: z2.string().optional() }).optional()
|
|
1888
|
+
});
|
|
1889
|
+
var ai_review_pull_comment_schema = z2.object({
|
|
1890
|
+
body: z2.string().optional(),
|
|
1891
|
+
url: z2.string().optional(),
|
|
1892
|
+
author: z2.object({ login: z2.string().optional() }).optional()
|
|
1893
|
+
});
|
|
1894
|
+
var pr_info_schema = z2.object({
|
|
1895
|
+
mergeable: z2.union([z2.boolean(), z2.string()]).nullable().optional(),
|
|
1896
|
+
mergeStateStatus: z2.string().nullable().optional(),
|
|
1897
|
+
state: z2.string().optional()
|
|
1898
|
+
});
|
|
1899
|
+
var epic_issue_schema = z2.object({
|
|
1900
|
+
number: z2.number(),
|
|
1901
|
+
body: z2.string().optional()
|
|
1902
|
+
});
|
|
1903
|
+
var blocking_issue_schema = z2.object({
|
|
1904
|
+
number: z2.number(),
|
|
1905
|
+
state: z2.string().optional(),
|
|
1906
|
+
repository_url: z2.string().optional()
|
|
1907
|
+
});
|
|
1908
|
+
var blocked_by_schema = z2.object({
|
|
1909
|
+
nodes: z2.array(blocking_issue_schema).default([]),
|
|
1910
|
+
totalCount: z2.number().optional()
|
|
1911
|
+
}).optional();
|
|
1912
|
+
var epic_child_schema = z2.object({
|
|
1913
|
+
state: z2.string().optional(),
|
|
1914
|
+
blockedBy: blocked_by_schema
|
|
1915
|
+
});
|
|
1916
|
+
var rest_comment_schema = z2.looseObject({
|
|
1917
|
+
body: z2.string().nullish(),
|
|
1918
|
+
html_url: z2.string().optional(),
|
|
1919
|
+
user: z2.looseObject({ login: z2.string().optional() }).nullish()
|
|
1920
|
+
});
|
|
1921
|
+
var issue_label_schema = z2.object({ name: z2.string() });
|
|
1922
|
+
var epic_subject_schema = z2.object({
|
|
1923
|
+
number: z2.number(),
|
|
1924
|
+
state: z2.string().optional(),
|
|
1925
|
+
labels: z2.array(issue_label_schema).optional(),
|
|
1926
|
+
body: z2.string().optional()
|
|
1927
|
+
});
|
|
1928
|
+
var open_issue_schema = z2.object({
|
|
1929
|
+
number: z2.number(),
|
|
1930
|
+
title: z2.string(),
|
|
1931
|
+
labels: z2.array(issue_label_schema).optional(),
|
|
1932
|
+
createdAt: z2.string(),
|
|
1933
|
+
blockedBy: blocked_by_schema,
|
|
1934
|
+
// Present only on the pickup listing, which reads it for the restructures each issue declares.
|
|
1935
|
+
body: z2.string().optional()
|
|
1936
|
+
});
|
|
1937
|
+
|
|
1938
|
+
// scripts/gh/git-pr-checks-parse.ts
|
|
1939
|
+
var CHECK_STATUS_PASS = "pass";
|
|
1940
|
+
var CHECK_STATUS_PENDING = "pending";
|
|
1941
|
+
var CHECK_STATUS_FAIL = "fail";
|
|
1942
|
+
var CHECK_STATUS_MISSING = "missing";
|
|
1943
|
+
var PASSING_CONCLUSIONS = /* @__PURE__ */ new Set(["success", "skipped", "neutral"]);
|
|
1944
|
+
var KEY_TYPE_NAME = "__typename";
|
|
1945
|
+
var KEY_STATE = "state";
|
|
1946
|
+
var KEY_STATUS = "status";
|
|
1947
|
+
var KEY_CONCLUSION = "conclusion";
|
|
1948
|
+
var KEY_NAME = "name";
|
|
1949
|
+
var KEY_CONTEXT = "context";
|
|
1950
|
+
function read_string(value) {
|
|
1951
|
+
if (typeof value !== "string") return void 0;
|
|
1952
|
+
const trimmed = value.trim();
|
|
1953
|
+
if (trimmed.length === 0) return void 0;
|
|
1954
|
+
return trimmed;
|
|
1955
|
+
}
|
|
1956
|
+
var PENDING_STATUS_STATES = /* @__PURE__ */ new Set(["pending", "expected"]);
|
|
1957
|
+
function parse_status_context(item) {
|
|
1958
|
+
const state = read_string(item[KEY_STATE])?.toLowerCase();
|
|
1959
|
+
if (state === "success") return CHECK_STATUS_PASS;
|
|
1960
|
+
if (state !== void 0 && PENDING_STATUS_STATES.has(state)) return CHECK_STATUS_PENDING;
|
|
1961
|
+
return CHECK_STATUS_FAIL;
|
|
1962
|
+
}
|
|
1963
|
+
function is_passing_conclusion(item) {
|
|
1964
|
+
const conclusion = read_string(item[KEY_CONCLUSION])?.toLowerCase();
|
|
1965
|
+
return conclusion !== void 0 && PASSING_CONCLUSIONS.has(conclusion);
|
|
1966
|
+
}
|
|
1967
|
+
function parse_check_run(item) {
|
|
1968
|
+
const status = read_string(item[KEY_STATUS])?.toLowerCase();
|
|
1969
|
+
if (status !== "completed") return CHECK_STATUS_PENDING;
|
|
1970
|
+
return is_passing_conclusion(item) ? CHECK_STATUS_PASS : CHECK_STATUS_FAIL;
|
|
1971
|
+
}
|
|
1972
|
+
function parse_rollup_status(item) {
|
|
1973
|
+
const type_name = read_string(item[KEY_TYPE_NAME]);
|
|
1974
|
+
if (type_name === "StatusContext") return parse_status_context(item);
|
|
1975
|
+
return parse_check_run(item);
|
|
1976
|
+
}
|
|
1977
|
+
function read_rollup_array(parsed) {
|
|
1978
|
+
const result = pr_raw_schema.safeParse(parsed);
|
|
1979
|
+
if (!result.success) return [];
|
|
1980
|
+
return result.data.statusCheckRollup ?? [];
|
|
1981
|
+
}
|
|
1982
|
+
function parse_rollup_item(item) {
|
|
1983
|
+
const name = read_string(item[KEY_NAME]) ?? read_string(item[KEY_CONTEXT]);
|
|
1984
|
+
if (name === void 0) return void 0;
|
|
1985
|
+
return { name, status: parse_rollup_status(item) };
|
|
1986
|
+
}
|
|
1987
|
+
function parse_rollup_checks(raw_json) {
|
|
1988
|
+
const parsed = json_value.parse_or_undefined(raw_json);
|
|
1989
|
+
const rollup = read_rollup_array(parsed);
|
|
1990
|
+
const checks = [];
|
|
1991
|
+
for (const item of rollup) {
|
|
1992
|
+
const parsed_item = parse_rollup_item(item);
|
|
1993
|
+
if (parsed_item !== void 0) checks.push(parsed_item);
|
|
1994
|
+
}
|
|
1995
|
+
return checks;
|
|
1996
|
+
}
|
|
1997
|
+
function parse_pr_state_snapshot(raw_json) {
|
|
1998
|
+
const parsed = json_value.parse_or_undefined(raw_json);
|
|
1999
|
+
const result = pr_raw_schema.safeParse(parsed);
|
|
2000
|
+
const data = result.success ? result.data : void 0;
|
|
2001
|
+
return {
|
|
2002
|
+
rollup: parse_rollup_checks(raw_json),
|
|
2003
|
+
merge_state_status: read_string(data?.mergeStateStatus),
|
|
2004
|
+
review_decision: read_string(data?.reviewDecision)
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
// scripts/gh/git-pr-checks-eval.ts
|
|
2009
|
+
var DEFAULT_REQUIRED_CHECKS = ["SonarQube"];
|
|
2010
|
+
var CODERABBIT_CHECK_NAME = "CodeRabbit";
|
|
2011
|
+
var REQUIRED_CHECKS_ENV_VAR = "JOSH_REQUIRED_CHECKS";
|
|
2012
|
+
function parse_required_checks() {
|
|
2013
|
+
const raw = process.env[REQUIRED_CHECKS_ENV_VAR];
|
|
2014
|
+
if (!raw) return DEFAULT_REQUIRED_CHECKS;
|
|
2015
|
+
return raw.split(",").map((check) => check.trim()).filter((check) => check.length > 0);
|
|
2016
|
+
}
|
|
2017
|
+
var REQUIRED_CHECKS = parse_required_checks();
|
|
2018
|
+
var MERGE_STATE_CLEAN = "CLEAN";
|
|
2019
|
+
var MERGE_STATE_UNSTABLE = "UNSTABLE";
|
|
2020
|
+
var MERGE_STATE_DIRTY = "DIRTY";
|
|
2021
|
+
var REVIEW_CHANGES_REQUESTED = "CHANGES_REQUESTED";
|
|
2022
|
+
var CHECK_SUITE_SEPARATOR = " / ";
|
|
2023
|
+
var FAILURE_MESSAGE_PREFIX = "PR checks failed";
|
|
2024
|
+
var FAILURE_REASON_REVIEW = "review requested changes";
|
|
2025
|
+
var FAILURE_REASON_CHECKS = "failed checks";
|
|
2026
|
+
var FAILURE_REASON_CONFLICT = "merge conflict";
|
|
2027
|
+
function is_required_match(check_name, required_name) {
|
|
2028
|
+
if (check_name === required_name) return true;
|
|
2029
|
+
return check_name.startsWith(`${required_name}${CHECK_SUITE_SEPARATOR}`);
|
|
2030
|
+
}
|
|
2031
|
+
function find_required_check(checks, required_name) {
|
|
2032
|
+
return checks.find((check) => is_required_match(check.name, required_name));
|
|
2033
|
+
}
|
|
2034
|
+
function read_required_statuses(checks) {
|
|
2035
|
+
return REQUIRED_CHECKS.map(
|
|
2036
|
+
(name) => find_required_check(checks, name)?.status ?? CHECK_STATUS_MISSING
|
|
2037
|
+
);
|
|
2038
|
+
}
|
|
2039
|
+
function is_review_blocked(review_decision) {
|
|
2040
|
+
return review_decision === REVIEW_CHANGES_REQUESTED;
|
|
2041
|
+
}
|
|
2042
|
+
function is_merge_conflict(merge_state_status) {
|
|
2043
|
+
return merge_state_status === MERGE_STATE_DIRTY;
|
|
2044
|
+
}
|
|
2045
|
+
function evaluate_failure_state(input) {
|
|
2046
|
+
if (is_merge_conflict(input.merge_state_status) || is_review_blocked(input.review_decision) || input.failed_checks.length > 0) {
|
|
2047
|
+
return "failure";
|
|
2048
|
+
}
|
|
2049
|
+
return void 0;
|
|
2050
|
+
}
|
|
2051
|
+
function is_merge_state_clean(merge_state_status) {
|
|
2052
|
+
return merge_state_status === MERGE_STATE_CLEAN;
|
|
2053
|
+
}
|
|
2054
|
+
function is_every_required_passing(statuses) {
|
|
2055
|
+
return statuses.every((status) => status === CHECK_STATUS_PASS);
|
|
2056
|
+
}
|
|
2057
|
+
function is_coderabbit_check(check_name) {
|
|
2058
|
+
return is_required_match(check_name, CODERABBIT_CHECK_NAME);
|
|
2059
|
+
}
|
|
2060
|
+
function is_unstable_only_from_coderabbit(snapshot) {
|
|
2061
|
+
if (snapshot.merge_state_status !== MERGE_STATE_UNSTABLE) return false;
|
|
2062
|
+
const non_passing = snapshot.rollup.filter((check) => check.status !== CHECK_STATUS_PASS);
|
|
2063
|
+
if (non_passing.length === 0) return false;
|
|
2064
|
+
return non_passing.every((check) => is_coderabbit_check(check.name));
|
|
2065
|
+
}
|
|
2066
|
+
function is_required_check(check_name) {
|
|
2067
|
+
return REQUIRED_CHECKS.some((required) => is_required_match(check_name, required));
|
|
2068
|
+
}
|
|
2069
|
+
function is_blocking_failure(check) {
|
|
2070
|
+
if (check.status !== CHECK_STATUS_FAIL) return false;
|
|
2071
|
+
return !is_coderabbit_check(check.name) || is_required_check(check.name);
|
|
2072
|
+
}
|
|
2073
|
+
function collect_blocking_failures(snapshot) {
|
|
2074
|
+
return snapshot.rollup.filter((check) => is_blocking_failure(check)).map((check) => check.name);
|
|
2075
|
+
}
|
|
2076
|
+
function is_mergeable_state(snapshot) {
|
|
2077
|
+
if (is_merge_state_clean(snapshot.merge_state_status)) return true;
|
|
2078
|
+
return is_unstable_only_from_coderabbit(snapshot);
|
|
2079
|
+
}
|
|
2080
|
+
function collect_failure_reasons(snapshot) {
|
|
2081
|
+
const reasons = [];
|
|
2082
|
+
if (is_merge_conflict(snapshot.merge_state_status)) reasons.push(FAILURE_REASON_CONFLICT);
|
|
2083
|
+
if (is_review_blocked(snapshot.review_decision)) reasons.push(FAILURE_REASON_REVIEW);
|
|
2084
|
+
const failed = collect_blocking_failures(snapshot);
|
|
2085
|
+
if (failed.length > 0) reasons.push(`${FAILURE_REASON_CHECKS}: ${failed.join(", ")}`);
|
|
2086
|
+
return reasons;
|
|
2087
|
+
}
|
|
2088
|
+
function describe_pr_failure(snapshot) {
|
|
2089
|
+
const reasons = collect_failure_reasons(snapshot);
|
|
2090
|
+
if (reasons.length === 0) return `${FAILURE_MESSAGE_PREFIX}.`;
|
|
2091
|
+
return `${FAILURE_MESSAGE_PREFIX} (${reasons.join("; ")}).`;
|
|
2092
|
+
}
|
|
2093
|
+
function evaluate_pr_state(snapshot) {
|
|
2094
|
+
const statuses = read_required_statuses(snapshot.rollup);
|
|
2095
|
+
const failure = evaluate_failure_state({
|
|
2096
|
+
review_decision: snapshot.review_decision,
|
|
2097
|
+
failed_checks: collect_blocking_failures(snapshot),
|
|
2098
|
+
merge_state_status: snapshot.merge_state_status
|
|
2099
|
+
});
|
|
2100
|
+
if (failure !== void 0) return failure;
|
|
2101
|
+
if (is_mergeable_state(snapshot) && is_every_required_passing(statuses)) {
|
|
2102
|
+
return "success";
|
|
2103
|
+
}
|
|
2104
|
+
return "pending";
|
|
2105
|
+
}
|
|
2106
|
+
function is_review_decision_decisive(snapshot) {
|
|
2107
|
+
return evaluate_pr_state(snapshot) !== "pending";
|
|
2108
|
+
}
|
|
2109
|
+
var PrConflictError = class extends Error {
|
|
2110
|
+
name = "PrConflictError";
|
|
2111
|
+
};
|
|
2112
|
+
|
|
1858
2113
|
// scripts/time-runtime/time-format.ts
|
|
1859
2114
|
var MS_PER_MINUTE = 6e4;
|
|
1860
2115
|
var MS_PER_SECOND = 1e3;
|
|
@@ -1926,8 +2181,14 @@ var STAGE = {
|
|
|
1926
2181
|
// The lap that was still running when a stage threw. `followup` exits non-zero on an AI-review
|
|
1927
2182
|
// blocker and on a red check, and those are the runs whose wait is longest — reporting nothing for
|
|
1928
2183
|
// them would leave the measurement blind to exactly the invocations worth measuring.
|
|
1929
|
-
interrupted: "interrupted"
|
|
2184
|
+
interrupted: "interrupted",
|
|
2185
|
+
// The interrupted lap when the wait failed on a merge conflict (joshuafolkken/kit#3221), so the
|
|
2186
|
+
// stage block names the cause a resumed session used to look up with `gh pr view`.
|
|
2187
|
+
conflict: "conflict"
|
|
1930
2188
|
};
|
|
2189
|
+
function stopped_lap(error) {
|
|
2190
|
+
return error instanceof PrConflictError ? STAGE.conflict : STAGE.interrupted;
|
|
2191
|
+
}
|
|
1931
2192
|
function new_log() {
|
|
1932
2193
|
return { stages: [], last_ms: performance.now() };
|
|
1933
2194
|
}
|
|
@@ -1960,7 +2221,8 @@ var git_followup_stages = {
|
|
|
1960
2221
|
lap,
|
|
1961
2222
|
total_ms,
|
|
1962
2223
|
format_stages,
|
|
1963
|
-
print_stages
|
|
2224
|
+
print_stages,
|
|
2225
|
+
stopped_lap
|
|
1964
2226
|
};
|
|
1965
2227
|
|
|
1966
2228
|
// scripts/time-runtime/time-followup-stage.ts
|
|
@@ -2092,6 +2354,7 @@ var ISSUE_COMMENT_PATTERN = /\bgh\s+issue\s+comment\b/u;
|
|
|
2092
2354
|
var BODY_FLAG_PATTERN = /--body(?:-file)?\b/u;
|
|
2093
2355
|
var ISSUE_LABELS_PATTERN = /repos\/\S+\/issues\/(\d+)\/labels\b(?!\/)/u;
|
|
2094
2356
|
var IN_PROGRESS_FIELD = "labels[]=in-progress";
|
|
2357
|
+
var RUN_ENTRY_PATTERN = /\bjosh\s+run:entry\s+(\d+)\b/u;
|
|
2095
2358
|
var NO_ISSUE = cost_attribute.UNATTRIBUTED_KEY;
|
|
2096
2359
|
function string_field(input, key) {
|
|
2097
2360
|
if (!json_value.is_record(input)) return "";
|
|
@@ -2121,19 +2384,23 @@ function is_issue_comment(command) {
|
|
|
2121
2384
|
function is_in_progress_label(command) {
|
|
2122
2385
|
return ISSUE_LABELS_PATTERN.test(command) && command.includes(IN_PROGRESS_FIELD);
|
|
2123
2386
|
}
|
|
2387
|
+
function is_run_start(command) {
|
|
2388
|
+
return is_in_progress_label(command) || RUN_ENTRY_PATTERN.test(command);
|
|
2389
|
+
}
|
|
2124
2390
|
var COMMAND_SEPARATOR = /&&|\|\||;/u;
|
|
2125
|
-
function
|
|
2126
|
-
const
|
|
2391
|
+
function declared_issue2(part) {
|
|
2392
|
+
const pattern = is_in_progress_label(part) ? ISSUE_LABELS_PATTERN : RUN_ENTRY_PATTERN;
|
|
2393
|
+
const matched = pattern.exec(part);
|
|
2127
2394
|
return matched?.[1] === void 0 ? NO_ISSUE : Number(matched[1]);
|
|
2128
2395
|
}
|
|
2129
2396
|
function bash_issue(command) {
|
|
2130
2397
|
for (const part of command.split(COMMAND_SEPARATOR)) {
|
|
2131
|
-
if (
|
|
2398
|
+
if (is_run_start(part)) return declared_issue2(part);
|
|
2132
2399
|
}
|
|
2133
2400
|
return NO_ISSUE;
|
|
2134
2401
|
}
|
|
2135
2402
|
function bash_marker(command) {
|
|
2136
|
-
if (
|
|
2403
|
+
if (is_run_start(command)) return WORKFLOW_MARKER;
|
|
2137
2404
|
return is_api_body_write(command) || is_issue_comment(command) ? PLAN_MARKER : NO_MARKER;
|
|
2138
2405
|
}
|
|
2139
2406
|
var time_markers = {
|
|
@@ -2190,9 +2457,9 @@ var josh_verdict = {
|
|
|
2190
2457
|
};
|
|
2191
2458
|
|
|
2192
2459
|
// scripts/time-runtime/time-reported-failure.ts
|
|
2193
|
-
import { z as
|
|
2194
|
-
var TEXT_BLOCK_SCHEMA =
|
|
2195
|
-
var CONTENT_SCHEMA =
|
|
2460
|
+
import { z as z3 } from "zod";
|
|
2461
|
+
var TEXT_BLOCK_SCHEMA = z3.object({ text: z3.string().nullish() });
|
|
2462
|
+
var CONTENT_SCHEMA = z3.union([z3.string(), z3.array(z3.unknown())]);
|
|
2196
2463
|
var LINE_SEPARATOR2 = "\n";
|
|
2197
2464
|
function block_text(block) {
|
|
2198
2465
|
const parsed = TEXT_BLOCK_SCHEMA.safeParse(block);
|
|
@@ -2287,7 +2554,7 @@ function check_key(josh_command, command) {
|
|
|
2287
2554
|
var time_single_check = { NO_CHECK, check_key };
|
|
2288
2555
|
|
|
2289
2556
|
// scripts/time-runtime/time-transcript-line.ts
|
|
2290
|
-
import { z as
|
|
2557
|
+
import { z as z4 } from "zod";
|
|
2291
2558
|
|
|
2292
2559
|
// scripts/time-runtime/time-instant.ts
|
|
2293
2560
|
function parse_instant(raw) {
|
|
@@ -2297,37 +2564,37 @@ function parse_instant(raw) {
|
|
|
2297
2564
|
var time_instant = { parse_instant };
|
|
2298
2565
|
|
|
2299
2566
|
// scripts/time-runtime/time-transcript-line.ts
|
|
2300
|
-
var BLOCK_SCHEMA2 =
|
|
2301
|
-
type:
|
|
2302
|
-
name:
|
|
2303
|
-
id:
|
|
2304
|
-
tool_use_id:
|
|
2305
|
-
input:
|
|
2567
|
+
var BLOCK_SCHEMA2 = z4.object({
|
|
2568
|
+
type: z4.string().nullish(),
|
|
2569
|
+
name: z4.string().nullish(),
|
|
2570
|
+
id: z4.string().nullish(),
|
|
2571
|
+
tool_use_id: z4.string().nullish(),
|
|
2572
|
+
input: z4.unknown().nullish(),
|
|
2306
2573
|
// Whether the harness wrote this result back as a failure (joshuafolkken/kit#1309). Present on a
|
|
2307
2574
|
// `tool_result` block and on nothing else, and absent even there for the tools that never report
|
|
2308
2575
|
// one — which is why it is read as three answers rather than as a boolean with a default.
|
|
2309
|
-
is_error:
|
|
2576
|
+
is_error: z4.boolean().nullish(),
|
|
2310
2577
|
// What the call printed. Read only to recover the outcome a pipeline threw away
|
|
2311
2578
|
// (joshuafolkken/kit#1361): it is kept as flattened text rather than as blocks, because that is
|
|
2312
2579
|
// the whole of what `time-reported-failure.ts` asks of it.
|
|
2313
|
-
content:
|
|
2580
|
+
content: z4.unknown().nullish()
|
|
2314
2581
|
});
|
|
2315
|
-
var CONTENT_SCHEMA2 =
|
|
2316
|
-
var MESSAGE_SCHEMA2 =
|
|
2317
|
-
var LINE_SCHEMA =
|
|
2318
|
-
type:
|
|
2319
|
-
timestamp:
|
|
2582
|
+
var CONTENT_SCHEMA2 = z4.union([z4.string(), z4.array(BLOCK_SCHEMA2)]);
|
|
2583
|
+
var MESSAGE_SCHEMA2 = z4.object({ id: z4.string().nullish(), content: CONTENT_SCHEMA2.nullish() });
|
|
2584
|
+
var LINE_SCHEMA = z4.object({
|
|
2585
|
+
type: z4.string().nullish(),
|
|
2586
|
+
timestamp: z4.string().nullish(),
|
|
2320
2587
|
// The branch the line was written on, which is where the issue number lives — `josh git` names a
|
|
2321
2588
|
// branch `<N>-<slug>`. Read here rather than re-parsed by a second reader so `josh time --issue`
|
|
2322
2589
|
// and `josh cost --issue` answer from the same field (joshuafolkken/kit#1268).
|
|
2323
|
-
gitBranch:
|
|
2590
|
+
gitBranch: z4.string().nullish(),
|
|
2324
2591
|
// The two fields outside `message` that the harness writes an end-of-task notice on
|
|
2325
2592
|
// (joshuafolkken/kit#1696). **Both are read as `unknown` rather than as strings**: a schema
|
|
2326
2593
|
// insisting on a string here would reject every line whose `content` is a list of blocks — which is
|
|
2327
2594
|
// most of them — and a rejected line is dropped from the timeline entirely, so the shares would stop
|
|
2328
2595
|
// reconstructing the elapsed time. The shape is checked at the read below instead.
|
|
2329
|
-
content:
|
|
2330
|
-
attachment:
|
|
2596
|
+
content: z4.unknown().nullish(),
|
|
2597
|
+
attachment: z4.unknown().nullish(),
|
|
2331
2598
|
message: MESSAGE_SCHEMA2.nullish()
|
|
2332
2599
|
});
|
|
2333
2600
|
var UNKNOWN_BRANCH = "";
|
|
@@ -2335,6 +2602,9 @@ var PROMPT_KEY2 = "prompt";
|
|
|
2335
2602
|
var NO_MESSAGE_ID = "";
|
|
2336
2603
|
var ERROR_TEXT_LIMIT = 256;
|
|
2337
2604
|
var REFUSAL_MARKER = "\u26D4";
|
|
2605
|
+
var HOOK_ERROR_LABEL = /^PreToolUse:\S+ hook error: /u;
|
|
2606
|
+
var TOKEN_LINE = /^[a-z][a-z-]*$/u;
|
|
2607
|
+
var TOKEN_LINE_LIMIT = 8;
|
|
2338
2608
|
function block_names(raw) {
|
|
2339
2609
|
return {
|
|
2340
2610
|
type: raw.type ?? "",
|
|
@@ -2344,12 +2614,15 @@ function block_names(raw) {
|
|
|
2344
2614
|
};
|
|
2345
2615
|
}
|
|
2346
2616
|
function guard_from_refusal(text) {
|
|
2347
|
-
const trimmed = text.trimStart();
|
|
2617
|
+
const trimmed = text.trimStart().replace(HOOK_ERROR_LABEL, "");
|
|
2348
2618
|
if (!trimmed.startsWith(REFUSAL_MARKER)) return "";
|
|
2349
2619
|
const headline = trimmed.slice(REFUSAL_MARKER.length).split("\n", 1)[0]?.trimStart() ?? "";
|
|
2350
2620
|
const colon = headline.indexOf(":");
|
|
2351
2621
|
return (colon === -1 ? headline : headline.slice(0, colon)).trim();
|
|
2352
2622
|
}
|
|
2623
|
+
function token_lines_of(text) {
|
|
2624
|
+
return text.split("\n").map((line) => line.trim()).filter((line) => TOKEN_LINE.test(line)).slice(0, TOKEN_LINE_LIMIT);
|
|
2625
|
+
}
|
|
2353
2626
|
function to_block2(raw) {
|
|
2354
2627
|
const text = time_reported_failure.result_text(raw.content);
|
|
2355
2628
|
const is_error = raw.is_error ?? void 0;
|
|
@@ -2361,6 +2634,7 @@ function to_block2(raw) {
|
|
|
2361
2634
|
followup_stages: time_followup_stage.read_stages(text),
|
|
2362
2635
|
error_text: is_error === true ? text.slice(0, ERROR_TEXT_LIMIT) : "",
|
|
2363
2636
|
refusal_guard: is_error === true ? guard_from_refusal(text) : "",
|
|
2637
|
+
token_lines: is_error === true ? [] : token_lines_of(text),
|
|
2364
2638
|
background_id: time_background.launch_id(text),
|
|
2365
2639
|
agent_id: time_background.agent_launch_id(text)
|
|
2366
2640
|
};
|
|
@@ -2394,6 +2668,7 @@ function parse_line2(line) {
|
|
|
2394
2668
|
var time_transcript_line = {
|
|
2395
2669
|
ERROR_TEXT_LIMIT,
|
|
2396
2670
|
NO_MESSAGE_ID,
|
|
2671
|
+
TOKEN_LINE_LIMIT,
|
|
2397
2672
|
guard_from_refusal,
|
|
2398
2673
|
parse_line: parse_line2
|
|
2399
2674
|
};
|
|
@@ -2631,6 +2906,530 @@ var time_spans = {
|
|
|
2631
2906
|
parse_timeline
|
|
2632
2907
|
};
|
|
2633
2908
|
|
|
2909
|
+
// scripts/time-runtime/time-round-trips.ts
|
|
2910
|
+
var CALLS_PER_ROUND_TRIP_FLOOR = 1.5;
|
|
2911
|
+
var DENSITY_DECIMALS = 2;
|
|
2912
|
+
var NONE = 0;
|
|
2913
|
+
function is_tool(span) {
|
|
2914
|
+
return span.category === time_spans.TOOL_CATEGORY;
|
|
2915
|
+
}
|
|
2916
|
+
function is_model(span) {
|
|
2917
|
+
return span.category === time_spans.MODEL_CATEGORY;
|
|
2918
|
+
}
|
|
2919
|
+
function started_ms2(span) {
|
|
2920
|
+
return span.ended_ms - span.duration_ms;
|
|
2921
|
+
}
|
|
2922
|
+
function in_time_order(spans) {
|
|
2923
|
+
return spans.toSorted((left, right) => started_ms2(left) - started_ms2(right));
|
|
2924
|
+
}
|
|
2925
|
+
function is_tool_at(spans, index) {
|
|
2926
|
+
const span = spans[index];
|
|
2927
|
+
return span !== void 0 && is_tool(span);
|
|
2928
|
+
}
|
|
2929
|
+
function is_call(span) {
|
|
2930
|
+
return is_tool(span) && !span.is_continuation;
|
|
2931
|
+
}
|
|
2932
|
+
function count_calls(spans) {
|
|
2933
|
+
return spans.filter((span) => is_call(span)).length;
|
|
2934
|
+
}
|
|
2935
|
+
function previous_break(spans, index) {
|
|
2936
|
+
for (let back = index - 1; back >= 0; back -= 1) {
|
|
2937
|
+
const span = spans[back];
|
|
2938
|
+
if (span === void 0 || !is_model(span)) return span;
|
|
2939
|
+
}
|
|
2940
|
+
return void 0;
|
|
2941
|
+
}
|
|
2942
|
+
function continues_turn(spans, index, message_id) {
|
|
2943
|
+
if (message_id === time_spans.NO_MESSAGE_ID) return false;
|
|
2944
|
+
const earlier = previous_break(spans, index);
|
|
2945
|
+
return earlier !== void 0 && !earlier.is_continuation && earlier.message_id === message_id;
|
|
2946
|
+
}
|
|
2947
|
+
function opens_round_trip(spans, index) {
|
|
2948
|
+
const span = spans[index];
|
|
2949
|
+
if (span === void 0 || !is_tool(span) || span.is_continuation || is_tool_at(spans, index - 1)) {
|
|
2950
|
+
return false;
|
|
2951
|
+
}
|
|
2952
|
+
return !continues_turn(spans, index, span.message_id);
|
|
2953
|
+
}
|
|
2954
|
+
function open_trip(walk) {
|
|
2955
|
+
walk.open = [];
|
|
2956
|
+
walk.trips.push(walk.open);
|
|
2957
|
+
}
|
|
2958
|
+
function place_call(walk, span) {
|
|
2959
|
+
if (is_call(span)) walk.open?.push(span);
|
|
2960
|
+
}
|
|
2961
|
+
function step_trip(walk, span, is_opener) {
|
|
2962
|
+
if (is_opener) open_trip(walk);
|
|
2963
|
+
if (is_tool(span)) place_call(walk, span);
|
|
2964
|
+
else if (!is_model(span)) walk.open = void 0;
|
|
2965
|
+
}
|
|
2966
|
+
function group_round_trips(spans) {
|
|
2967
|
+
const ordered = in_time_order(spans);
|
|
2968
|
+
const walk = { trips: [], open: void 0 };
|
|
2969
|
+
for (const [index, span] of ordered.entries()) {
|
|
2970
|
+
step_trip(walk, span, opens_round_trip(ordered, index));
|
|
2971
|
+
}
|
|
2972
|
+
return walk.trips;
|
|
2973
|
+
}
|
|
2974
|
+
function count_round_trips(spans) {
|
|
2975
|
+
return group_round_trips(spans).length;
|
|
2976
|
+
}
|
|
2977
|
+
function turn_key(span, index) {
|
|
2978
|
+
return span.message_id === time_spans.NO_MESSAGE_ID ? `#${String(index)}` : span.message_id;
|
|
2979
|
+
}
|
|
2980
|
+
function count_turns(spans) {
|
|
2981
|
+
const keys = spans.filter((span) => is_model(span)).map((span, index) => turn_key(span, index));
|
|
2982
|
+
return new Set(keys).size;
|
|
2983
|
+
}
|
|
2984
|
+
function per_round_trip(total, round_trip_count) {
|
|
2985
|
+
if (round_trip_count === NONE) return NONE;
|
|
2986
|
+
return total / round_trip_count;
|
|
2987
|
+
}
|
|
2988
|
+
function format_density(density) {
|
|
2989
|
+
return density.toFixed(DENSITY_DECIMALS);
|
|
2990
|
+
}
|
|
2991
|
+
function is_below_floor(density) {
|
|
2992
|
+
return density > NONE && density < CALLS_PER_ROUND_TRIP_FLOOR;
|
|
2993
|
+
}
|
|
2994
|
+
var time_round_trips = {
|
|
2995
|
+
CALLS_PER_ROUND_TRIP_FLOOR,
|
|
2996
|
+
count_calls,
|
|
2997
|
+
count_round_trips,
|
|
2998
|
+
// Exported since joshuafolkken/kit#1406, so a turn is defined in the one module that already
|
|
2999
|
+
// defines a round trip rather than as a span filter in the report next door.
|
|
3000
|
+
count_turns,
|
|
3001
|
+
format_density,
|
|
3002
|
+
// Exported since joshuafolkken/kit#1385, so the per-tool counts are read off the very groups this
|
|
3003
|
+
// module counts rather than off a second grouping beside them.
|
|
3004
|
+
group_round_trips,
|
|
3005
|
+
// Exported since joshuafolkken/kit#1309, so the failure aggregation orders a run's spans through
|
|
3006
|
+
// the one function that already knows why they need it — a second `toSorted` beside it would be
|
|
3007
|
+
// the clone `CLAUDE.md` prohibits, and the seam it guards (a delegated unit's spans appended
|
|
3008
|
+
// after the parent's) is not one a second copy would keep remembering.
|
|
3009
|
+
in_time_order,
|
|
3010
|
+
is_below_floor,
|
|
3011
|
+
// The four below are exported since joshuafolkken/kit#1406, when the model-gap walk moved to
|
|
3012
|
+
// `time-model-gaps.ts` and needed the same predicates and the same opener test this walk uses. A
|
|
3013
|
+
// private copy there would be the clone `CLAUDE.md` prohibits, in the one place a drift would have
|
|
3014
|
+
// the distribution and the count disagreeing about what a round trip is.
|
|
3015
|
+
per_round_trip
|
|
3016
|
+
};
|
|
3017
|
+
|
|
3018
|
+
// scripts/time-runtime/time-agent-bundles.ts
|
|
3019
|
+
var NONE2 = 0;
|
|
3020
|
+
var ONE = 1;
|
|
3021
|
+
var MIN_GROUP = 2;
|
|
3022
|
+
function is_launch2(span) {
|
|
3023
|
+
return span.category === time_spans.TOOL_CATEGORY && !span.is_continuation && time_bundle_call.is_launch_tool(span.label);
|
|
3024
|
+
}
|
|
3025
|
+
function new_walk() {
|
|
3026
|
+
return { closed: [], open: NONE2, wrote_since: false, turn_id: time_spans.NO_MESSAGE_ID };
|
|
3027
|
+
}
|
|
3028
|
+
function close_group(walk) {
|
|
3029
|
+
if (walk.open >= MIN_GROUP) walk.closed.push(walk.open);
|
|
3030
|
+
walk.open = NONE2;
|
|
3031
|
+
}
|
|
3032
|
+
function is_same_turn(walk, span) {
|
|
3033
|
+
return span.message_id !== time_spans.NO_MESSAGE_ID && span.message_id === walk.turn_id;
|
|
3034
|
+
}
|
|
3035
|
+
function open_turn(walk, span) {
|
|
3036
|
+
if (walk.wrote_since || span.has_prior_reference) close_group(walk);
|
|
3037
|
+
walk.open += ONE;
|
|
3038
|
+
walk.turn_id = span.message_id;
|
|
3039
|
+
walk.wrote_since = false;
|
|
3040
|
+
}
|
|
3041
|
+
function step(walk, span) {
|
|
3042
|
+
if (span.is_writing) {
|
|
3043
|
+
walk.wrote_since = true;
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3046
|
+
if (!is_launch2(span) || is_same_turn(walk, span)) return;
|
|
3047
|
+
open_turn(walk, span);
|
|
3048
|
+
}
|
|
3049
|
+
function agent_bundles(spans) {
|
|
3050
|
+
const walk = new_walk();
|
|
3051
|
+
for (const span of time_round_trips.in_time_order(spans)) step(walk, span);
|
|
3052
|
+
close_group(walk);
|
|
3053
|
+
return walk.closed;
|
|
3054
|
+
}
|
|
3055
|
+
var time_agent_bundles = { agent_bundles };
|
|
3056
|
+
|
|
3057
|
+
// scripts/time-runtime/time-bundles.ts
|
|
3058
|
+
var { unmeasured_row: unmeasured_row2 } = time_format;
|
|
3059
|
+
var HEADING = "Bundling:";
|
|
3060
|
+
var SEQUENCE_LABEL = "bundleable sequences";
|
|
3061
|
+
var RECOVERABLE_LABEL = "recoverable round trips";
|
|
3062
|
+
var SAVING_LABEL = "recoverable wait";
|
|
3063
|
+
var BY_TOOL_LABEL = "recoverable by tool";
|
|
3064
|
+
var AGENT_ROW_LABEL = "Agent";
|
|
3065
|
+
var ROW_INDENT = " ";
|
|
3066
|
+
var MIN_SEQUENCE = 2;
|
|
3067
|
+
var ONE_CALL = 1;
|
|
3068
|
+
var NONE3 = 0;
|
|
3069
|
+
var PATH_SEPARATOR2 = "/";
|
|
3070
|
+
var FIRST_CALL = 1;
|
|
3071
|
+
var NO_LABEL = "";
|
|
3072
|
+
var NO_BUNDLES = {
|
|
3073
|
+
sequence_count: 0,
|
|
3074
|
+
longest_sequence: 0,
|
|
3075
|
+
recoverable_round_trips: 0,
|
|
3076
|
+
by_tool: [],
|
|
3077
|
+
unattributed_round_trips: 0,
|
|
3078
|
+
is_measured: false
|
|
3079
|
+
};
|
|
3080
|
+
function contains_segments(whole, part) {
|
|
3081
|
+
if (whole.startsWith(`${part}${PATH_SEPARATOR2}`)) return true;
|
|
3082
|
+
return whole.endsWith(`${PATH_SEPARATOR2}${part}`) || whole.includes(`${PATH_SEPARATOR2}${part}${PATH_SEPARATOR2}`);
|
|
3083
|
+
}
|
|
3084
|
+
function is_related(left, right) {
|
|
3085
|
+
if (left === right) return true;
|
|
3086
|
+
return contains_segments(left, right) || contains_segments(right, left);
|
|
3087
|
+
}
|
|
3088
|
+
function shares_target(left, right) {
|
|
3089
|
+
return left.some((one) => right.some((other) => is_related(one, other)));
|
|
3090
|
+
}
|
|
3091
|
+
function is_dependent(earlier, later) {
|
|
3092
|
+
if (earlier.is_writing && later.is_writing) return false;
|
|
3093
|
+
return shares_target(earlier.targets, later.targets);
|
|
3094
|
+
}
|
|
3095
|
+
function conflicts(span, sequence) {
|
|
3096
|
+
return sequence.some((earlier) => is_dependent(earlier, span));
|
|
3097
|
+
}
|
|
3098
|
+
function is_call2(span) {
|
|
3099
|
+
return span.category === time_spans.TOOL_CATEGORY && !span.is_continuation;
|
|
3100
|
+
}
|
|
3101
|
+
function is_turn_boundary(span) {
|
|
3102
|
+
return span.category === time_spans.MODEL_CATEGORY;
|
|
3103
|
+
}
|
|
3104
|
+
function new_walk2() {
|
|
3105
|
+
return { pending: [], sequence: [], closed: [] };
|
|
3106
|
+
}
|
|
3107
|
+
function flush(walk) {
|
|
3108
|
+
if (walk.sequence.length >= MIN_SEQUENCE) walk.closed.push(walk.sequence);
|
|
3109
|
+
walk.sequence = [];
|
|
3110
|
+
}
|
|
3111
|
+
function extend(walk, span) {
|
|
3112
|
+
if (conflicts(span, walk.sequence)) flush(walk);
|
|
3113
|
+
walk.sequence.push(span);
|
|
3114
|
+
}
|
|
3115
|
+
function close_trip(walk) {
|
|
3116
|
+
const [only] = walk.pending;
|
|
3117
|
+
if (walk.pending.length === ONE_CALL && only?.is_bundleable === true) extend(walk, only);
|
|
3118
|
+
else if (walk.pending.length > NONE3) flush(walk);
|
|
3119
|
+
walk.pending = [];
|
|
3120
|
+
}
|
|
3121
|
+
function is_same_turn2(span, pending) {
|
|
3122
|
+
const [first] = pending;
|
|
3123
|
+
if (first === void 0 || span.is_continuation || span.message_id === time_spans.NO_MESSAGE_ID) {
|
|
3124
|
+
return false;
|
|
3125
|
+
}
|
|
3126
|
+
return span.message_id === first.message_id;
|
|
3127
|
+
}
|
|
3128
|
+
function step2(walk, span) {
|
|
3129
|
+
if (is_call2(span)) {
|
|
3130
|
+
walk.pending.push(span);
|
|
3131
|
+
return;
|
|
3132
|
+
}
|
|
3133
|
+
if (is_same_turn2(span, walk.pending)) return;
|
|
3134
|
+
close_trip(walk);
|
|
3135
|
+
if (!is_turn_boundary(span)) flush(walk);
|
|
3136
|
+
}
|
|
3137
|
+
function longest_of(sizes) {
|
|
3138
|
+
return sizes.length === NONE3 ? NONE3 : Math.max(...sizes);
|
|
3139
|
+
}
|
|
3140
|
+
function recoverable_of(sizes) {
|
|
3141
|
+
return sizes.reduce((sum, size) => sum + size - ONE_CALL, NONE3);
|
|
3142
|
+
}
|
|
3143
|
+
function sizes_of(closed) {
|
|
3144
|
+
return closed.map((sequence) => sequence.length);
|
|
3145
|
+
}
|
|
3146
|
+
function tally_for(tallies, label) {
|
|
3147
|
+
const found = tallies.get(label);
|
|
3148
|
+
if (found !== void 0) return found;
|
|
3149
|
+
const created = { sequence_count: NONE3, recoverable_round_trips: NONE3 };
|
|
3150
|
+
tallies.set(label, created);
|
|
3151
|
+
return created;
|
|
3152
|
+
}
|
|
3153
|
+
function count_trip(tallies, counted, label) {
|
|
3154
|
+
const tally2 = tally_for(tallies, label);
|
|
3155
|
+
tally2.recoverable_round_trips += ONE_CALL;
|
|
3156
|
+
if (!counted.has(label)) tally2.sequence_count += ONE_CALL;
|
|
3157
|
+
counted.add(label);
|
|
3158
|
+
}
|
|
3159
|
+
function tally_sequence(tallies, sequence) {
|
|
3160
|
+
const counted = /* @__PURE__ */ new Set();
|
|
3161
|
+
for (const span of sequence.slice(FIRST_CALL)) {
|
|
3162
|
+
if (span.label !== NO_LABEL) count_trip(tallies, counted, span.label);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
function by_weight(left, right) {
|
|
3166
|
+
if (left.recoverable_round_trips !== right.recoverable_round_trips) {
|
|
3167
|
+
return right.recoverable_round_trips - left.recoverable_round_trips;
|
|
3168
|
+
}
|
|
3169
|
+
return left.label.localeCompare(right.label);
|
|
3170
|
+
}
|
|
3171
|
+
function tool_rows(closed) {
|
|
3172
|
+
const tallies = /* @__PURE__ */ new Map();
|
|
3173
|
+
for (const sequence of closed) tally_sequence(tallies, sequence);
|
|
3174
|
+
return [...tallies].map(([label, tally2]) => ({ label, ...tally2 })).toSorted(by_weight);
|
|
3175
|
+
}
|
|
3176
|
+
function attributed_of(rows) {
|
|
3177
|
+
return rows.reduce((sum, row) => sum + row.recoverable_round_trips, NONE3);
|
|
3178
|
+
}
|
|
3179
|
+
function with_agent_row(rows, agent_sizes) {
|
|
3180
|
+
const recoverable_round_trips = recoverable_of(agent_sizes);
|
|
3181
|
+
if (recoverable_round_trips === NONE3) return [...rows];
|
|
3182
|
+
const row = {
|
|
3183
|
+
label: AGENT_ROW_LABEL,
|
|
3184
|
+
sequence_count: agent_sizes.length,
|
|
3185
|
+
recoverable_round_trips
|
|
3186
|
+
};
|
|
3187
|
+
return [...rows, row].toSorted(by_weight);
|
|
3188
|
+
}
|
|
3189
|
+
function build_bundles(spans) {
|
|
3190
|
+
const walk = new_walk2();
|
|
3191
|
+
for (const span of time_round_trips.in_time_order(spans)) step2(walk, span);
|
|
3192
|
+
close_trip(walk);
|
|
3193
|
+
flush(walk);
|
|
3194
|
+
const sizes = sizes_of(walk.closed);
|
|
3195
|
+
const agent_sizes = time_agent_bundles.agent_bundles(spans);
|
|
3196
|
+
const by_tool = with_agent_row(tool_rows(walk.closed), agent_sizes);
|
|
3197
|
+
const recoverable_round_trips = recoverable_of(sizes) + recoverable_of(agent_sizes);
|
|
3198
|
+
return {
|
|
3199
|
+
sequence_count: sizes.length + agent_sizes.length,
|
|
3200
|
+
longest_sequence: Math.max(longest_of(sizes), longest_of(agent_sizes)),
|
|
3201
|
+
recoverable_round_trips,
|
|
3202
|
+
by_tool,
|
|
3203
|
+
unattributed_round_trips: recoverable_round_trips - attributed_of(by_tool),
|
|
3204
|
+
is_measured: time_spans.has_transcript_data(spans.length)
|
|
3205
|
+
};
|
|
3206
|
+
}
|
|
3207
|
+
function open_sequence(spans) {
|
|
3208
|
+
const walk = new_walk2();
|
|
3209
|
+
for (const span of time_round_trips.in_time_order(spans)) step2(walk, span);
|
|
3210
|
+
return walk.sequence;
|
|
3211
|
+
}
|
|
3212
|
+
function sequence_suffix(totals) {
|
|
3213
|
+
return `longest ${String(totals.longest_sequence)} turn(s)`;
|
|
3214
|
+
}
|
|
3215
|
+
function recoverable_suffix(totals, round_trip_count) {
|
|
3216
|
+
const share = time_format.format_share(totals.recoverable_round_trips, round_trip_count);
|
|
3217
|
+
return `${share} of ${String(round_trip_count)} round trip(s)`;
|
|
3218
|
+
}
|
|
3219
|
+
function saving_line(totals, model_ms_per_round_trip) {
|
|
3220
|
+
const saved_ms = totals.recoverable_round_trips * model_ms_per_round_trip;
|
|
3221
|
+
const rate = `at ${time_format.format_seconds(model_ms_per_round_trip)} model time per round trip`;
|
|
3222
|
+
return time_format.format_row(SAVING_LABEL, saved_ms, rate);
|
|
3223
|
+
}
|
|
3224
|
+
function by_tool_suffix(totals) {
|
|
3225
|
+
const attributed = totals.recoverable_round_trips - totals.unattributed_round_trips;
|
|
3226
|
+
return `${String(attributed)} of ${String(totals.recoverable_round_trips)} attributed`;
|
|
3227
|
+
}
|
|
3228
|
+
function tool_row(row) {
|
|
3229
|
+
return time_format.format_columns(
|
|
3230
|
+
`${ROW_INDENT}${row.label}`,
|
|
3231
|
+
String(row.recoverable_round_trips),
|
|
3232
|
+
`in ${String(row.sequence_count)} sequence(s)`
|
|
3233
|
+
);
|
|
3234
|
+
}
|
|
3235
|
+
function by_tool_lines(totals) {
|
|
3236
|
+
const heading = time_format.format_columns(
|
|
3237
|
+
BY_TOOL_LABEL,
|
|
3238
|
+
String(totals.by_tool.length),
|
|
3239
|
+
by_tool_suffix(totals)
|
|
3240
|
+
);
|
|
3241
|
+
const rows = totals.by_tool.slice(NONE3, time_format.MAX_ROWS).map((row) => tool_row(row));
|
|
3242
|
+
return [heading, ...rows, ...time_format.overflow_line(totals.by_tool.length)];
|
|
3243
|
+
}
|
|
3244
|
+
function measured_lines(totals, price) {
|
|
3245
|
+
return [
|
|
3246
|
+
time_format.format_columns(
|
|
3247
|
+
SEQUENCE_LABEL,
|
|
3248
|
+
String(totals.sequence_count),
|
|
3249
|
+
sequence_suffix(totals)
|
|
3250
|
+
),
|
|
3251
|
+
time_format.format_columns(
|
|
3252
|
+
RECOVERABLE_LABEL,
|
|
3253
|
+
String(totals.recoverable_round_trips),
|
|
3254
|
+
recoverable_suffix(totals, price.round_trip_count)
|
|
3255
|
+
),
|
|
3256
|
+
saving_line(totals, price.model_ms_per_round_trip),
|
|
3257
|
+
...by_tool_lines(totals)
|
|
3258
|
+
];
|
|
3259
|
+
}
|
|
3260
|
+
var LABELS = [SEQUENCE_LABEL, RECOVERABLE_LABEL, SAVING_LABEL, BY_TOOL_LABEL];
|
|
3261
|
+
function no_divisor_lines() {
|
|
3262
|
+
return LABELS.map((label) => time_format.format_columns(label, "", time_format.NO_CALLS));
|
|
3263
|
+
}
|
|
3264
|
+
function bundle_lines(totals, price) {
|
|
3265
|
+
const heading = ["", HEADING];
|
|
3266
|
+
if (!totals.is_measured) return [...heading, ...LABELS.map((label) => unmeasured_row2(label))];
|
|
3267
|
+
if (price.round_trip_count === NONE3) return [...heading, ...no_divisor_lines()];
|
|
3268
|
+
return [...heading, ...measured_lines(totals, price)];
|
|
3269
|
+
}
|
|
3270
|
+
var time_bundles = {
|
|
3271
|
+
HEADING,
|
|
3272
|
+
BY_TOOL_LABEL,
|
|
3273
|
+
NO_BUNDLES,
|
|
3274
|
+
build_bundles,
|
|
3275
|
+
bundle_lines,
|
|
3276
|
+
is_dependent,
|
|
3277
|
+
open_sequence,
|
|
3278
|
+
shares_target
|
|
3279
|
+
};
|
|
3280
|
+
|
|
3281
|
+
// scripts/time-runtime/time-command-key.ts
|
|
3282
|
+
var UNNAMED_KEY = "";
|
|
3283
|
+
function command_key(span) {
|
|
3284
|
+
if (span.label === time_spans.UNKNOWN_TOOL) return UNNAMED_KEY;
|
|
3285
|
+
return span.josh_command === "" ? span.label : span.josh_command;
|
|
3286
|
+
}
|
|
3287
|
+
var time_command_key = { UNNAMED_KEY, command_key };
|
|
3288
|
+
|
|
3289
|
+
// scripts/time-runtime/time-call-identity.ts
|
|
3290
|
+
var IDENTITY_SEPARATOR = "\0";
|
|
3291
|
+
function identity_of(call) {
|
|
3292
|
+
return [
|
|
3293
|
+
time_command_key.command_key(call),
|
|
3294
|
+
call.check_key,
|
|
3295
|
+
[...call.targets].toSorted((left, right) => left.localeCompare(right)).join(",")
|
|
3296
|
+
].join(IDENTITY_SEPARATOR);
|
|
3297
|
+
}
|
|
3298
|
+
var time_call_identity = { identity_of };
|
|
3299
|
+
|
|
3300
|
+
// scripts/time-runtime/time-batch-guard.ts
|
|
3301
|
+
var CONSECUTIVE_LIMIT = 3;
|
|
3302
|
+
var REFIRE_EVERY = CONSECUTIVE_LIMIT;
|
|
3303
|
+
var ONE_TURN = 1;
|
|
3304
|
+
var NONE4 = 0;
|
|
3305
|
+
var NOTICE_REFIRE_EVERY = ONE_TURN;
|
|
3306
|
+
var NAMED_CANDIDATE_COUNT = 3;
|
|
3307
|
+
var SEQUENCE_BEFORE_LIMIT = CONSECUTIVE_LIMIT - ONE_TURN;
|
|
3308
|
+
var REASON = `\u26D4 batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this one would make ${String(CONSECUTIVE_LIMIT)} in a row. Reissue it in one turn together with the calls meant to follow it that do not need its result. **The criterion is whether this call's input needs another call's result, not what kind of call it is** \u2014 edits are covered exactly as reads are, and it never authorizes weakening a verification gate or a review: fewer turns, never less work. The rule, and where its measured cost and rejected mechanisms are, is in \`prompts/collaboration-workflow/turn-batching.md\`. If this turn was already batching, or the call genuinely has nothing to go beside it, reissue it as it was: this fires once per run of single-call turns and cannot repeat on the call in hand.`;
|
|
3309
|
+
var NOTICE = `\u{1F4A1} batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this Write makes ${String(CONSECUTIVE_LIMIT)} in a row. This is a notice, not a refusal \u2014 the write proceeds. Where the writes meant to follow it do not need its result, issue them in one turn together. **The criterion is whether a call's input needs another call's result, not what kind of call it is** \u2014 it never authorizes weakening a verification gate or a review: fewer turns, never less work. The rule, and where its measured cost and rejected mechanisms are, is in \`prompts/collaboration-workflow/turn-batching.md\`. If this run was already batching, or the write genuinely has nothing to go beside it, carry on: this recurs every ${String(NOTICE_REFIRE_EVERY)} further single-call turn(s).`;
|
|
3310
|
+
var LANE_NOTICE = `\u{1F4A1} batching: the last ${String(SEQUENCE_BEFORE_LIMIT)} turns each issued a single tool call, so this one makes ${String(CONSECUTIVE_LIMIT)} in a row. This is a notice, not a refusal \u2014 the call proceeds, because a dispatched lane child ends its turn on a denial. Where the calls meant to follow it do not need its result, issue them in one turn together. **The criterion is whether a call's input needs another call's result, not what kind of call it is** \u2014 it never authorizes weakening a verification gate or a review: fewer turns, never less work. The rule, and where its measured cost and rejected mechanisms are, is in \`prompts/collaboration-workflow/turn-batching.md\`. If this run was already batching, or the call genuinely has nothing to go beside it, carry on: this recurs every ${String(NOTICE_REFIRE_EVERY)} further single-call turn(s).`;
|
|
3311
|
+
var WHOLE_FILE_WRITE_TOOL = "Write";
|
|
3312
|
+
var EDIT_TOOL = "Edit";
|
|
3313
|
+
function is_guarded_call(call) {
|
|
3314
|
+
if (call.name === WHOLE_FILE_WRITE_TOOL) return false;
|
|
3315
|
+
return time_bundle_call.call_facts(call.name, call.input).is_bundleable;
|
|
3316
|
+
}
|
|
3317
|
+
function is_notice_call(call) {
|
|
3318
|
+
return call.name === WHOLE_FILE_WRITE_TOOL;
|
|
3319
|
+
}
|
|
3320
|
+
function is_read_only_call(call) {
|
|
3321
|
+
const facts = time_bundle_call.call_facts(call.name, call.input);
|
|
3322
|
+
return facts.is_bundleable && !facts.may_write;
|
|
3323
|
+
}
|
|
3324
|
+
function depends_on_sequence(sequence, facts) {
|
|
3325
|
+
return sequence.some((span) => time_bundles.shares_target(span.targets, facts.targets));
|
|
3326
|
+
}
|
|
3327
|
+
function sequence_started_ms(sequence) {
|
|
3328
|
+
return sequence[0]?.ended_ms ?? NONE4;
|
|
3329
|
+
}
|
|
3330
|
+
function turns_since(sequence, last_fired_ms) {
|
|
3331
|
+
return sequence.filter((span) => span.ended_ms > last_fired_ms).length;
|
|
3332
|
+
}
|
|
3333
|
+
function is_sequence_at_limit(sequence, facts, last_fired_ms, refire_every) {
|
|
3334
|
+
if (sequence.length < SEQUENCE_BEFORE_LIMIT || depends_on_sequence(sequence, facts)) return false;
|
|
3335
|
+
if (last_fired_ms < sequence_started_ms(sequence)) return true;
|
|
3336
|
+
return turns_since(sequence, last_fired_ms) >= refire_every;
|
|
3337
|
+
}
|
|
3338
|
+
function is_at_limit(spans, call, last_fired_ms, refire_every) {
|
|
3339
|
+
return is_sequence_at_limit(
|
|
3340
|
+
time_bundles.open_sequence(spans),
|
|
3341
|
+
time_bundle_call.call_facts(call.name, call.input),
|
|
3342
|
+
last_fired_ms,
|
|
3343
|
+
refire_every
|
|
3344
|
+
);
|
|
3345
|
+
}
|
|
3346
|
+
var GUARD_LABEL = time_transcript_line.guard_from_refusal(REASON);
|
|
3347
|
+
function is_reissued_refusal(spans, call) {
|
|
3348
|
+
const identity = time_call_identity.identity_of(
|
|
3349
|
+
time_spans.to_tool_call(call.name, call.input, time_spans.NO_MESSAGE_ID)
|
|
3350
|
+
);
|
|
3351
|
+
return spans.some(
|
|
3352
|
+
(span) => span.refusal_guard === GUARD_LABEL && time_call_identity.identity_of(span) === identity
|
|
3353
|
+
);
|
|
3354
|
+
}
|
|
3355
|
+
function should_block(text, call, refused_at_ms, refire_every = REFIRE_EVERY) {
|
|
3356
|
+
if (!is_guarded_call(call)) return false;
|
|
3357
|
+
const { spans } = time_spans.parse_timeline(text);
|
|
3358
|
+
if (is_reissued_refusal(spans, call)) return false;
|
|
3359
|
+
return is_at_limit(spans, call, refused_at_ms, refire_every);
|
|
3360
|
+
}
|
|
3361
|
+
function should_notify(text, call, notified_at_ms) {
|
|
3362
|
+
if (!is_notice_call(call)) return false;
|
|
3363
|
+
const { spans } = time_spans.parse_timeline(text);
|
|
3364
|
+
return is_at_limit(spans, call, notified_at_ms, NOTICE_REFIRE_EVERY);
|
|
3365
|
+
}
|
|
3366
|
+
function describe_span(span) {
|
|
3367
|
+
const target = span.targets[0] ?? "";
|
|
3368
|
+
if (target === "" || span.label.includes(target)) return span.label;
|
|
3369
|
+
return `${span.label} ${target}`;
|
|
3370
|
+
}
|
|
3371
|
+
var FOLD_MINIMUM = 2;
|
|
3372
|
+
function read_targets(sequence) {
|
|
3373
|
+
const paths = sequence.filter((span) => span.is_bundleable && !span.is_writing).map((span) => span.targets[0] ?? "").filter((path6) => path6 !== "" && time_bundle_call.has_extension(path6));
|
|
3374
|
+
return [...new Set(paths)];
|
|
3375
|
+
}
|
|
3376
|
+
function read_fold_directive(sequence) {
|
|
3377
|
+
const paths = read_targets(sequence);
|
|
3378
|
+
if (paths.length < FOLD_MINIMUM) return "";
|
|
3379
|
+
return ` Fold them into one call: \`pnpm josh read:files ${paths.join(" ")}\`.`;
|
|
3380
|
+
}
|
|
3381
|
+
function write_targets(sequence) {
|
|
3382
|
+
const paths = sequence.filter((span) => span.label === EDIT_TOOL).map((span) => span.targets[0] ?? "").filter((path6) => path6 !== "" && time_bundle_call.has_extension(path6));
|
|
3383
|
+
return [...new Set(paths)];
|
|
3384
|
+
}
|
|
3385
|
+
function write_fold_directive(sequence) {
|
|
3386
|
+
const paths = write_targets(sequence);
|
|
3387
|
+
if (paths.length < FOLD_MINIMUM) return "";
|
|
3388
|
+
return ` Fold them into one \`pnpm josh edit:files\` call with a plan over: ${paths.join(" ")}.`;
|
|
3389
|
+
}
|
|
3390
|
+
function name_candidates(calls) {
|
|
3391
|
+
if (calls.length === NONE4) return "";
|
|
3392
|
+
const named = calls.map((call) => describe_span(call)).join(", ");
|
|
3393
|
+
const folds = `${read_fold_directive(calls)}${write_fold_directive(calls)}`;
|
|
3394
|
+
return ` Just issued one per turn, so at least these could have shared a turn: ${named}.${folds}`;
|
|
3395
|
+
}
|
|
3396
|
+
function recent_candidates(tail) {
|
|
3397
|
+
return name_candidates(
|
|
3398
|
+
time_bundles.open_sequence(time_spans.parse_timeline(tail).spans).slice(-NAMED_CANDIDATE_COUNT)
|
|
3399
|
+
);
|
|
3400
|
+
}
|
|
3401
|
+
function pairing_candidates(tail, call) {
|
|
3402
|
+
const sequence = time_bundles.open_sequence(time_spans.parse_timeline(tail).spans);
|
|
3403
|
+
if (call === void 0 || sequence.length === NONE4) {
|
|
3404
|
+
return name_candidates(sequence.slice(-NAMED_CANDIDATE_COUNT));
|
|
3405
|
+
}
|
|
3406
|
+
const facts = time_bundle_call.call_facts(call.name, call.input);
|
|
3407
|
+
if (!facts.is_bundleable || depends_on_sequence(sequence, facts)) return "";
|
|
3408
|
+
const current = time_spans.to_tool_call(call.name, call.input, time_spans.NO_MESSAGE_ID);
|
|
3409
|
+
return name_candidates([...sequence.slice(ONE_TURN - NAMED_CANDIDATE_COUNT), current]);
|
|
3410
|
+
}
|
|
3411
|
+
var STAMP_PREFIX = "josh-batch-guard-";
|
|
3412
|
+
var NOTICE_STAMP_PREFIX = "josh-batch-guard-notice-";
|
|
3413
|
+
var time_batch_guard = {
|
|
3414
|
+
CONSECUTIVE_LIMIT,
|
|
3415
|
+
GUARD_LABEL,
|
|
3416
|
+
LANE_NOTICE,
|
|
3417
|
+
NOTICE,
|
|
3418
|
+
NOTICE_REFIRE_EVERY,
|
|
3419
|
+
NOTICE_STAMP_PREFIX,
|
|
3420
|
+
REASON,
|
|
3421
|
+
REFIRE_EVERY,
|
|
3422
|
+
SEQUENCE_BEFORE_LIMIT,
|
|
3423
|
+
STAMP_PREFIX,
|
|
3424
|
+
is_guarded_call,
|
|
3425
|
+
is_notice_call,
|
|
3426
|
+
is_read_only_call,
|
|
3427
|
+
pairing_candidates,
|
|
3428
|
+
recent_candidates,
|
|
3429
|
+
should_block,
|
|
3430
|
+
should_notify
|
|
3431
|
+
};
|
|
3432
|
+
|
|
2634
3433
|
// scripts/time-runtime/time-hook-transcript.ts
|
|
2635
3434
|
import path3 from "node:path";
|
|
2636
3435
|
|
|
@@ -2708,30 +3507,30 @@ function read_if_readable(path6) {
|
|
|
2708
3507
|
var file_reader = { read_optional, read_file_or_empty, read_if_readable };
|
|
2709
3508
|
|
|
2710
3509
|
// scripts/cost-runtime/cost-usage.ts
|
|
2711
|
-
import { z as
|
|
2712
|
-
var CACHE_CREATION_SCHEMA =
|
|
2713
|
-
ephemeral_1h_input_tokens:
|
|
2714
|
-
ephemeral_5m_input_tokens:
|
|
3510
|
+
import { z as z5 } from "zod";
|
|
3511
|
+
var CACHE_CREATION_SCHEMA = z5.object({
|
|
3512
|
+
ephemeral_1h_input_tokens: z5.number().nullish(),
|
|
3513
|
+
ephemeral_5m_input_tokens: z5.number().nullish()
|
|
2715
3514
|
});
|
|
2716
|
-
var USAGE_SCHEMA =
|
|
2717
|
-
input_tokens:
|
|
2718
|
-
cache_creation_input_tokens:
|
|
2719
|
-
cache_read_input_tokens:
|
|
2720
|
-
output_tokens:
|
|
2721
|
-
output_tokens_details:
|
|
3515
|
+
var USAGE_SCHEMA = z5.object({
|
|
3516
|
+
input_tokens: z5.number(),
|
|
3517
|
+
cache_creation_input_tokens: z5.number().nullish(),
|
|
3518
|
+
cache_read_input_tokens: z5.number().nullish(),
|
|
3519
|
+
output_tokens: z5.number(),
|
|
3520
|
+
output_tokens_details: z5.object({ thinking_tokens: z5.number().nullish() }).nullish(),
|
|
2722
3521
|
cache_creation: CACHE_CREATION_SCHEMA.nullish()
|
|
2723
3522
|
});
|
|
2724
|
-
var MESSAGE_SCHEMA3 =
|
|
2725
|
-
id:
|
|
2726
|
-
model:
|
|
3523
|
+
var MESSAGE_SCHEMA3 = z5.object({
|
|
3524
|
+
id: z5.string().nullish(),
|
|
3525
|
+
model: z5.string().nullish(),
|
|
2727
3526
|
usage: USAGE_SCHEMA.nullish()
|
|
2728
3527
|
});
|
|
2729
|
-
var LINE_SCHEMA2 =
|
|
2730
|
-
type:
|
|
2731
|
-
requestId:
|
|
2732
|
-
uuid:
|
|
2733
|
-
gitBranch:
|
|
2734
|
-
timestamp:
|
|
3528
|
+
var LINE_SCHEMA2 = z5.object({
|
|
3529
|
+
type: z5.string(),
|
|
3530
|
+
requestId: z5.string().nullish(),
|
|
3531
|
+
uuid: z5.string().nullish(),
|
|
3532
|
+
gitBranch: z5.string().nullish(),
|
|
3533
|
+
timestamp: z5.string().nullish(),
|
|
2735
3534
|
message: MESSAGE_SCHEMA3.nullish()
|
|
2736
3535
|
});
|
|
2737
3536
|
var SYNTHETIC_MODEL = "<synthetic>";
|
|
@@ -3204,122 +4003,13 @@ var stamp_file = {
|
|
|
3204
4003
|
};
|
|
3205
4004
|
|
|
3206
4005
|
// scripts/time-runtime/time-density-hook.ts
|
|
3207
|
-
import { z as
|
|
3208
|
-
|
|
3209
|
-
// scripts/time-runtime/time-round-trips.ts
|
|
3210
|
-
var CALLS_PER_ROUND_TRIP_FLOOR = 1.5;
|
|
3211
|
-
var DENSITY_DECIMALS = 2;
|
|
3212
|
-
var NONE = 0;
|
|
3213
|
-
function is_tool(span) {
|
|
3214
|
-
return span.category === time_spans.TOOL_CATEGORY;
|
|
3215
|
-
}
|
|
3216
|
-
function is_model(span) {
|
|
3217
|
-
return span.category === time_spans.MODEL_CATEGORY;
|
|
3218
|
-
}
|
|
3219
|
-
function started_ms2(span) {
|
|
3220
|
-
return span.ended_ms - span.duration_ms;
|
|
3221
|
-
}
|
|
3222
|
-
function in_time_order(spans) {
|
|
3223
|
-
return spans.toSorted((left, right) => started_ms2(left) - started_ms2(right));
|
|
3224
|
-
}
|
|
3225
|
-
function is_tool_at(spans, index) {
|
|
3226
|
-
const span = spans[index];
|
|
3227
|
-
return span !== void 0 && is_tool(span);
|
|
3228
|
-
}
|
|
3229
|
-
function is_call(span) {
|
|
3230
|
-
return is_tool(span) && !span.is_continuation;
|
|
3231
|
-
}
|
|
3232
|
-
function count_calls(spans) {
|
|
3233
|
-
return spans.filter((span) => is_call(span)).length;
|
|
3234
|
-
}
|
|
3235
|
-
function previous_break(spans, index) {
|
|
3236
|
-
for (let back = index - 1; back >= 0; back -= 1) {
|
|
3237
|
-
const span = spans[back];
|
|
3238
|
-
if (span === void 0 || !is_model(span)) return span;
|
|
3239
|
-
}
|
|
3240
|
-
return void 0;
|
|
3241
|
-
}
|
|
3242
|
-
function continues_turn(spans, index, message_id) {
|
|
3243
|
-
if (message_id === time_spans.NO_MESSAGE_ID) return false;
|
|
3244
|
-
const earlier = previous_break(spans, index);
|
|
3245
|
-
return earlier !== void 0 && !earlier.is_continuation && earlier.message_id === message_id;
|
|
3246
|
-
}
|
|
3247
|
-
function opens_round_trip(spans, index) {
|
|
3248
|
-
const span = spans[index];
|
|
3249
|
-
if (span === void 0 || !is_tool(span) || span.is_continuation || is_tool_at(spans, index - 1)) {
|
|
3250
|
-
return false;
|
|
3251
|
-
}
|
|
3252
|
-
return !continues_turn(spans, index, span.message_id);
|
|
3253
|
-
}
|
|
3254
|
-
function open_trip(walk) {
|
|
3255
|
-
walk.open = [];
|
|
3256
|
-
walk.trips.push(walk.open);
|
|
3257
|
-
}
|
|
3258
|
-
function place_call(walk, span) {
|
|
3259
|
-
if (is_call(span)) walk.open?.push(span);
|
|
3260
|
-
}
|
|
3261
|
-
function step_trip(walk, span, is_opener) {
|
|
3262
|
-
if (is_opener) open_trip(walk);
|
|
3263
|
-
if (is_tool(span)) place_call(walk, span);
|
|
3264
|
-
else if (!is_model(span)) walk.open = void 0;
|
|
3265
|
-
}
|
|
3266
|
-
function group_round_trips(spans) {
|
|
3267
|
-
const ordered = in_time_order(spans);
|
|
3268
|
-
const walk = { trips: [], open: void 0 };
|
|
3269
|
-
for (const [index, span] of ordered.entries()) {
|
|
3270
|
-
step_trip(walk, span, opens_round_trip(ordered, index));
|
|
3271
|
-
}
|
|
3272
|
-
return walk.trips;
|
|
3273
|
-
}
|
|
3274
|
-
function count_round_trips(spans) {
|
|
3275
|
-
return group_round_trips(spans).length;
|
|
3276
|
-
}
|
|
3277
|
-
function turn_key(span, index) {
|
|
3278
|
-
return span.message_id === time_spans.NO_MESSAGE_ID ? `#${String(index)}` : span.message_id;
|
|
3279
|
-
}
|
|
3280
|
-
function count_turns(spans) {
|
|
3281
|
-
const keys = spans.filter((span) => is_model(span)).map((span, index) => turn_key(span, index));
|
|
3282
|
-
return new Set(keys).size;
|
|
3283
|
-
}
|
|
3284
|
-
function per_round_trip(total, round_trip_count) {
|
|
3285
|
-
if (round_trip_count === NONE) return NONE;
|
|
3286
|
-
return total / round_trip_count;
|
|
3287
|
-
}
|
|
3288
|
-
function format_density(density) {
|
|
3289
|
-
return density.toFixed(DENSITY_DECIMALS);
|
|
3290
|
-
}
|
|
3291
|
-
function is_below_floor(density) {
|
|
3292
|
-
return density > NONE && density < CALLS_PER_ROUND_TRIP_FLOOR;
|
|
3293
|
-
}
|
|
3294
|
-
var time_round_trips = {
|
|
3295
|
-
CALLS_PER_ROUND_TRIP_FLOOR,
|
|
3296
|
-
count_calls,
|
|
3297
|
-
count_round_trips,
|
|
3298
|
-
// Exported since joshuafolkken/kit#1406, so a turn is defined in the one module that already
|
|
3299
|
-
// defines a round trip rather than as a span filter in the report next door.
|
|
3300
|
-
count_turns,
|
|
3301
|
-
format_density,
|
|
3302
|
-
// Exported since joshuafolkken/kit#1385, so the per-tool counts are read off the very groups this
|
|
3303
|
-
// module counts rather than off a second grouping beside them.
|
|
3304
|
-
group_round_trips,
|
|
3305
|
-
// Exported since joshuafolkken/kit#1309, so the failure aggregation orders a run's spans through
|
|
3306
|
-
// the one function that already knows why they need it — a second `toSorted` beside it would be
|
|
3307
|
-
// the clone `CLAUDE.md` prohibits, and the seam it guards (a delegated unit's spans appended
|
|
3308
|
-
// after the parent's) is not one a second copy would keep remembering.
|
|
3309
|
-
in_time_order,
|
|
3310
|
-
is_below_floor,
|
|
3311
|
-
// The four below are exported since joshuafolkken/kit#1406, when the model-gap walk moved to
|
|
3312
|
-
// `time-model-gaps.ts` and needed the same predicates and the same opener test this walk uses. A
|
|
3313
|
-
// private copy there would be the clone `CLAUDE.md` prohibits, in the one place a drift would have
|
|
3314
|
-
// the distribution and the count disagreeing about what a round trip is.
|
|
3315
|
-
per_round_trip
|
|
3316
|
-
};
|
|
4006
|
+
import { z as z6 } from "zod";
|
|
3317
4007
|
|
|
3318
4008
|
// scripts/time-runtime/time-density.ts
|
|
3319
4009
|
var MIN_ROUND_TRIPS = 10;
|
|
3320
4010
|
var NOTICE_INTERVAL_MS = 3e5;
|
|
3321
|
-
var
|
|
3322
|
-
var
|
|
4011
|
+
var ONE_CALL2 = 1;
|
|
4012
|
+
var NONE5 = 0;
|
|
3323
4013
|
function has_whole_tail(text) {
|
|
3324
4014
|
const last = text.split("\n").findLast((line) => line.trim() !== "");
|
|
3325
4015
|
return last !== void 0 && time_spans.parse_line(last) !== void 0;
|
|
@@ -3328,10 +4018,10 @@ function assistant_lines(text) {
|
|
|
3328
4018
|
return text.split("\n").map((line) => time_spans.parse_line(line)).filter((line) => line?.type === time_spans.ASSISTANT_TYPE);
|
|
3329
4019
|
}
|
|
3330
4020
|
function last_turn_calls(text) {
|
|
3331
|
-
if (!has_whole_tail(text)) return
|
|
4021
|
+
if (!has_whole_tail(text)) return NONE5;
|
|
3332
4022
|
const lines = assistant_lines(text);
|
|
3333
4023
|
const message_id = lines.at(-1)?.message_id;
|
|
3334
|
-
if (message_id === void 0 || message_id === time_spans.NO_MESSAGE_ID) return
|
|
4024
|
+
if (message_id === void 0 || message_id === time_spans.NO_MESSAGE_ID) return NONE5;
|
|
3335
4025
|
return lines.filter((line) => line.message_id === message_id).flatMap((line) => line.blocks).filter((block) => block.type === cost_blocks.TOOL_USE_TYPE).length;
|
|
3336
4026
|
}
|
|
3337
4027
|
function read_window(text) {
|
|
@@ -3345,15 +4035,15 @@ function read_window(text) {
|
|
|
3345
4035
|
};
|
|
3346
4036
|
}
|
|
3347
4037
|
function is_due(reading, since_last_ms) {
|
|
3348
|
-
if (reading.round_trip_count < MIN_ROUND_TRIPS || reading.turn_calls !==
|
|
4038
|
+
if (reading.round_trip_count < MIN_ROUND_TRIPS || reading.turn_calls !== ONE_CALL2 || !time_round_trips.is_below_floor(reading.density)) {
|
|
3349
4039
|
return false;
|
|
3350
4040
|
}
|
|
3351
4041
|
return since_last_ms >= NOTICE_INTERVAL_MS;
|
|
3352
4042
|
}
|
|
3353
|
-
function format_notice(reading) {
|
|
4043
|
+
function format_notice(reading, candidates = "") {
|
|
3354
4044
|
const density = time_round_trips.format_density(reading.density);
|
|
3355
4045
|
const floor = time_round_trips.format_density(time_round_trips.CALLS_PER_ROUND_TRIP_FLOOR);
|
|
3356
|
-
return `\u26A0 batching: ${density} calls per round trip over the last ${String(reading.round_trip_count)}, under the ${floor} floor, and this turn issued one call. Independent reads, greps, gh queries and edits go out together; the criterion is whether this call's input needs another call's result, not what kind of call it is \u2014 prompts/collaboration-workflow/turn-batching.md
|
|
4046
|
+
return `\u26A0 batching: ${density} calls per round trip over the last ${String(reading.round_trip_count)}, under the ${floor} floor, and this turn issued one call. Independent reads, greps, gh queries and edits go out together; the criterion is whether this call's input needs another call's result, not what kind of call it is \u2014 prompts/collaboration-workflow/turn-batching.md.${candidates}`;
|
|
3357
4047
|
}
|
|
3358
4048
|
var time_density = {
|
|
3359
4049
|
MIN_ROUND_TRIPS,
|
|
@@ -3369,19 +4059,25 @@ var TAIL_BYTES = 262144;
|
|
|
3369
4059
|
var FILE_START = 0;
|
|
3370
4060
|
var NOTICE_PREFIX = "josh-density-notice-";
|
|
3371
4061
|
var NEVER_MS = 0;
|
|
3372
|
-
var payload_schema =
|
|
3373
|
-
transcript_path:
|
|
4062
|
+
var payload_schema = z6.object({
|
|
4063
|
+
transcript_path: z6.string().min(1).optional(),
|
|
3374
4064
|
// **`nullish`, not `optional`.** A payload spelling the absent agent as `null` has to read as "no
|
|
3375
4065
|
// fork"; rejected, it would fail `safeParse` for the whole payload and silence the line for every
|
|
3376
4066
|
// edit of the main line — the opposite of this module's stated failure direction.
|
|
3377
|
-
agent_id:
|
|
4067
|
+
agent_id: z6.string().nullish()
|
|
3378
4068
|
});
|
|
3379
|
-
var notice_schema =
|
|
4069
|
+
var notice_schema = z6.object({ notified_at_ms: z6.number() });
|
|
4070
|
+
var call_schema = z6.object({ tool_name: z6.string().min(1), tool_input: z6.unknown() });
|
|
3380
4071
|
function parse_transcript_path(raw_payload) {
|
|
3381
4072
|
const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
|
|
3382
4073
|
if (!parsed.success || parsed.data.transcript_path === void 0) return void 0;
|
|
3383
4074
|
return time_hook_transcript.transcript_of(parsed.data.transcript_path, parsed.data.agent_id);
|
|
3384
4075
|
}
|
|
4076
|
+
function parse_call(raw_payload) {
|
|
4077
|
+
const parsed = call_schema.safeParse(JSON.parse(raw_payload));
|
|
4078
|
+
if (!parsed.success) return void 0;
|
|
4079
|
+
return { name: parsed.data.tool_name, input: parsed.data.tool_input };
|
|
4080
|
+
}
|
|
3385
4081
|
function read_tail(file_path, max_bytes = TAIL_BYTES) {
|
|
3386
4082
|
const descriptor = openSync(file_path, "r");
|
|
3387
4083
|
try {
|
|
@@ -3415,11 +4111,14 @@ function arm_throttle(target, now_ms) {
|
|
|
3415
4111
|
function notice_for(raw_payload, now_ms) {
|
|
3416
4112
|
const transcript_path = parse_transcript_path(raw_payload);
|
|
3417
4113
|
if (transcript_path === void 0) return void 0;
|
|
3418
|
-
const
|
|
4114
|
+
const tail = read_tail(transcript_path);
|
|
4115
|
+
const reading = time_density.read_window(tail);
|
|
3419
4116
|
const target = notice_path(transcript_path);
|
|
3420
4117
|
if (!time_density.is_due(reading, now_ms - last_notice_ms(target))) return void 0;
|
|
4118
|
+
const candidates = time_batch_guard.pairing_candidates(tail, parse_call(raw_payload));
|
|
4119
|
+
if (candidates === "") return void 0;
|
|
3421
4120
|
arm_throttle(target, now_ms);
|
|
3422
|
-
return time_density.format_notice(reading);
|
|
4121
|
+
return time_density.format_notice(reading, candidates);
|
|
3423
4122
|
}
|
|
3424
4123
|
function density_notice(raw_payload, now_ms = Date.now()) {
|
|
3425
4124
|
try {
|
|
@@ -3443,12 +4142,25 @@ export {
|
|
|
3443
4142
|
ESLINT_EDIT_CACHE_FLAGS,
|
|
3444
4143
|
time_shell,
|
|
3445
4144
|
time_bundle_call,
|
|
3446
|
-
|
|
4145
|
+
blocking_issue_schema,
|
|
4146
|
+
rest_comment_schema,
|
|
4147
|
+
open_issue_schema,
|
|
4148
|
+
CHECK_STATUS_PENDING,
|
|
4149
|
+
CHECK_STATUS_FAIL,
|
|
4150
|
+
read_string,
|
|
4151
|
+
parse_pr_state_snapshot,
|
|
4152
|
+
is_merge_conflict,
|
|
4153
|
+
is_coderabbit_check,
|
|
4154
|
+
is_required_check,
|
|
4155
|
+
describe_pr_failure,
|
|
4156
|
+
evaluate_pr_state,
|
|
4157
|
+
is_review_decision_decisive,
|
|
4158
|
+
PrConflictError,
|
|
3447
4159
|
cost_attribute,
|
|
3448
4160
|
time_reported_failure,
|
|
3449
4161
|
time_transcript_line,
|
|
3450
4162
|
time_spans,
|
|
3451
|
-
|
|
4163
|
+
time_batch_guard,
|
|
3452
4164
|
lane_paths,
|
|
3453
4165
|
file_reader,
|
|
3454
4166
|
cost_usage,
|