ralphctl 0.22.0 → 0.23.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/README.md +56 -29
- package/dist/{cli-LJZZGXAY.mjs → cli-J3MI4B6A.mjs} +1509 -748
- package/dist/cli.mjs +1 -1
- package/dist/manifest.json +2 -2
- package/package.json +7 -7
|
@@ -646,19 +646,22 @@ var CLAUDE_MODELS = [
|
|
|
646
646
|
"claude-opus-4-8",
|
|
647
647
|
"claude-opus-4-8[1m]",
|
|
648
648
|
"claude-opus-5",
|
|
649
|
+
"claude-opus-5-5",
|
|
649
650
|
"claude-fable-5",
|
|
650
|
-
"claude-fable-5[1m]"
|
|
651
|
+
"claude-fable-5[1m]",
|
|
652
|
+
"claude-fable-5-1"
|
|
651
653
|
];
|
|
652
654
|
var isClaudeModel = (s) => CLAUDE_MODELS.includes(s);
|
|
653
655
|
|
|
654
656
|
// src/domain/value/settings-models/codex.ts
|
|
655
657
|
var CODEX_MODELS = [
|
|
658
|
+
"gpt-6-astra",
|
|
659
|
+
"gpt-6-sol",
|
|
660
|
+
"gpt-6-luna",
|
|
656
661
|
"gpt-5.6-sol",
|
|
657
662
|
"gpt-5.6-terra",
|
|
658
663
|
"gpt-5.6-luna",
|
|
659
664
|
"gpt-5.5",
|
|
660
|
-
"gpt-5.4",
|
|
661
|
-
"gpt-5.4-mini",
|
|
662
665
|
"codex-auto-review"
|
|
663
666
|
];
|
|
664
667
|
var isCodexModel = (s) => CODEX_MODELS.includes(s);
|
|
@@ -675,25 +678,25 @@ var COPILOT_MODELS = [
|
|
|
675
678
|
"gpt-5.6-sol",
|
|
676
679
|
"gpt-5.6-terra",
|
|
677
680
|
"gpt-5.6-luna",
|
|
681
|
+
"gpt-6-astra",
|
|
682
|
+
"gpt-6-sol",
|
|
683
|
+
"gpt-6-luna",
|
|
678
684
|
// Anthropic
|
|
679
685
|
"claude-haiku-4.5",
|
|
680
|
-
"claude-opus-4.5",
|
|
681
|
-
"claude-opus-4.6",
|
|
682
686
|
"claude-opus-4.7",
|
|
683
687
|
"claude-opus-4.8",
|
|
684
688
|
"claude-opus-4.8-fast",
|
|
685
689
|
"claude-opus-5",
|
|
690
|
+
"claude-opus-5.5",
|
|
686
691
|
"claude-fable-5",
|
|
687
|
-
"claude-
|
|
688
|
-
"claude-sonnet-4.6",
|
|
692
|
+
"claude-fable-5.1",
|
|
689
693
|
"claude-sonnet-5",
|
|
690
694
|
// Google
|
|
691
|
-
"gemini-3.1-pro",
|
|
692
695
|
"gemini-3.5-flash",
|
|
693
696
|
"gemini-3.6-flash",
|
|
694
697
|
"gemini-3.7-flash",
|
|
698
|
+
"gemini-3.8-flash",
|
|
695
699
|
// Microsoft
|
|
696
|
-
"mai-code-1-flash",
|
|
697
700
|
"mai-code-1.1-flash",
|
|
698
701
|
// Moonshot
|
|
699
702
|
"kimi-k2.7-code",
|
|
@@ -701,26 +704,24 @@ var COPILOT_MODELS = [
|
|
|
701
704
|
// xAI
|
|
702
705
|
"grok-4.5",
|
|
703
706
|
"grok-4.6",
|
|
704
|
-
|
|
705
|
-
"raptor-mini"
|
|
707
|
+
"grok-4.7"
|
|
706
708
|
];
|
|
707
709
|
var isCopilotModel = (s) => COPILOT_MODELS.includes(s);
|
|
708
710
|
|
|
709
711
|
// src/domain/value/settings-models/opencode.ts
|
|
710
712
|
var OPENCODE_MODELS = [
|
|
711
713
|
"opencode/big-pickle",
|
|
712
|
-
"opencode/
|
|
713
|
-
"opencode/
|
|
714
|
-
"opencode/ling-3.0-tiny-free",
|
|
715
|
-
"opencode/longcat-2.0-free",
|
|
714
|
+
"opencode/hy3-free",
|
|
715
|
+
"opencode/ling-3.0-flash-fin-free",
|
|
716
716
|
"opencode/mimo-v2.5-free",
|
|
717
|
+
"opencode/muse-spark-1.2-contributor-free",
|
|
717
718
|
"opencode/nemotron-3-ultra-free",
|
|
718
|
-
"opencode/
|
|
719
|
+
"opencode/nemotron-3.5-lightning-free"
|
|
719
720
|
];
|
|
720
721
|
var isOpencodeModelIdShape = (s) => /^[^/\s]+(?:\/[^/\s]+)+$/.test(s);
|
|
721
722
|
|
|
722
723
|
// src/domain/value/settings-models/grok.ts
|
|
723
|
-
var GROK_MODELS = ["grok-4.6", "grok-4.5"];
|
|
724
|
+
var GROK_MODELS = ["grok-4.7", "grok-4.7-build-fast", "grok-4.6", "grok-4.5"];
|
|
724
725
|
var isGrokModel = (s) => GROK_MODELS.includes(s);
|
|
725
726
|
|
|
726
727
|
// src/domain/value/flow-id.ts
|
|
@@ -818,23 +819,53 @@ var seedLegacyCreatePrRow = (ai) => {
|
|
|
818
819
|
if (!("provider" in refine)) return ai;
|
|
819
820
|
return { ...aiObj, createPr: { ...refine } };
|
|
820
821
|
};
|
|
822
|
+
var COPILOT_GEMINI_SUCCESSOR = "gemini-3.8-flash";
|
|
823
|
+
var COPILOT_SMALL_CODE_SUCCESSOR = "mai-code-1.1-flash";
|
|
821
824
|
var RETIRED_MODEL_REMAPS = [
|
|
822
825
|
{ provider: PROVIDER_CLAUDE_CODE, from: "claude-opus-4-7", to: "claude-opus-4-8" },
|
|
826
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "claude-opus-4.5", to: "claude-opus-4.8" },
|
|
827
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "claude-opus-4.6", to: "claude-opus-4.8" },
|
|
823
828
|
{ provider: PROVIDER_GITHUB_COPILOT, from: "claude-opus-4.6-fast", to: "claude-opus-4.8-fast" },
|
|
824
|
-
{ provider: PROVIDER_GITHUB_COPILOT, from: "
|
|
825
|
-
{ provider: PROVIDER_GITHUB_COPILOT, from: "
|
|
826
|
-
{ provider: PROVIDER_GITHUB_COPILOT, from: "gemini-
|
|
829
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "claude-sonnet-4.5", to: "claude-sonnet-5" },
|
|
830
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "claude-sonnet-4.6", to: "claude-sonnet-5" },
|
|
831
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "gemini-3.1-pro", to: COPILOT_GEMINI_SUCCESSOR },
|
|
832
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "gemini-3.1-pro-preview", to: COPILOT_GEMINI_SUCCESSOR },
|
|
833
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "gemini-2.5-pro", to: COPILOT_GEMINI_SUCCESSOR },
|
|
827
834
|
{ provider: PROVIDER_GITHUB_COPILOT, from: "gemini-3-flash", to: "gemini-3.5-flash" },
|
|
835
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "raptor-mini", to: COPILOT_SMALL_CODE_SUCCESSOR },
|
|
836
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "raptor-mini-preview", to: COPILOT_SMALL_CODE_SUCCESSOR },
|
|
837
|
+
{ provider: PROVIDER_GITHUB_COPILOT, from: "mai-code-1-flash", to: COPILOT_SMALL_CODE_SUCCESSOR },
|
|
838
|
+
{ provider: PROVIDER_OPENAI_CODEX, from: "gpt-5.4", to: "gpt-6-sol" },
|
|
839
|
+
{ provider: PROVIDER_OPENAI_CODEX, from: "gpt-5.4-mini", to: "gpt-6-luna" },
|
|
828
840
|
{ provider: PROVIDER_OPENAI_CODEX, from: "gpt-5.2", to: "gpt-5.5" },
|
|
829
841
|
{ provider: PROVIDER_OPENAI_CODEX, from: "gpt-5.3-codex", to: "gpt-5.5" },
|
|
830
|
-
{ provider: PROVIDER_OPENAI_CODEX, from: "gpt-5.3-codex-spark", to: "gpt-5.5" }
|
|
842
|
+
{ provider: PROVIDER_OPENAI_CODEX, from: "gpt-5.3-codex-spark", to: "gpt-5.5" },
|
|
843
|
+
{ provider: PROVIDER_OPENCODE, from: "opencode/deepseek-v4-flash-free", to: "opencode/nemotron-3.5-lightning-free" },
|
|
844
|
+
{ provider: PROVIDER_OPENCODE, from: "opencode/ling-3.0-tiny-free", to: "opencode/ling-3.0-flash-fin-free" }
|
|
831
845
|
];
|
|
846
|
+
var remapRetiredModel = (provider, model) => RETIRED_MODEL_REMAPS.find((r) => r.provider === provider && r.from === model)?.to ?? model;
|
|
847
|
+
var LIVE_CATALOG_IDS = /* @__PURE__ */ new Set([
|
|
848
|
+
...CLAUDE_MODELS,
|
|
849
|
+
...COPILOT_MODELS,
|
|
850
|
+
...CODEX_MODELS,
|
|
851
|
+
...OPENCODE_MODELS,
|
|
852
|
+
...GROK_MODELS
|
|
853
|
+
]);
|
|
854
|
+
var unambiguousRetiredSuccessor = (model) => {
|
|
855
|
+
if (LIVE_CATALOG_IDS.has(model)) return void 0;
|
|
856
|
+
const hits = RETIRED_MODEL_REMAPS.filter((r) => r.from === model);
|
|
857
|
+
return hits.length === 1 ? hits[0]?.to : void 0;
|
|
858
|
+
};
|
|
832
859
|
var RETIRED_CODEX_EFFORT = "minimal";
|
|
833
860
|
var migrateStaleRow = (row) => {
|
|
834
861
|
if (typeof row !== "object" || row === null) return row;
|
|
835
862
|
let next = row;
|
|
836
|
-
const
|
|
837
|
-
|
|
863
|
+
const provider = next["provider"];
|
|
864
|
+
const model = next["model"];
|
|
865
|
+
if (typeof provider === "string" && typeof model === "string") {
|
|
866
|
+
const remapped = remapRetiredModel(provider, model);
|
|
867
|
+
if (remapped !== model) next = { ...next, model: remapped };
|
|
868
|
+
}
|
|
838
869
|
if (next["provider"] === PROVIDER_OPENAI_CODEX && next["effort"] === RETIRED_CODEX_EFFORT) {
|
|
839
870
|
next = { ...next, effort: "low" };
|
|
840
871
|
}
|
|
@@ -871,6 +902,21 @@ var healHarnessCrossKnobs = (harness) => {
|
|
|
871
902
|
const healedTurns = Math.max(turns, healedThreshold);
|
|
872
903
|
return { ...h, maxTurns: healedTurns, plateauThreshold: healedThreshold };
|
|
873
904
|
};
|
|
905
|
+
var remapRetiredEscalationTargets = (harness) => {
|
|
906
|
+
if (typeof harness !== "object" || harness === null) return harness;
|
|
907
|
+
const h = harness;
|
|
908
|
+
const map = h["escalationMap"];
|
|
909
|
+
if (typeof map !== "object" || map === null) return harness;
|
|
910
|
+
let changed2 = false;
|
|
911
|
+
const next = {};
|
|
912
|
+
for (const [from, to] of Object.entries(map)) {
|
|
913
|
+
const successor = typeof to === "string" ? unambiguousRetiredSuccessor(to) : void 0;
|
|
914
|
+
if (successor !== void 0) changed2 = true;
|
|
915
|
+
next[from] = successor ?? to;
|
|
916
|
+
}
|
|
917
|
+
return changed2 ? { ...h, escalationMap: next } : harness;
|
|
918
|
+
};
|
|
919
|
+
var healHarness = (harness) => remapRetiredEscalationTargets(healHarnessCrossKnobs(harness));
|
|
874
920
|
var FlowSkillsRowSchema = z.object({
|
|
875
921
|
disabled: z.array(z.string().trim().min(1, "skill name must be a non-empty trimmed string")).readonly()
|
|
876
922
|
});
|
|
@@ -904,7 +950,7 @@ var SettingsSchema = z.object({
|
|
|
904
950
|
schemaVersion: z.literal(CURRENT_SCHEMA_VERSION).default(CURRENT_SCHEMA_VERSION),
|
|
905
951
|
ai: AiSettingsSchema,
|
|
906
952
|
harness: z.preprocess(
|
|
907
|
-
|
|
953
|
+
healHarness,
|
|
908
954
|
z.object({
|
|
909
955
|
/** Generator–evaluator turns budgeted per `Attempt` (1–10). */
|
|
910
956
|
maxTurns: z.number().int().min(1).max(10),
|
|
@@ -954,7 +1000,7 @@ var SettingsSchema = z.object({
|
|
|
954
1000
|
* a plain same-model fresh-attempt retry — instead of settling immediately.
|
|
955
1001
|
*
|
|
956
1002
|
* On an escalatable exit the generator climbs one rung up the merged ladder ({@link
|
|
957
|
-
* escalationMap} over the built-in
|
|
1003
|
+
* escalationMap} over the generator provider's built-in ladder) across successive failures, bounded
|
|
958
1004
|
* by `maxAttempts`; each climb hands the targeted prior critique to the stronger model. The
|
|
959
1005
|
* "change your approach" directive is NOT injected on a model bump — it fires only once the
|
|
960
1006
|
* generator reaches the top of the ladder, as a same-model nudge (one more attempt on the same
|
|
@@ -968,10 +1014,11 @@ var SettingsSchema = z.object({
|
|
|
968
1014
|
*/
|
|
969
1015
|
escalateOnPlateau: z.boolean().default(true),
|
|
970
1016
|
/**
|
|
971
|
-
* User overrides for the built-in `
|
|
1017
|
+
* User overrides for the built-in per-provider `DEFAULT_ESCALATION_LADDERS` (in
|
|
972
1018
|
* `business/task/escalation-map.ts`). Keys are the current model id, values the model id
|
|
973
|
-
* to escalate to.
|
|
974
|
-
*
|
|
1019
|
+
* to escalate to. Flat on purpose: it applies to whichever provider the generator runs on.
|
|
1020
|
+
* Empty by default; merged at read time over the generator provider's ladder, with user
|
|
1021
|
+
* keys winning on conflict and extending it. Non-string entries fail schema validation
|
|
975
1022
|
* with a typed Zod error naming the offending field.
|
|
976
1023
|
*/
|
|
977
1024
|
escalationMap: z.record(z.string(), z.string()).default({}),
|
|
@@ -1025,7 +1072,7 @@ var SettingsSchema = z.object({
|
|
|
1025
1072
|
* COST CAVEAT: the granted attempt spawns N full generator sessions instead of one,
|
|
1026
1073
|
* multiplying spend for that one attempt. It is bounded (at most once per task, and only
|
|
1027
1074
|
* for a task that has already exhausted the whole ladder), but cost-sensitive setups opt
|
|
1028
|
-
* out with `0` — which is exactly what the
|
|
1075
|
+
* out with `0` — which is exactly what the five `*-economic` presets pin.
|
|
1029
1076
|
*
|
|
1030
1077
|
* Research: arXiv 2604.16529 (RTV) — harness-level N-candidate selection lifted SWE-bench
|
|
1031
1078
|
* Verified 67.4 → 73.6 at N=16 (RTV measured N=16, not the 2-4 cap used here); the tight
|
|
@@ -1064,10 +1111,9 @@ var SettingsSchema = z.object({
|
|
|
1064
1111
|
*/
|
|
1065
1112
|
scm: z.object({
|
|
1066
1113
|
/**
|
|
1067
|
-
*
|
|
1068
|
-
* and
|
|
1069
|
-
*
|
|
1070
|
-
* description is never touched, and posting a comment is strictly opt-in.
|
|
1114
|
+
* Retained so existing settings files parse. Does not select the refine approval default
|
|
1115
|
+
* and does not post a comment — Approve always leads, and commenting is an explicit
|
|
1116
|
+
* "Post as comment" choice on a linked ticket.
|
|
1071
1117
|
*/
|
|
1072
1118
|
postRefinementComment: z.boolean().default(false)
|
|
1073
1119
|
}).default({ postRefinementComment: false }),
|
|
@@ -1109,42 +1155,59 @@ var uniqueProvidersFromAi = (ai) => {
|
|
|
1109
1155
|
var AI_PROVIDERS = AiProviderSchema.options;
|
|
1110
1156
|
var AI_PROVIDERS_HINT = AI_PROVIDERS.join(", ");
|
|
1111
1157
|
|
|
1112
|
-
// src/business/settings/
|
|
1113
|
-
var
|
|
1114
|
-
var
|
|
1115
|
-
var
|
|
1116
|
-
var
|
|
1117
|
-
var
|
|
1158
|
+
// src/business/settings/preset-model-ids.ts
|
|
1159
|
+
var CLAUDE = "claude-code";
|
|
1160
|
+
var COPILOT = "github-copilot";
|
|
1161
|
+
var CODEX = "openai-codex";
|
|
1162
|
+
var OPENCODE = "opencode";
|
|
1163
|
+
var GROK = "xai-grok";
|
|
1164
|
+
var OPUS = "claude-opus-5-5";
|
|
1165
|
+
var SONNET = "claude-sonnet-5";
|
|
1166
|
+
var FABLE = "claude-fable-5-1";
|
|
1167
|
+
var COPILOT_OPUS = "claude-opus-4.8";
|
|
1168
|
+
var COPILOT_SONNET = "claude-sonnet-5";
|
|
1169
|
+
var COPILOT_LUNA = "gpt-5.6-luna";
|
|
1170
|
+
var GPT_6_ASTRA = "gpt-6-astra";
|
|
1171
|
+
var GPT_6_SOL = "gpt-6-sol";
|
|
1172
|
+
var GPT_6_LUNA = "gpt-6-luna";
|
|
1173
|
+
var GROK_FLAGSHIP = "grok-4.7";
|
|
1174
|
+
var GROK_MID = "grok-4.6";
|
|
1175
|
+
var GROK_CHEAP = "grok-4.5";
|
|
1118
1176
|
var OPENCODE_BIG = "opencode/big-pickle";
|
|
1119
|
-
var OPENCODE_MINI = "opencode/
|
|
1177
|
+
var OPENCODE_MINI = "opencode/nemotron-3.5-lightning-free";
|
|
1178
|
+
|
|
1179
|
+
// src/business/settings/defaults.ts
|
|
1120
1180
|
var DEFAULT_MODELS_BY_PROVIDER = {
|
|
1121
1181
|
"claude-code": {
|
|
1122
|
-
refine:
|
|
1123
|
-
plan:
|
|
1124
|
-
implement:
|
|
1125
|
-
readiness:
|
|
1126
|
-
ideate:
|
|
1182
|
+
refine: SONNET,
|
|
1183
|
+
plan: OPUS,
|
|
1184
|
+
implement: OPUS,
|
|
1185
|
+
readiness: SONNET,
|
|
1186
|
+
ideate: OPUS,
|
|
1127
1187
|
// PR-content drafting is a single-shot summarisation task — Sonnet matches refine's
|
|
1128
1188
|
// light reasoning profile and avoids the Opus premium for a few-paragraph diff write-up.
|
|
1129
|
-
createPr:
|
|
1189
|
+
createPr: SONNET
|
|
1130
1190
|
},
|
|
1191
|
+
// Same tiers as `copilot-only`. Opus 4.8 rather than Opus 5 / 5.5 (plan-gated on Copilot), and
|
|
1192
|
+
// it tops the Copilot escalation ladder, so the reset-to-copilot implement default and the
|
|
1193
|
+
// ladder top stay aligned.
|
|
1131
1194
|
"github-copilot": {
|
|
1132
|
-
refine:
|
|
1133
|
-
plan:
|
|
1134
|
-
implement:
|
|
1135
|
-
readiness:
|
|
1136
|
-
ideate:
|
|
1137
|
-
createPr:
|
|
1195
|
+
refine: COPILOT_SONNET,
|
|
1196
|
+
plan: COPILOT_OPUS,
|
|
1197
|
+
implement: COPILOT_OPUS,
|
|
1198
|
+
readiness: COPILOT_LUNA,
|
|
1199
|
+
ideate: COPILOT_OPUS,
|
|
1200
|
+
createPr: COPILOT_LUNA
|
|
1138
1201
|
},
|
|
1139
1202
|
"openai-codex": {
|
|
1140
|
-
refine:
|
|
1141
|
-
plan:
|
|
1142
|
-
// `gpt-
|
|
1143
|
-
//
|
|
1144
|
-
implement:
|
|
1145
|
-
readiness:
|
|
1146
|
-
ideate:
|
|
1147
|
-
createPr:
|
|
1203
|
+
refine: GPT_6_LUNA,
|
|
1204
|
+
plan: GPT_6_SOL,
|
|
1205
|
+
// `gpt-6-sol` is the codex flagship; it tops the Codex escalation ladder, so the
|
|
1206
|
+
// reset-to-codex implement default and the ladder top stay aligned.
|
|
1207
|
+
implement: GPT_6_SOL,
|
|
1208
|
+
readiness: GPT_6_LUNA,
|
|
1209
|
+
ideate: GPT_6_SOL,
|
|
1210
|
+
createPr: GPT_6_LUNA
|
|
1148
1211
|
},
|
|
1149
1212
|
// OpenCode aggregates upstream providers, so there is no vendor flagship to default to. These
|
|
1150
1213
|
// are the zero-auth free-tier picks — they make a fresh install runnable with no credentials
|
|
@@ -1159,13 +1222,14 @@ var DEFAULT_MODELS_BY_PROVIDER = {
|
|
|
1159
1222
|
ideate: OPENCODE_BIG,
|
|
1160
1223
|
createPr: OPENCODE_MINI
|
|
1161
1224
|
},
|
|
1225
|
+
// Same split as `grok-only`.
|
|
1162
1226
|
"xai-grok": {
|
|
1163
|
-
refine:
|
|
1164
|
-
plan:
|
|
1165
|
-
implement:
|
|
1166
|
-
readiness:
|
|
1167
|
-
ideate:
|
|
1168
|
-
createPr:
|
|
1227
|
+
refine: GROK_MID,
|
|
1228
|
+
plan: GROK_FLAGSHIP,
|
|
1229
|
+
implement: GROK_FLAGSHIP,
|
|
1230
|
+
readiness: GROK_CHEAP,
|
|
1231
|
+
ideate: GROK_FLAGSHIP,
|
|
1232
|
+
createPr: GROK_CHEAP
|
|
1169
1233
|
}
|
|
1170
1234
|
};
|
|
1171
1235
|
var defaultAiSettingsForProvider = (provider) => {
|
|
@@ -1185,8 +1249,8 @@ var DEFAULT_SETTINGS = {
|
|
|
1185
1249
|
ai: {
|
|
1186
1250
|
...defaultAiSettingsForProvider("claude-code"),
|
|
1187
1251
|
implement: {
|
|
1188
|
-
generator: { provider: "claude-code", model:
|
|
1189
|
-
evaluator: { provider: "openai-codex", model:
|
|
1252
|
+
generator: { provider: "claude-code", model: OPUS },
|
|
1253
|
+
evaluator: { provider: "openai-codex", model: GPT_6_SOL }
|
|
1190
1254
|
}
|
|
1191
1255
|
},
|
|
1192
1256
|
harness: {
|
|
@@ -3903,10 +3967,15 @@ var CONTEXT_WINDOW = {
|
|
|
3903
3967
|
"claude-sonnet-5": 1e6,
|
|
3904
3968
|
// Opus 5 — natively 1M in Claude Code — no `[1m]` selector; the bare id carries the figure.
|
|
3905
3969
|
"claude-opus-5": 1e6,
|
|
3970
|
+
// Opus 5.5 and Fable 5.1 — natively 1M (default AND max) in Claude Code, no `[1m]` selector.
|
|
3971
|
+
"claude-opus-5-5": 1e6,
|
|
3972
|
+
"claude-fable-5-1": 1e6,
|
|
3906
3973
|
// `[1m]` is Claude Code's 1M-token long-context selector — the window IS the id suffix.
|
|
3907
3974
|
"claude-opus-4-8[1m]": 1e6,
|
|
3908
3975
|
"claude-fable-5[1m]": 1e6,
|
|
3909
|
-
// Grok (xai-grok adapter — docs.x.ai published window
|
|
3976
|
+
// Grok (xai-grok adapter — docs.x.ai published window; build-fast is the same model)
|
|
3977
|
+
"grok-4.7": 5e5,
|
|
3978
|
+
"grok-4.7-build-fast": 5e5,
|
|
3910
3979
|
"grok-4.6": 5e5,
|
|
3911
3980
|
"grok-4.5": 5e5
|
|
3912
3981
|
};
|
|
@@ -6005,10 +6074,76 @@ var runCli = (spawn2, command, args, opts) => new Promise((resolve2) => {
|
|
|
6005
6074
|
writeStdinBody(child, opts.stdin);
|
|
6006
6075
|
});
|
|
6007
6076
|
|
|
6008
|
-
// src/integration/scm/
|
|
6077
|
+
// src/integration/scm/gitlab-notes.ts
|
|
6009
6078
|
var CLI_TIMEOUT_MS = 3e4;
|
|
6010
|
-
var MAX_COMMENTS = 20;
|
|
6011
6079
|
var UNKNOWN_ERROR = "unknown error";
|
|
6080
|
+
var NOTES_LABEL = "glab api issue notes";
|
|
6081
|
+
var gitLabNotesArgs = (ref3) => [
|
|
6082
|
+
"api",
|
|
6083
|
+
"--hostname",
|
|
6084
|
+
ref3.hostname,
|
|
6085
|
+
"--paginate",
|
|
6086
|
+
"--output",
|
|
6087
|
+
"json",
|
|
6088
|
+
`projects/${encodeURIComponent(`${ref3.owner}/${ref3.repo}`)}/issues/${String(ref3.number)}/notes?per_page=100&sort=asc&order_by=created_at`
|
|
6089
|
+
];
|
|
6090
|
+
var listGitLabIssueNotes = async (spawn2, ref3) => {
|
|
6091
|
+
const result = await runCli(spawn2, "glab", [...gitLabNotesArgs(ref3)], { timeoutMs: CLI_TIMEOUT_MS });
|
|
6092
|
+
if (!result.ok) return Result.error(result.error);
|
|
6093
|
+
if (result.value.exitCode !== 0) {
|
|
6094
|
+
return Result.error(
|
|
6095
|
+
new StorageError({
|
|
6096
|
+
subCode: "io",
|
|
6097
|
+
message: `${NOTES_LABEL} failed: ${result.value.stderr.trim() || UNKNOWN_ERROR}`
|
|
6098
|
+
})
|
|
6099
|
+
);
|
|
6100
|
+
}
|
|
6101
|
+
let parsed;
|
|
6102
|
+
try {
|
|
6103
|
+
parsed = JSON.parse(result.value.stdout);
|
|
6104
|
+
} catch (cause) {
|
|
6105
|
+
return Result.error(
|
|
6106
|
+
new StorageError({ subCode: "parse", message: `failed to parse ${NOTES_LABEL} response`, cause })
|
|
6107
|
+
);
|
|
6108
|
+
}
|
|
6109
|
+
if (!Array.isArray(parsed)) {
|
|
6110
|
+
return Result.error(
|
|
6111
|
+
new StorageError({ subCode: "parse", message: `failed to parse ${NOTES_LABEL} response: expected a JSON array` })
|
|
6112
|
+
);
|
|
6113
|
+
}
|
|
6114
|
+
const notes = parsed.filter((n) => n.system !== true);
|
|
6115
|
+
const sorted = [...notes].sort((a, b) => (a.created_at ?? "").localeCompare(b.created_at ?? ""));
|
|
6116
|
+
return Result.ok(sorted.map((n) => ({ body: n.body ?? "", author: n.author?.username })));
|
|
6117
|
+
};
|
|
6118
|
+
|
|
6119
|
+
// src/integration/scm/issue-fetcher.ts
|
|
6120
|
+
var CLI_TIMEOUT_MS2 = 3e4;
|
|
6121
|
+
var MAX_COMMENTS = 20;
|
|
6122
|
+
var UNKNOWN_ERROR2 = "unknown error";
|
|
6123
|
+
var parseGitRemoteUrl = (url) => {
|
|
6124
|
+
const trimmed = url.trim();
|
|
6125
|
+
if (trimmed.length === 0) return null;
|
|
6126
|
+
const sshShort = /^[A-Za-z0-9._-]+@([A-Za-z0-9._-]+):([^/]+)\/(.+?)(\.git)?$/u.exec(trimmed);
|
|
6127
|
+
if (sshShort !== null) {
|
|
6128
|
+
const host2 = sshShort[1];
|
|
6129
|
+
const owner2 = sshShort[2];
|
|
6130
|
+
const repo2 = sshShort[3];
|
|
6131
|
+
return { provider: host2.includes("github") ? "github" : "gitlab", owner: owner2, repo: repo2 };
|
|
6132
|
+
}
|
|
6133
|
+
let parsed;
|
|
6134
|
+
try {
|
|
6135
|
+
parsed = new URL(trimmed);
|
|
6136
|
+
} catch {
|
|
6137
|
+
return null;
|
|
6138
|
+
}
|
|
6139
|
+
const segments = parsed.pathname.replace(/^\/+/, "").replace(/\.git$/, "").split("/");
|
|
6140
|
+
if (segments.length < 2) return null;
|
|
6141
|
+
const repo = segments[segments.length - 1];
|
|
6142
|
+
const owner = segments.slice(0, -1).join("/");
|
|
6143
|
+
if (owner.length === 0 || repo === void 0 || repo.length === 0) return null;
|
|
6144
|
+
const host = parsed.hostname;
|
|
6145
|
+
return { provider: host.includes("github") ? "github" : "gitlab", owner, repo };
|
|
6146
|
+
};
|
|
6012
6147
|
var parseGitHubIssuePath = (segments, hostname) => {
|
|
6013
6148
|
if (segments.length >= 4 && segments[2] === "issues") {
|
|
6014
6149
|
const owner = segments[0];
|
|
@@ -6063,7 +6198,7 @@ var fetchGitHub = async (spawn2, parsed, url) => {
|
|
|
6063
6198
|
"--json",
|
|
6064
6199
|
"title,body,state,url,comments"
|
|
6065
6200
|
],
|
|
6066
|
-
{ timeoutMs:
|
|
6201
|
+
{ timeoutMs: CLI_TIMEOUT_MS2 }
|
|
6067
6202
|
);
|
|
6068
6203
|
if (!result.ok) return Result.error(result.error);
|
|
6069
6204
|
if (result.value.exitCode !== 0) {
|
|
@@ -6071,7 +6206,7 @@ var fetchGitHub = async (spawn2, parsed, url) => {
|
|
|
6071
6206
|
return Result.error(
|
|
6072
6207
|
new StorageError({
|
|
6073
6208
|
subCode: "io",
|
|
6074
|
-
message: `gh issue view failed: ${result.value.stderr.trim() ||
|
|
6209
|
+
message: `gh issue view failed: ${result.value.stderr.trim() || UNKNOWN_ERROR2}`
|
|
6075
6210
|
})
|
|
6076
6211
|
);
|
|
6077
6212
|
}
|
|
@@ -6100,33 +6235,11 @@ var fetchGitHub = async (spawn2, parsed, url) => {
|
|
|
6100
6235
|
});
|
|
6101
6236
|
};
|
|
6102
6237
|
var fetchGitLabNotes = async (spawn2, parsed) => {
|
|
6103
|
-
const
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
);
|
|
6109
|
-
if (!result.ok) return { comments: [], failure: result.error.message };
|
|
6110
|
-
if (result.value.exitCode !== 0) {
|
|
6111
|
-
return {
|
|
6112
|
-
comments: [],
|
|
6113
|
-
failure: `glab issue note list exited ${String(result.value.exitCode)}: ${result.value.stderr.trim() || UNKNOWN_ERROR}`
|
|
6114
|
-
};
|
|
6115
|
-
}
|
|
6116
|
-
let notes;
|
|
6117
|
-
try {
|
|
6118
|
-
notes = JSON.parse(result.value.stdout);
|
|
6119
|
-
} catch (cause) {
|
|
6120
|
-
return {
|
|
6121
|
-
comments: [],
|
|
6122
|
-
failure: `failed to parse glab issue note list response: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
6123
|
-
};
|
|
6124
|
-
}
|
|
6125
|
-
const filtered = notes.filter((n) => n.system !== true);
|
|
6126
|
-
const sorted = [...filtered].sort((a, b) => (a.created_at ?? "").localeCompare(b.created_at ?? ""));
|
|
6127
|
-
const comments = sorted.slice(-MAX_COMMENTS).map((n) => ({
|
|
6128
|
-
author: n.author?.username ?? "unknown",
|
|
6129
|
-
body: n.body ?? ""
|
|
6238
|
+
const notes = await listGitLabIssueNotes(spawn2, parsed);
|
|
6239
|
+
if (!notes.ok) return { comments: [], failure: notes.error.message };
|
|
6240
|
+
const comments = notes.value.slice(-MAX_COMMENTS).map((n) => ({
|
|
6241
|
+
author: n.author ?? "unknown",
|
|
6242
|
+
body: n.body
|
|
6130
6243
|
}));
|
|
6131
6244
|
return { comments };
|
|
6132
6245
|
};
|
|
@@ -6135,7 +6248,7 @@ var fetchGitLab = async (spawn2, parsed, url, logger) => {
|
|
|
6135
6248
|
spawn2,
|
|
6136
6249
|
"glab",
|
|
6137
6250
|
["issue", "view", String(parsed.number), "--repo", glabRepoArg(parsed), "--output", "json"],
|
|
6138
|
-
{ timeoutMs:
|
|
6251
|
+
{ timeoutMs: CLI_TIMEOUT_MS2 }
|
|
6139
6252
|
);
|
|
6140
6253
|
if (!result.ok) return Result.error(result.error);
|
|
6141
6254
|
if (result.value.exitCode !== 0) {
|
|
@@ -6143,7 +6256,7 @@ var fetchGitLab = async (spawn2, parsed, url, logger) => {
|
|
|
6143
6256
|
return Result.error(
|
|
6144
6257
|
new StorageError({
|
|
6145
6258
|
subCode: "io",
|
|
6146
|
-
message: `glab issue view failed: ${result.value.stderr.trim() ||
|
|
6259
|
+
message: `glab issue view failed: ${result.value.stderr.trim() || UNKNOWN_ERROR2}`
|
|
6147
6260
|
})
|
|
6148
6261
|
);
|
|
6149
6262
|
}
|
|
@@ -6161,7 +6274,7 @@ var fetchGitLab = async (spawn2, parsed, url, logger) => {
|
|
|
6161
6274
|
}
|
|
6162
6275
|
const notes = await fetchGitLabNotes(spawn2, parsed);
|
|
6163
6276
|
if (notes.failure !== void 0) {
|
|
6164
|
-
logger?.warn(`
|
|
6277
|
+
logger?.warn(`could not list GitLab notes for ${url}: ${notes.failure} \u2014 proceeding without comments`);
|
|
6165
6278
|
}
|
|
6166
6279
|
return Result.ok({
|
|
6167
6280
|
url: parsedJson.web_url ?? url,
|
|
@@ -6178,23 +6291,52 @@ var createIssueFetcher = (deps) => async (url) => {
|
|
|
6178
6291
|
return fetchGitLab(deps.spawn, parsed, url, deps.logger);
|
|
6179
6292
|
};
|
|
6180
6293
|
|
|
6294
|
+
// src/business/scm/pull-request-creator.ts
|
|
6295
|
+
var HTTP_REMOTE_RE = /^https?:\/\/([^/]+)\//i;
|
|
6296
|
+
var SSH_REMOTE_RE = /^(?:git\+ssh:\/\/)?(?:[^@]+@)?([^:/]+)[:/]/i;
|
|
6297
|
+
var parseRemoteHostname = (remoteUrl) => {
|
|
6298
|
+
const trimmed = remoteUrl.trim();
|
|
6299
|
+
if (trimmed.length === 0) return null;
|
|
6300
|
+
const httpMatch = HTTP_REMOTE_RE.exec(trimmed);
|
|
6301
|
+
if (httpMatch?.[1] !== void 0) return httpMatch[1];
|
|
6302
|
+
const sshMatch = SSH_REMOTE_RE.exec(trimmed);
|
|
6303
|
+
if (sshMatch?.[1] !== void 0) return sshMatch[1];
|
|
6304
|
+
return null;
|
|
6305
|
+
};
|
|
6306
|
+
var detectPullRequestPlatform = (remoteUrl) => {
|
|
6307
|
+
const hostname = parseRemoteHostname(remoteUrl);
|
|
6308
|
+
if (hostname === null) return null;
|
|
6309
|
+
const lower = hostname.toLowerCase();
|
|
6310
|
+
if (lower === "github.com" || lower.endsWith(".github.com")) return "github";
|
|
6311
|
+
if (lower === "gitlab.com" || lower.startsWith("gitlab.") || lower.includes(".gitlab.")) return "gitlab";
|
|
6312
|
+
return null;
|
|
6313
|
+
};
|
|
6314
|
+
var parseUrlFromCliStdout = (stdout) => {
|
|
6315
|
+
const lines = stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
6316
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
6317
|
+
const line = lines[i];
|
|
6318
|
+
if (line !== void 0 && /^https?:\/\//.test(line)) return line;
|
|
6319
|
+
}
|
|
6320
|
+
return lines.at(-1) ?? null;
|
|
6321
|
+
};
|
|
6322
|
+
|
|
6181
6323
|
// src/integration/scm/issue-pusher.ts
|
|
6182
|
-
var
|
|
6324
|
+
var CLI_TIMEOUT_MS3 = 3e4;
|
|
6325
|
+
var UNKNOWN_ERROR3 = "unknown error";
|
|
6326
|
+
var cliFailed = (noun, stderr, extra) => new StorageError({
|
|
6327
|
+
subCode: "io",
|
|
6328
|
+
message: extra === void 0 ? `${noun} failed: ${stderr.trim() || UNKNOWN_ERROR3}` : `${noun} failed: ${stderr.trim() || UNKNOWN_ERROR3} (${extra})`
|
|
6329
|
+
});
|
|
6183
6330
|
var commentGitHub = async (spawn2, url, body, parsed) => {
|
|
6184
6331
|
const r = await runCli(
|
|
6185
6332
|
spawn2,
|
|
6186
6333
|
"gh",
|
|
6187
6334
|
["issue", "comment", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--body-file", "-"],
|
|
6188
|
-
{ stdin: body, timeoutMs:
|
|
6335
|
+
{ stdin: body, timeoutMs: CLI_TIMEOUT_MS3 }
|
|
6189
6336
|
);
|
|
6190
6337
|
if (!r.ok) return Result.error(r.error);
|
|
6191
6338
|
if (r.value.exitCode !== 0) {
|
|
6192
|
-
return Result.error(
|
|
6193
|
-
new StorageError({
|
|
6194
|
-
subCode: "io",
|
|
6195
|
-
message: `gh issue comment failed: ${r.value.stderr.trim() || "unknown error"} (url=${url})`
|
|
6196
|
-
})
|
|
6197
|
-
);
|
|
6339
|
+
return Result.error(cliFailed("gh issue comment", r.value.stderr, `url=${url}`));
|
|
6198
6340
|
}
|
|
6199
6341
|
return Result.ok(void 0);
|
|
6200
6342
|
};
|
|
@@ -6208,23 +6350,148 @@ var commentGitLab = async (spawn2, url, body, parsed) => {
|
|
|
6208
6350
|
String(parsed.number),
|
|
6209
6351
|
"--repo",
|
|
6210
6352
|
`${parsed.hostname}/${parsed.owner}/${parsed.repo}`,
|
|
6211
|
-
"--
|
|
6353
|
+
"--message",
|
|
6212
6354
|
body
|
|
6213
6355
|
],
|
|
6214
|
-
{ timeoutMs:
|
|
6356
|
+
{ timeoutMs: CLI_TIMEOUT_MS3 }
|
|
6357
|
+
);
|
|
6358
|
+
if (!r.ok) return Result.error(r.error);
|
|
6359
|
+
if (r.value.exitCode !== 0) {
|
|
6360
|
+
return Result.error(cliFailed("glab issue comment", r.value.stderr, `url=${url}`));
|
|
6361
|
+
}
|
|
6362
|
+
return Result.ok(void 0);
|
|
6363
|
+
};
|
|
6364
|
+
var resolveOriginFromGit = async (gitRunner, cwd) => {
|
|
6365
|
+
const result = await gitRunner.run(cwd, ["remote", "get-url", "origin"]);
|
|
6366
|
+
if (!result.ok) return Result.error(result.error);
|
|
6367
|
+
if (result.value.exitCode !== 0) return Result.ok(null);
|
|
6368
|
+
const url = result.value.stdout.trim();
|
|
6369
|
+
if (url.length === 0) return Result.ok(null);
|
|
6370
|
+
const parsed = parseGitRemoteUrl(url);
|
|
6371
|
+
if (parsed === null) return Result.ok(null);
|
|
6372
|
+
const platform = detectPullRequestPlatform(url);
|
|
6373
|
+
if (platform === null) return Result.ok(null);
|
|
6374
|
+
const hostname = parseRemoteHostname(url);
|
|
6375
|
+
if (hostname === null) return Result.ok(null);
|
|
6376
|
+
return Result.ok({
|
|
6377
|
+
provider: platform,
|
|
6378
|
+
hostname,
|
|
6379
|
+
owner: parsed.owner,
|
|
6380
|
+
repo: parsed.repo
|
|
6381
|
+
});
|
|
6382
|
+
};
|
|
6383
|
+
var createGitHub = async (spawn2, origin, title, body) => {
|
|
6384
|
+
const r = await runCli(
|
|
6385
|
+
spawn2,
|
|
6386
|
+
"gh",
|
|
6387
|
+
["issue", "create", "--repo", `${origin.owner}/${origin.repo}`, "--title", title, "--body-file", "-"],
|
|
6388
|
+
{ stdin: body, timeoutMs: CLI_TIMEOUT_MS3 }
|
|
6215
6389
|
);
|
|
6216
6390
|
if (!r.ok) return Result.error(r.error);
|
|
6217
6391
|
if (r.value.exitCode !== 0) {
|
|
6392
|
+
return Result.error(cliFailed("gh issue create", r.value.stderr));
|
|
6393
|
+
}
|
|
6394
|
+
const url = parseUrlFromCliStdout(r.value.stdout);
|
|
6395
|
+
if (url === null) {
|
|
6396
|
+
return Result.error(new StorageError({ subCode: "io", message: "gh issue create succeeded but emitted no URL" }));
|
|
6397
|
+
}
|
|
6398
|
+
return Result.ok({ url });
|
|
6399
|
+
};
|
|
6400
|
+
var createGitLab = async (spawn2, origin, title, body) => {
|
|
6401
|
+
const r = await runCli(
|
|
6402
|
+
spawn2,
|
|
6403
|
+
"glab",
|
|
6404
|
+
[
|
|
6405
|
+
"issue",
|
|
6406
|
+
"create",
|
|
6407
|
+
"--repo",
|
|
6408
|
+
`${origin.hostname}/${origin.owner}/${origin.repo}`,
|
|
6409
|
+
"--title",
|
|
6410
|
+
title,
|
|
6411
|
+
"--description",
|
|
6412
|
+
body
|
|
6413
|
+
],
|
|
6414
|
+
{ timeoutMs: CLI_TIMEOUT_MS3 }
|
|
6415
|
+
);
|
|
6416
|
+
if (!r.ok) return Result.error(r.error);
|
|
6417
|
+
if (r.value.exitCode !== 0) {
|
|
6418
|
+
return Result.error(cliFailed("glab issue create", r.value.stderr));
|
|
6419
|
+
}
|
|
6420
|
+
const url = parseUrlFromCliStdout(r.value.stdout);
|
|
6421
|
+
if (url === null) {
|
|
6422
|
+
return Result.error(new StorageError({ subCode: "io", message: "glab issue create succeeded but emitted no URL" }));
|
|
6423
|
+
}
|
|
6424
|
+
return Result.ok({ url });
|
|
6425
|
+
};
|
|
6426
|
+
var listGitHubComments = async (spawn2, parsed) => {
|
|
6427
|
+
const result = await runCli(
|
|
6428
|
+
spawn2,
|
|
6429
|
+
"gh",
|
|
6430
|
+
[
|
|
6431
|
+
"issue",
|
|
6432
|
+
"view",
|
|
6433
|
+
String(parsed.number),
|
|
6434
|
+
"--repo",
|
|
6435
|
+
`${parsed.owner}/${parsed.repo}`,
|
|
6436
|
+
"--json",
|
|
6437
|
+
"title,body,state,url,comments"
|
|
6438
|
+
],
|
|
6439
|
+
{ timeoutMs: CLI_TIMEOUT_MS3 }
|
|
6440
|
+
);
|
|
6441
|
+
if (!result.ok) return Result.error(result.error);
|
|
6442
|
+
if (result.value.exitCode !== 0) {
|
|
6443
|
+
return Result.error(cliFailed("gh issue view", result.value.stderr));
|
|
6444
|
+
}
|
|
6445
|
+
let parsedJson;
|
|
6446
|
+
try {
|
|
6447
|
+
parsedJson = JSON.parse(result.value.stdout);
|
|
6448
|
+
} catch (cause) {
|
|
6218
6449
|
return Result.error(
|
|
6219
6450
|
new StorageError({
|
|
6220
|
-
subCode: "
|
|
6221
|
-
message:
|
|
6451
|
+
subCode: "parse",
|
|
6452
|
+
message: "failed to parse gh issue response",
|
|
6453
|
+
cause
|
|
6222
6454
|
})
|
|
6223
6455
|
);
|
|
6224
6456
|
}
|
|
6225
|
-
return Result.ok(
|
|
6457
|
+
return Result.ok((parsedJson.comments ?? []).map((c) => c.body ?? ""));
|
|
6458
|
+
};
|
|
6459
|
+
var listGitLabComments = async (spawn2, parsed) => {
|
|
6460
|
+
const notes = await listGitLabIssueNotes(spawn2, parsed);
|
|
6461
|
+
if (!notes.ok) return Result.error(notes.error);
|
|
6462
|
+
return Result.ok(notes.value.map((n) => n.body));
|
|
6226
6463
|
};
|
|
6227
6464
|
var createIssuePusher = (deps) => ({
|
|
6465
|
+
async resolveOrigin(cwd) {
|
|
6466
|
+
return resolveOriginFromGit(deps.gitRunner, cwd);
|
|
6467
|
+
},
|
|
6468
|
+
async create({ cwd, title, body }) {
|
|
6469
|
+
const origin = await resolveOriginFromGit(deps.gitRunner, cwd);
|
|
6470
|
+
if (!origin.ok) return Result.error(origin.error);
|
|
6471
|
+
if (origin.value === null) {
|
|
6472
|
+
return Result.error(
|
|
6473
|
+
new StorageError({
|
|
6474
|
+
subCode: "io",
|
|
6475
|
+
message: `no GitHub or GitLab origin at ${String(cwd)}`
|
|
6476
|
+
})
|
|
6477
|
+
);
|
|
6478
|
+
}
|
|
6479
|
+
if (origin.value.provider === "github") return createGitHub(deps.spawn, origin.value, title, body);
|
|
6480
|
+
return createGitLab(deps.spawn, origin.value, title, body);
|
|
6481
|
+
},
|
|
6482
|
+
async listComments(url) {
|
|
6483
|
+
const parsed = parseIssueUrl(url);
|
|
6484
|
+
if (parsed === null) {
|
|
6485
|
+
return Result.error(
|
|
6486
|
+
new StorageError({
|
|
6487
|
+
subCode: "parse",
|
|
6488
|
+
message: `unsupported issue URL: ${url}`
|
|
6489
|
+
})
|
|
6490
|
+
);
|
|
6491
|
+
}
|
|
6492
|
+
if (parsed.host === "github") return listGitHubComments(deps.spawn, parsed);
|
|
6493
|
+
return listGitLabComments(deps.spawn, parsed);
|
|
6494
|
+
},
|
|
6228
6495
|
async comment(url, { body }) {
|
|
6229
6496
|
const parsed = parseIssueUrl(url);
|
|
6230
6497
|
if (parsed === null) {
|
|
@@ -6240,37 +6507,8 @@ var createIssuePusher = (deps) => ({
|
|
|
6240
6507
|
}
|
|
6241
6508
|
});
|
|
6242
6509
|
|
|
6243
|
-
// src/business/scm/pull-request-creator.ts
|
|
6244
|
-
var HTTP_REMOTE_RE = /^https?:\/\/([^/]+)\//i;
|
|
6245
|
-
var SSH_REMOTE_RE = /^(?:git\+ssh:\/\/)?(?:[^@]+@)?([^:/]+)[:/]/i;
|
|
6246
|
-
var parseRemoteHostname = (remoteUrl) => {
|
|
6247
|
-
const trimmed = remoteUrl.trim();
|
|
6248
|
-
if (trimmed.length === 0) return null;
|
|
6249
|
-
const httpMatch = HTTP_REMOTE_RE.exec(trimmed);
|
|
6250
|
-
if (httpMatch?.[1] !== void 0) return httpMatch[1];
|
|
6251
|
-
const sshMatch = SSH_REMOTE_RE.exec(trimmed);
|
|
6252
|
-
if (sshMatch?.[1] !== void 0) return sshMatch[1];
|
|
6253
|
-
return null;
|
|
6254
|
-
};
|
|
6255
|
-
var detectPullRequestPlatform = (remoteUrl) => {
|
|
6256
|
-
const hostname = parseRemoteHostname(remoteUrl);
|
|
6257
|
-
if (hostname === null) return null;
|
|
6258
|
-
const lower = hostname.toLowerCase();
|
|
6259
|
-
if (lower === "github.com" || lower.endsWith(".github.com")) return "github";
|
|
6260
|
-
if (lower === "gitlab.com" || lower.startsWith("gitlab.") || lower.includes(".gitlab.")) return "gitlab";
|
|
6261
|
-
return null;
|
|
6262
|
-
};
|
|
6263
|
-
var parseUrlFromCliStdout = (stdout) => {
|
|
6264
|
-
const lines = stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
6265
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
6266
|
-
const line = lines[i];
|
|
6267
|
-
if (line !== void 0 && /^https?:\/\//.test(line)) return line;
|
|
6268
|
-
}
|
|
6269
|
-
return lines.at(-1) ?? null;
|
|
6270
|
-
};
|
|
6271
|
-
|
|
6272
6510
|
// src/integration/scm/pull-request-creator.ts
|
|
6273
|
-
var
|
|
6511
|
+
var CLI_TIMEOUT_MS4 = 6e4;
|
|
6274
6512
|
var getOriginRemoteUrl = async (gitRunner, cwd) => {
|
|
6275
6513
|
const result = await gitRunner.run(cwd, ["remote", "get-url", "origin"]);
|
|
6276
6514
|
if (!result.ok) return Result.error(result.error);
|
|
@@ -6329,7 +6567,7 @@ var runPlatformCli = async (spawn2, platform, input) => {
|
|
|
6329
6567
|
const command = platform === "github" ? "gh" : "glab";
|
|
6330
6568
|
const args = platform === "github" ? buildGhArgs(input) : buildGlabArgs(input);
|
|
6331
6569
|
const noun = platform === "github" ? "gh pr create" : "glab mr create";
|
|
6332
|
-
const result = await runCli(spawn2, command, args, { cwd: String(input.cwd), timeoutMs:
|
|
6570
|
+
const result = await runCli(spawn2, command, args, { cwd: String(input.cwd), timeoutMs: CLI_TIMEOUT_MS4 });
|
|
6333
6571
|
if (!result.ok) return Result.error(result.error);
|
|
6334
6572
|
if (result.value.exitCode !== 0) {
|
|
6335
6573
|
const stderr = result.value.stderr.trim();
|
|
@@ -7127,7 +7365,7 @@ var createNpmVersionChecker = (deps) => {
|
|
|
7127
7365
|
// package.json
|
|
7128
7366
|
var package_default = {
|
|
7129
7367
|
name: "ralphctl",
|
|
7130
|
-
version: "0.
|
|
7368
|
+
version: "0.23.0",
|
|
7131
7369
|
description: "A ralph harness for long-running AI coding tasks \u2014 a generator-evaluator loop that drives Claude Code, GitHub Copilot CLI, OpenAI Codex CLI, OpenCode or Grok Build CLI across one or more repositories",
|
|
7132
7370
|
homepage: "https://github.com/lukas-grigis/ralphctl",
|
|
7133
7371
|
type: "module",
|
|
@@ -7209,24 +7447,24 @@ var package_default = {
|
|
|
7209
7447
|
devDependencies: {
|
|
7210
7448
|
"@eslint/js": "^10.0.1",
|
|
7211
7449
|
"@types/cross-spawn": "^6.0.6",
|
|
7212
|
-
"@types/node": "^26.
|
|
7450
|
+
"@types/node": "^26.6.2",
|
|
7213
7451
|
"@types/proper-lockfile": "^4.1.4",
|
|
7214
7452
|
"@types/react": "^19.3.0",
|
|
7215
7453
|
"@vitest/coverage-v8": "^5.0.0",
|
|
7216
|
-
eslint: "^10.
|
|
7454
|
+
eslint: "^10.11.0",
|
|
7217
7455
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
7218
7456
|
"eslint-plugin-sonarjs": "^4.2.0",
|
|
7219
7457
|
globals: "^17.12.0",
|
|
7220
7458
|
husky: "^9.1.7",
|
|
7221
7459
|
"ink-testing-library": "^4.0.0",
|
|
7222
7460
|
jiti: "^2.7.0",
|
|
7223
|
-
knip: "^6.
|
|
7461
|
+
knip: "^6.37.0",
|
|
7224
7462
|
"lint-staged": "^17.5.0",
|
|
7225
|
-
prettier: "^3.9.
|
|
7463
|
+
prettier: "^3.9.8",
|
|
7226
7464
|
tsup: "^8.5.1",
|
|
7227
|
-
tsx: "^4.23.
|
|
7465
|
+
tsx: "^4.23.15",
|
|
7228
7466
|
typescript: "^6.0.3",
|
|
7229
|
-
"typescript-eslint": "^8.70.
|
|
7467
|
+
"typescript-eslint": "^8.70.1",
|
|
7230
7468
|
vite: "^8.2.2",
|
|
7231
7469
|
vitest: "^5.0.0"
|
|
7232
7470
|
},
|
|
@@ -7246,30 +7484,45 @@ var CLI_METADATA = {
|
|
|
7246
7484
|
};
|
|
7247
7485
|
|
|
7248
7486
|
// src/business/task/escalation-map.ts
|
|
7249
|
-
var
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
"claude-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7487
|
+
var CLAUDE_OPUS_5_5 = "claude-opus-5-5";
|
|
7488
|
+
var GPT_5_5 = "gpt-5.5";
|
|
7489
|
+
var GPT_5_6_SOL = "gpt-5.6-sol";
|
|
7490
|
+
var GPT_6_SOL2 = "gpt-6-sol";
|
|
7491
|
+
var DEFAULT_ESCALATION_LADDERS = {
|
|
7492
|
+
"claude-code": {
|
|
7493
|
+
"claude-haiku-4-5": "claude-sonnet-5",
|
|
7494
|
+
"claude-sonnet-5": CLAUDE_OPUS_5_5,
|
|
7495
|
+
"claude-sonnet-4-6": "claude-opus-4-8",
|
|
7496
|
+
"claude-opus-4-8": CLAUDE_OPUS_5_5,
|
|
7497
|
+
"claude-opus-5": CLAUDE_OPUS_5_5
|
|
7498
|
+
},
|
|
7499
|
+
"github-copilot": {
|
|
7500
|
+
"claude-haiku-4.5": "claude-sonnet-5",
|
|
7501
|
+
"claude-sonnet-5": "claude-opus-4.8",
|
|
7502
|
+
"claude-opus-4.7": "claude-opus-4.8",
|
|
7503
|
+
"gpt-5-mini": GPT_5_5,
|
|
7504
|
+
"gpt-5.4-mini": GPT_5_5,
|
|
7505
|
+
"gpt-5.4": GPT_5_5,
|
|
7506
|
+
[GPT_5_5]: GPT_5_6_SOL,
|
|
7507
|
+
"gpt-5.6-luna": "gpt-5.6-terra",
|
|
7508
|
+
"gpt-5.6-terra": GPT_5_6_SOL,
|
|
7509
|
+
"grok-4.5": "grok-4.6"
|
|
7510
|
+
},
|
|
7511
|
+
"openai-codex": {
|
|
7512
|
+
"gpt-6-luna": GPT_6_SOL2,
|
|
7513
|
+
[GPT_5_5]: GPT_5_6_SOL,
|
|
7514
|
+
"gpt-5.6-luna": "gpt-5.6-terra",
|
|
7515
|
+
"gpt-5.6-terra": GPT_5_6_SOL,
|
|
7516
|
+
[GPT_5_6_SOL]: GPT_6_SOL2
|
|
7517
|
+
},
|
|
7518
|
+
"xai-grok": {
|
|
7519
|
+
"grok-4.5": "grok-4.6",
|
|
7520
|
+
"grok-4.6": "grok-4.7"
|
|
7521
|
+
},
|
|
7522
|
+
opencode: {}
|
|
7523
|
+
};
|
|
7524
|
+
var mergeEscalationMap = (user, provider) => ({
|
|
7525
|
+
...provider === void 0 ? {} : DEFAULT_ESCALATION_LADDERS[provider],
|
|
7273
7526
|
...user
|
|
7274
7527
|
});
|
|
7275
7528
|
var warnEscalationMapSelfLoops = (escalationMap, logger) => {
|
|
@@ -7279,6 +7532,17 @@ var warnEscalationMapSelfLoops = (escalationMap, logger) => {
|
|
|
7279
7532
|
}
|
|
7280
7533
|
}
|
|
7281
7534
|
};
|
|
7535
|
+
var warnEscalationMapRetiredValues = (escalationMap, logger) => {
|
|
7536
|
+
for (const [from, to] of Object.entries(escalationMap)) {
|
|
7537
|
+
const retirements = RETIRED_MODEL_REMAPS.filter((r) => r.from === to);
|
|
7538
|
+
if (retirements.length === 0) continue;
|
|
7539
|
+
const where = retirements.map((r) => `${r.provider} (successor '${r.to}')`).join(", ");
|
|
7540
|
+
logger.warn(
|
|
7541
|
+
`escalationMap: '${from}' escalates to '${to}', which is retired on ${where} \u2014 left unchanged because the slug is ambiguous; pin the successor if the generator runs there`,
|
|
7542
|
+
{ from, to }
|
|
7543
|
+
);
|
|
7544
|
+
}
|
|
7545
|
+
};
|
|
7282
7546
|
var escalationLadderCyclicFrom = (map, start) => {
|
|
7283
7547
|
const seen = /* @__PURE__ */ new Set([start]);
|
|
7284
7548
|
let cur = map[start];
|
|
@@ -7300,19 +7564,21 @@ var EFFORT_CAPABLE_PROVIDERS = /* @__PURE__ */ new Set([
|
|
|
7300
7564
|
"xai-grok"
|
|
7301
7565
|
]);
|
|
7302
7566
|
var CLAUDE_EFFORT_LADDER = ["low", "medium", "high", "xhigh", "max"];
|
|
7303
|
-
var CLAUDE_XHIGH_INDEX = CLAUDE_EFFORT_LADDER.indexOf("xhigh");
|
|
7304
|
-
var CLAUDE_MAX_INDEX = CLAUDE_EFFORT_LADDER.indexOf("max");
|
|
7305
7567
|
var CLAUDE_EFFORTLESS_MODELS = /* @__PURE__ */ new Set(["claude-haiku-4-5", "claude-haiku-4.5"]);
|
|
7306
|
-
var
|
|
7568
|
+
var CLAUDE_NO_XHIGH_MODELS = /* @__PURE__ */ new Set(["claude-sonnet-4-6", "claude-sonnet-4.6"]);
|
|
7569
|
+
var CLAUDE_CLI_DEFAULT_EFFORT = {
|
|
7570
|
+
"claude-opus-5-5": "medium",
|
|
7571
|
+
"claude-opus-5.5": "medium"
|
|
7572
|
+
};
|
|
7573
|
+
var CLAUDE_FALLBACK_CLI_DEFAULT_EFFORT = "high";
|
|
7574
|
+
var isClaudeEffort = (s) => CLAUDE_EFFORT_LADDER.includes(s);
|
|
7307
7575
|
var claudeEffortRung = (model, currentEffort) => {
|
|
7308
7576
|
if (CLAUDE_EFFORTLESS_MODELS.has(model)) return void 0;
|
|
7309
|
-
const
|
|
7310
|
-
|
|
7577
|
+
const effective = currentEffort ?? CLAUDE_CLI_DEFAULT_EFFORT[model] ?? CLAUDE_FALLBACK_CLI_DEFAULT_EFFORT;
|
|
7578
|
+
if (!isClaudeEffort(effective)) return void 0;
|
|
7311
7579
|
const effectiveIndex = CLAUDE_EFFORT_LADDER.indexOf(effective);
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
if (xhighCapable && effectiveIndex < CLAUDE_XHIGH_INDEX) return "xhigh";
|
|
7315
|
-
return CLAUDE_EFFORT_LADDER[CLAUDE_MAX_INDEX];
|
|
7580
|
+
const modelLadder = CLAUDE_NO_XHIGH_MODELS.has(model) ? CLAUDE_EFFORT_LADDER.filter((level) => level !== "xhigh") : CLAUDE_EFFORT_LADDER;
|
|
7581
|
+
return modelLadder.find((level) => CLAUDE_EFFORT_LADDER.indexOf(level) > effectiveIndex);
|
|
7316
7582
|
};
|
|
7317
7583
|
var nextEffortRung = (provider, model, currentEffort) => {
|
|
7318
7584
|
if (provider === void 0 || !EFFORT_CAPABLE_PROVIDERS.has(provider)) return void 0;
|
|
@@ -8990,6 +9256,7 @@ var wire = (opts) => {
|
|
|
8990
9256
|
const eventBus = createInMemoryEventBus();
|
|
8991
9257
|
const logger = createEventBusLogger({ eventBus, clock: IsoTimestamp.now });
|
|
8992
9258
|
warnEscalationMapSelfLoops(opts.settings.harness.escalationMap, logger);
|
|
9259
|
+
warnEscalationMapRetiredValues(opts.settings.harness.escalationMap, logger);
|
|
8993
9260
|
const notificationDispatcher = opts.notificationDispatcher ?? noopNotificationDispatcher;
|
|
8994
9261
|
const fileLocker = createFileLocker({
|
|
8995
9262
|
// Surface stale `.lock` files via the application logger. The locker is intentionally
|
|
@@ -9012,6 +9279,7 @@ var wire = (opts) => {
|
|
|
9012
9279
|
return pending;
|
|
9013
9280
|
};
|
|
9014
9281
|
const atomicWriteFile = createAtomicWriteFile();
|
|
9282
|
+
const gitRunner = createGitRunner();
|
|
9015
9283
|
return {
|
|
9016
9284
|
storage: opts.storage,
|
|
9017
9285
|
projectRepo: createFsProjectRepository({ root: opts.storage.dataRoot }),
|
|
@@ -9022,7 +9290,7 @@ var wire = (opts) => {
|
|
|
9022
9290
|
settingsRepo: createJsonSettingsRepository({ configRoot: opts.storage.configRoot }),
|
|
9023
9291
|
provider: buildWireProvider(opts, eventBus, providerSpawn),
|
|
9024
9292
|
...providerSpawn !== void 0 ? { providerSpawn } : {},
|
|
9025
|
-
gitRunner
|
|
9293
|
+
gitRunner,
|
|
9026
9294
|
shellScriptRunner: createShellScriptRunner(),
|
|
9027
9295
|
fileLocker,
|
|
9028
9296
|
writeFile: atomicWriteFile,
|
|
@@ -9037,7 +9305,7 @@ var wire = (opts) => {
|
|
|
9037
9305
|
logger,
|
|
9038
9306
|
pullRequestCreator: createPullRequestCreator({ gitRunner: createGitRunner(), spawn: spawn2 }),
|
|
9039
9307
|
issueFetcher: createIssueFetcher({ spawn: spawn2, logger }),
|
|
9040
|
-
issuePusher: createIssuePusher({ spawn: spawn2 }),
|
|
9308
|
+
issuePusher: createIssuePusher({ spawn: spawn2, gitRunner }),
|
|
9041
9309
|
versionChecker: createNpmVersionChecker({
|
|
9042
9310
|
stateRoot: opts.storage.stateRoot,
|
|
9043
9311
|
currentVersion: CLI_METADATA.currentVersion,
|
|
@@ -15748,25 +16016,24 @@ var warnIfContractViolated = (logger, skillName, content) => {
|
|
|
15748
16016
|
|
|
15749
16017
|
// src/business/settings/resolve-effort.ts
|
|
15750
16018
|
var FLOW_DEFAULT_EFFORT = {
|
|
16019
|
+
refine: "medium",
|
|
15751
16020
|
plan: "high",
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
return resolveEffortForRow(row, settings.ai.effort, flow);
|
|
16021
|
+
implement: "high",
|
|
16022
|
+
readiness: "medium",
|
|
16023
|
+
ideate: "high",
|
|
16024
|
+
createPr: "low"
|
|
15757
16025
|
};
|
|
16026
|
+
var resolveEffort = (flow, settings) => resolveEffortForRow(primaryFlowRow(settings.ai, flow), settings.ai.effort, flow);
|
|
15758
16027
|
var resolveEffortForRow = (row, globalEffort, flow) => {
|
|
15759
16028
|
if (row.effort !== void 0) return row.effort;
|
|
15760
|
-
if (globalEffort !== void 0) return
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
return void 0;
|
|
16029
|
+
if (globalEffort !== void 0) return clampEffortToProvider(globalEffort, row.provider);
|
|
16030
|
+
if (row.provider === "opencode") return void 0;
|
|
16031
|
+
return clampEffortToProvider(FLOW_DEFAULT_EFFORT[flow], row.provider);
|
|
15764
16032
|
};
|
|
15765
16033
|
var clampEffortToProvider = (effort, provider) => {
|
|
15766
16034
|
if (provider === "openai-codex" && effort === "max") return "xhigh";
|
|
15767
16035
|
return effort;
|
|
15768
16036
|
};
|
|
15769
|
-
var _floorForProvider = (effort, provider) => clampEffortToProvider(effort, provider);
|
|
15770
16037
|
|
|
15771
16038
|
// src/application/session/session.ts
|
|
15772
16039
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -16091,6 +16358,142 @@ var setExecutionBaselineBrokenPolicy = (execution, policy) => {
|
|
|
16091
16358
|
return { ...execution, baselineBrokenPolicy: policy };
|
|
16092
16359
|
};
|
|
16093
16360
|
|
|
16361
|
+
// src/domain/value/external-ref.ts
|
|
16362
|
+
var toIssueRef = (segment) => {
|
|
16363
|
+
const num2 = Number(segment);
|
|
16364
|
+
return Number.isInteger(num2) && num2 > 0 ? `#${String(num2)}` : void 0;
|
|
16365
|
+
};
|
|
16366
|
+
var parseGithubIssueRef = (segments) => {
|
|
16367
|
+
if (segments.length < 4 || segments[2] !== "issues") return void 0;
|
|
16368
|
+
return toIssueRef(segments[3]);
|
|
16369
|
+
};
|
|
16370
|
+
var parseGitlabIssueRef = (segments) => {
|
|
16371
|
+
const dashIdx = segments.indexOf("-");
|
|
16372
|
+
if (dashIdx < 2 || segments[dashIdx + 1] !== "issues") return void 0;
|
|
16373
|
+
return toIssueRef(segments[dashIdx + 2]);
|
|
16374
|
+
};
|
|
16375
|
+
var parseExternalRefFromUrl = (url) => {
|
|
16376
|
+
let parsed;
|
|
16377
|
+
try {
|
|
16378
|
+
parsed = new URL(url);
|
|
16379
|
+
} catch {
|
|
16380
|
+
return void 0;
|
|
16381
|
+
}
|
|
16382
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return void 0;
|
|
16383
|
+
const segments = parsed.pathname.split("/").filter((s) => s.length > 0);
|
|
16384
|
+
return parsed.hostname.includes("github") ? parseGithubIssueRef(segments) : parseGitlabIssueRef(segments);
|
|
16385
|
+
};
|
|
16386
|
+
var normalizeRefs = (refs) => {
|
|
16387
|
+
if (refs === void 0 || refs.length === 0) return [];
|
|
16388
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16389
|
+
const ordered = [];
|
|
16390
|
+
for (const r of refs) {
|
|
16391
|
+
const trimmed = r.trim();
|
|
16392
|
+
if (trimmed.length === 0) continue;
|
|
16393
|
+
if (seen.has(trimmed)) continue;
|
|
16394
|
+
seen.add(trimmed);
|
|
16395
|
+
ordered.push(trimmed);
|
|
16396
|
+
}
|
|
16397
|
+
return ordered;
|
|
16398
|
+
};
|
|
16399
|
+
|
|
16400
|
+
// src/domain/value/parsers/parse-optional-string.ts
|
|
16401
|
+
var parseOptionalString = (field, value) => {
|
|
16402
|
+
if (value === void 0) return Result.ok(void 0);
|
|
16403
|
+
const trimmed = value.trim();
|
|
16404
|
+
if (trimmed.length === 0) {
|
|
16405
|
+
return Result.error(
|
|
16406
|
+
new ValidationError({
|
|
16407
|
+
field,
|
|
16408
|
+
value,
|
|
16409
|
+
message: `${field} must be non-empty when provided`,
|
|
16410
|
+
hint: "omit the field instead of passing an empty string"
|
|
16411
|
+
})
|
|
16412
|
+
);
|
|
16413
|
+
}
|
|
16414
|
+
return Result.ok(trimmed);
|
|
16415
|
+
};
|
|
16416
|
+
|
|
16417
|
+
// src/domain/entity/ticket.ts
|
|
16418
|
+
var createTicket = (input) => {
|
|
16419
|
+
const title = parseRequiredString("ticket.title", input.title);
|
|
16420
|
+
if (!title.ok) return Result.error(title.error);
|
|
16421
|
+
const description = parseOptionalString("ticket.description", input.description);
|
|
16422
|
+
if (!description.ok) return Result.error(description.error);
|
|
16423
|
+
let link;
|
|
16424
|
+
if (input.link !== void 0) {
|
|
16425
|
+
const parsed = parseHttpUrl("ticket.link", input.link);
|
|
16426
|
+
if (!parsed.ok) return Result.error(parsed.error);
|
|
16427
|
+
link = parsed.value;
|
|
16428
|
+
}
|
|
16429
|
+
const trimmedRef = input.externalRef?.trim();
|
|
16430
|
+
const suppliedRef = trimmedRef !== void 0 && trimmedRef.length > 0 ? trimmedRef : void 0;
|
|
16431
|
+
const externalRef = suppliedRef ?? (link !== void 0 ? parseExternalRefFromUrl(link) : void 0);
|
|
16432
|
+
return Result.ok({
|
|
16433
|
+
id: input.id ?? TicketId.generate(),
|
|
16434
|
+
title: title.value,
|
|
16435
|
+
...description.value !== void 0 ? { description: description.value } : {},
|
|
16436
|
+
...link !== void 0 ? { link } : {},
|
|
16437
|
+
...externalRef !== void 0 ? { externalRef } : {},
|
|
16438
|
+
status: "pending",
|
|
16439
|
+
requirements: void 0
|
|
16440
|
+
});
|
|
16441
|
+
};
|
|
16442
|
+
function setTicketLink(ticket, url) {
|
|
16443
|
+
if (url === void 0) {
|
|
16444
|
+
const { link: _drop, ...rest } = ticket;
|
|
16445
|
+
void _drop;
|
|
16446
|
+
return Result.ok(rest);
|
|
16447
|
+
}
|
|
16448
|
+
const parsed = parseHttpUrl("ticket.link", url);
|
|
16449
|
+
if (!parsed.ok) return Result.error(parsed.error);
|
|
16450
|
+
const derivedRef = ticket.externalRef === void 0 ? parseExternalRefFromUrl(parsed.value) : void 0;
|
|
16451
|
+
return Result.ok({
|
|
16452
|
+
...ticket,
|
|
16453
|
+
link: parsed.value,
|
|
16454
|
+
...derivedRef !== void 0 ? { externalRef: derivedRef } : {}
|
|
16455
|
+
});
|
|
16456
|
+
}
|
|
16457
|
+
function setTicketTitle(ticket, title) {
|
|
16458
|
+
const parsed = parseRequiredString("ticket.title", title);
|
|
16459
|
+
if (!parsed.ok) return Result.error(parsed.error);
|
|
16460
|
+
return Result.ok({ ...ticket, title: parsed.value });
|
|
16461
|
+
}
|
|
16462
|
+
function setTicketDescription(ticket, description) {
|
|
16463
|
+
const parsed = parseOptionalString("ticket.description", description);
|
|
16464
|
+
if (!parsed.ok) return Result.error(parsed.error);
|
|
16465
|
+
if (parsed.value === void 0) {
|
|
16466
|
+
const { description: _drop, ...rest } = ticket;
|
|
16467
|
+
void _drop;
|
|
16468
|
+
return Result.ok(rest);
|
|
16469
|
+
}
|
|
16470
|
+
return Result.ok({ ...ticket, description: parsed.value });
|
|
16471
|
+
}
|
|
16472
|
+
var setTicketRequirements = (ticket, requirements) => {
|
|
16473
|
+
const parsed = parseRequiredString("ticket.requirements", requirements);
|
|
16474
|
+
if (!parsed.ok) return Result.error(parsed.error);
|
|
16475
|
+
return Result.ok({ ...ticket, requirements: parsed.value });
|
|
16476
|
+
};
|
|
16477
|
+
var approveTicketRequirements = (ticket, text) => {
|
|
16478
|
+
const guard2 = requireStatus(
|
|
16479
|
+
"ticket",
|
|
16480
|
+
ticket,
|
|
16481
|
+
["pending"],
|
|
16482
|
+
"approve-requirements",
|
|
16483
|
+
"Requirements have already been approved for this ticket."
|
|
16484
|
+
);
|
|
16485
|
+
if (!guard2.ok) return Result.error(guard2.error);
|
|
16486
|
+
return Result.ok({
|
|
16487
|
+
id: ticket.id,
|
|
16488
|
+
title: ticket.title,
|
|
16489
|
+
...ticket.description !== void 0 ? { description: ticket.description } : {},
|
|
16490
|
+
...ticket.link !== void 0 ? { link: ticket.link } : {},
|
|
16491
|
+
...ticket.externalRef !== void 0 ? { externalRef: ticket.externalRef } : {},
|
|
16492
|
+
status: "approved",
|
|
16493
|
+
requirements: text
|
|
16494
|
+
});
|
|
16495
|
+
};
|
|
16496
|
+
|
|
16094
16497
|
// src/domain/entity/sprint.ts
|
|
16095
16498
|
var sprintBaseFrom = (sprint) => ({
|
|
16096
16499
|
id: sprint.id,
|
|
@@ -16270,13 +16673,14 @@ var transitionSprintToDone = (sprint, now) => {
|
|
|
16270
16673
|
doneAt: now
|
|
16271
16674
|
});
|
|
16272
16675
|
};
|
|
16676
|
+
var DONE_IMMUTABLE_HINT = "Done sprints are immutable.";
|
|
16273
16677
|
var renameSprint = (sprint, newName) => {
|
|
16274
16678
|
const guard2 = requireStatus(
|
|
16275
16679
|
"sprint",
|
|
16276
16680
|
sprint,
|
|
16277
16681
|
["draft", "planned", "active", "review"],
|
|
16278
16682
|
"rename",
|
|
16279
|
-
|
|
16683
|
+
DONE_IMMUTABLE_HINT
|
|
16280
16684
|
);
|
|
16281
16685
|
if (!guard2.ok) return Result.error(guard2.error);
|
|
16282
16686
|
const name = parseRequiredString("sprint.name", newName);
|
|
@@ -16329,6 +16733,24 @@ var replaceTicket = (sprint, id, updated) => {
|
|
|
16329
16733
|
const draft = guard2.value;
|
|
16330
16734
|
return Result.ok({ ...draft, tickets: draft.tickets.map((t) => t.id === id ? updated : t) });
|
|
16331
16735
|
};
|
|
16736
|
+
var attachTicketLink = (sprint, ticketId, url) => {
|
|
16737
|
+
const guard2 = requireStatus(
|
|
16738
|
+
"sprint",
|
|
16739
|
+
sprint,
|
|
16740
|
+
["draft", "planned", "active", "review"],
|
|
16741
|
+
"attach-ticket-link",
|
|
16742
|
+
DONE_IMMUTABLE_HINT
|
|
16743
|
+
);
|
|
16744
|
+
if (!guard2.ok) return Result.error(guard2.error);
|
|
16745
|
+
const open = guard2.value;
|
|
16746
|
+
const ticket = open.tickets.find((t) => t.id === ticketId);
|
|
16747
|
+
if (ticket === void 0) {
|
|
16748
|
+
return Result.error(new NotFoundError({ entity: "ticket", id: String(ticketId) }));
|
|
16749
|
+
}
|
|
16750
|
+
const updated = ticket.status === "approved" ? setTicketLink(ticket, url) : setTicketLink(ticket, url);
|
|
16751
|
+
if (!updated.ok) return Result.error(updated.error);
|
|
16752
|
+
return Result.ok({ ...open, tickets: open.tickets.map((t) => t.id === ticketId ? updated.value : t) });
|
|
16753
|
+
};
|
|
16332
16754
|
var assertSprintStatus = (sprint, allowed, attemptedAction) => {
|
|
16333
16755
|
if (allowed.includes(sprint.status)) return Result.ok(sprint);
|
|
16334
16756
|
return Result.error(
|
|
@@ -16713,127 +17135,6 @@ var launchCreateSprint = (ctx) => {
|
|
|
16713
17135
|
// src/application/ui/shared/launch/refine.ts
|
|
16714
17136
|
import { join as join49 } from "path";
|
|
16715
17137
|
|
|
16716
|
-
// src/domain/value/external-ref.ts
|
|
16717
|
-
var toIssueRef = (segment) => {
|
|
16718
|
-
const num2 = Number(segment);
|
|
16719
|
-
return Number.isInteger(num2) && num2 > 0 ? `#${String(num2)}` : void 0;
|
|
16720
|
-
};
|
|
16721
|
-
var parseGithubIssueRef = (segments) => {
|
|
16722
|
-
if (segments.length < 4 || segments[2] !== "issues") return void 0;
|
|
16723
|
-
return toIssueRef(segments[3]);
|
|
16724
|
-
};
|
|
16725
|
-
var parseGitlabIssueRef = (segments) => {
|
|
16726
|
-
const dashIdx = segments.indexOf("-");
|
|
16727
|
-
if (dashIdx < 2 || segments[dashIdx + 1] !== "issues") return void 0;
|
|
16728
|
-
return toIssueRef(segments[dashIdx + 2]);
|
|
16729
|
-
};
|
|
16730
|
-
var parseExternalRefFromUrl = (url) => {
|
|
16731
|
-
let parsed;
|
|
16732
|
-
try {
|
|
16733
|
-
parsed = new URL(url);
|
|
16734
|
-
} catch {
|
|
16735
|
-
return void 0;
|
|
16736
|
-
}
|
|
16737
|
-
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return void 0;
|
|
16738
|
-
const segments = parsed.pathname.split("/").filter((s) => s.length > 0);
|
|
16739
|
-
return parsed.hostname.includes("github") ? parseGithubIssueRef(segments) : parseGitlabIssueRef(segments);
|
|
16740
|
-
};
|
|
16741
|
-
var normalizeRefs = (refs) => {
|
|
16742
|
-
if (refs === void 0 || refs.length === 0) return [];
|
|
16743
|
-
const seen = /* @__PURE__ */ new Set();
|
|
16744
|
-
const ordered = [];
|
|
16745
|
-
for (const r of refs) {
|
|
16746
|
-
const trimmed = r.trim();
|
|
16747
|
-
if (trimmed.length === 0) continue;
|
|
16748
|
-
if (seen.has(trimmed)) continue;
|
|
16749
|
-
seen.add(trimmed);
|
|
16750
|
-
ordered.push(trimmed);
|
|
16751
|
-
}
|
|
16752
|
-
return ordered;
|
|
16753
|
-
};
|
|
16754
|
-
|
|
16755
|
-
// src/domain/value/parsers/parse-optional-string.ts
|
|
16756
|
-
var parseOptionalString = (field, value) => {
|
|
16757
|
-
if (value === void 0) return Result.ok(void 0);
|
|
16758
|
-
const trimmed = value.trim();
|
|
16759
|
-
if (trimmed.length === 0) {
|
|
16760
|
-
return Result.error(
|
|
16761
|
-
new ValidationError({
|
|
16762
|
-
field,
|
|
16763
|
-
value,
|
|
16764
|
-
message: `${field} must be non-empty when provided`,
|
|
16765
|
-
hint: "omit the field instead of passing an empty string"
|
|
16766
|
-
})
|
|
16767
|
-
);
|
|
16768
|
-
}
|
|
16769
|
-
return Result.ok(trimmed);
|
|
16770
|
-
};
|
|
16771
|
-
|
|
16772
|
-
// src/domain/entity/ticket.ts
|
|
16773
|
-
var createTicket = (input) => {
|
|
16774
|
-
const title = parseRequiredString("ticket.title", input.title);
|
|
16775
|
-
if (!title.ok) return Result.error(title.error);
|
|
16776
|
-
const description = parseOptionalString("ticket.description", input.description);
|
|
16777
|
-
if (!description.ok) return Result.error(description.error);
|
|
16778
|
-
let link;
|
|
16779
|
-
if (input.link !== void 0) {
|
|
16780
|
-
const parsed = parseHttpUrl("ticket.link", input.link);
|
|
16781
|
-
if (!parsed.ok) return Result.error(parsed.error);
|
|
16782
|
-
link = parsed.value;
|
|
16783
|
-
}
|
|
16784
|
-
const trimmedRef = input.externalRef?.trim();
|
|
16785
|
-
const suppliedRef = trimmedRef !== void 0 && trimmedRef.length > 0 ? trimmedRef : void 0;
|
|
16786
|
-
const externalRef = suppliedRef ?? (link !== void 0 ? parseExternalRefFromUrl(link) : void 0);
|
|
16787
|
-
return Result.ok({
|
|
16788
|
-
id: input.id ?? TicketId.generate(),
|
|
16789
|
-
title: title.value,
|
|
16790
|
-
...description.value !== void 0 ? { description: description.value } : {},
|
|
16791
|
-
...link !== void 0 ? { link } : {},
|
|
16792
|
-
...externalRef !== void 0 ? { externalRef } : {},
|
|
16793
|
-
status: "pending",
|
|
16794
|
-
requirements: void 0
|
|
16795
|
-
});
|
|
16796
|
-
};
|
|
16797
|
-
function setTicketTitle(ticket, title) {
|
|
16798
|
-
const parsed = parseRequiredString("ticket.title", title);
|
|
16799
|
-
if (!parsed.ok) return Result.error(parsed.error);
|
|
16800
|
-
return Result.ok({ ...ticket, title: parsed.value });
|
|
16801
|
-
}
|
|
16802
|
-
function setTicketDescription(ticket, description) {
|
|
16803
|
-
const parsed = parseOptionalString("ticket.description", description);
|
|
16804
|
-
if (!parsed.ok) return Result.error(parsed.error);
|
|
16805
|
-
if (parsed.value === void 0) {
|
|
16806
|
-
const { description: _drop, ...rest } = ticket;
|
|
16807
|
-
void _drop;
|
|
16808
|
-
return Result.ok(rest);
|
|
16809
|
-
}
|
|
16810
|
-
return Result.ok({ ...ticket, description: parsed.value });
|
|
16811
|
-
}
|
|
16812
|
-
var setTicketRequirements = (ticket, requirements) => {
|
|
16813
|
-
const parsed = parseRequiredString("ticket.requirements", requirements);
|
|
16814
|
-
if (!parsed.ok) return Result.error(parsed.error);
|
|
16815
|
-
return Result.ok({ ...ticket, requirements: parsed.value });
|
|
16816
|
-
};
|
|
16817
|
-
var approveTicketRequirements = (ticket, text) => {
|
|
16818
|
-
const guard2 = requireStatus(
|
|
16819
|
-
"ticket",
|
|
16820
|
-
ticket,
|
|
16821
|
-
["pending"],
|
|
16822
|
-
"approve-requirements",
|
|
16823
|
-
"Requirements have already been approved for this ticket."
|
|
16824
|
-
);
|
|
16825
|
-
if (!guard2.ok) return Result.error(guard2.error);
|
|
16826
|
-
return Result.ok({
|
|
16827
|
-
id: ticket.id,
|
|
16828
|
-
title: ticket.title,
|
|
16829
|
-
...ticket.description !== void 0 ? { description: ticket.description } : {},
|
|
16830
|
-
...ticket.link !== void 0 ? { link: ticket.link } : {},
|
|
16831
|
-
...ticket.externalRef !== void 0 ? { externalRef: ticket.externalRef } : {},
|
|
16832
|
-
status: "approved",
|
|
16833
|
-
requirements: text
|
|
16834
|
-
});
|
|
16835
|
-
};
|
|
16836
|
-
|
|
16837
17138
|
// src/application/flows/_shared/sprint/load.ts
|
|
16838
17139
|
var loadSprintLeaf = (deps, name = "load-sprint") => leaf(name, {
|
|
16839
17140
|
useCase: {
|
|
@@ -17297,11 +17598,13 @@ var refineOutputContract = {
|
|
|
17297
17598
|
exampleSignals: refineExampleSignals
|
|
17298
17599
|
};
|
|
17299
17600
|
|
|
17300
|
-
// src/
|
|
17301
|
-
var
|
|
17601
|
+
// src/business/scm/refinement-comment.ts
|
|
17602
|
+
var REFINEMENT_MARKER = "<!-- ralphctl:refined-requirements -->";
|
|
17603
|
+
var refinementCommentBody = (requirements) => `${requirements}
|
|
17302
17604
|
|
|
17303
|
-
|
|
17304
|
-
|
|
17605
|
+
${REFINEMENT_MARKER}`;
|
|
17606
|
+
|
|
17607
|
+
// src/application/flows/refine/leaves/refine-ticket-interactive.ts
|
|
17305
17608
|
var remapRefineSignalsError = (error) => {
|
|
17306
17609
|
if (error instanceof InvalidStateError && error.message.includes("signals-missing")) {
|
|
17307
17610
|
return new InvalidStateError({
|
|
@@ -17335,8 +17638,20 @@ var warnDroppedSignals = async (deps, outputDir) => {
|
|
|
17335
17638
|
} catch {
|
|
17336
17639
|
}
|
|
17337
17640
|
};
|
|
17338
|
-
var
|
|
17641
|
+
var commentBannerId = (ticketId) => `refine-comment-${String(ticketId)}`;
|
|
17642
|
+
var publishCommentBanner = (deps, id, tier, message, cause) => {
|
|
17643
|
+
deps.eventBus.publish({
|
|
17644
|
+
type: "banner-show",
|
|
17645
|
+
id,
|
|
17646
|
+
tier,
|
|
17647
|
+
message,
|
|
17648
|
+
...cause !== void 0 ? { cause } : {},
|
|
17649
|
+
at: IsoTimestamp.now()
|
|
17650
|
+
});
|
|
17651
|
+
};
|
|
17652
|
+
var maybeCommentOnOrigin = async (deps, ticket) => {
|
|
17339
17653
|
const PUSH_LOGGER = "refine.push";
|
|
17654
|
+
const bannerId = commentBannerId(ticket.id);
|
|
17340
17655
|
if (deps.issuePusher === void 0) {
|
|
17341
17656
|
deps.logger.named(PUSH_LOGGER).warn("no IssuePusher wired \u2014 skipping issue comment");
|
|
17342
17657
|
return;
|
|
@@ -17345,15 +17660,26 @@ var maybeCommentOnOrigin = async (deps, ticket, body) => {
|
|
|
17345
17660
|
deps.logger.named(PUSH_LOGGER).warn("comment requested but ticket has no link \u2014 skipping");
|
|
17346
17661
|
return;
|
|
17347
17662
|
}
|
|
17348
|
-
const
|
|
17349
|
-
const fullBody = `${body}${REFINEMENT_COMMENT_SIGNATURE(deps.sprintId, now)}`;
|
|
17663
|
+
const body = refinementCommentBody(ticket.requirements);
|
|
17350
17664
|
const url = String(ticket.link);
|
|
17351
|
-
const
|
|
17665
|
+
const listed = await deps.issuePusher.listComments(url);
|
|
17666
|
+
if (!listed.ok) {
|
|
17667
|
+
deps.logger.named(PUSH_LOGGER).warn(`list comments failed (${url}): ${listed.error.message}`);
|
|
17668
|
+
publishCommentBanner(deps, bannerId, "error", "Could not post the refinement comment", listed.error.message);
|
|
17669
|
+
return;
|
|
17670
|
+
}
|
|
17671
|
+
if (listed.value.includes(body)) {
|
|
17672
|
+
deps.logger.named(PUSH_LOGGER).info(`tracker already up to date for ${url}`);
|
|
17673
|
+
publishCommentBanner(deps, bannerId, "info", "Tracker is already up to date");
|
|
17674
|
+
return;
|
|
17675
|
+
}
|
|
17676
|
+
const result = await deps.issuePusher.comment(url, { body });
|
|
17352
17677
|
if (!result.ok) {
|
|
17353
17678
|
deps.logger.named(PUSH_LOGGER).warn(`issue comment failed (${url}): ${result.error.message}`);
|
|
17354
|
-
|
|
17355
|
-
|
|
17679
|
+
publishCommentBanner(deps, bannerId, "error", "Could not post the refinement comment", result.error.message);
|
|
17680
|
+
return;
|
|
17356
17681
|
}
|
|
17682
|
+
deps.logger.named(PUSH_LOGGER).info(`posted comment on issue ${url}`);
|
|
17357
17683
|
};
|
|
17358
17684
|
var runInteractiveSession = async (deps, input, signal) => {
|
|
17359
17685
|
const session = await deps.runInTerminal(
|
|
@@ -17406,10 +17732,9 @@ var applyResult = async (deps, input, refinedSignal) => {
|
|
|
17406
17732
|
if (!useCaseResult.ok) return Result.error(useCaseResult.error);
|
|
17407
17733
|
const out = useCaseResult.value;
|
|
17408
17734
|
if (!out.accepted) return Result.ok(out);
|
|
17409
|
-
|
|
17410
|
-
if (!shouldComment) return Result.ok(out);
|
|
17735
|
+
if (out.alsoUpdateOrigin !== true) return Result.ok(out);
|
|
17411
17736
|
const approved = out.ticket;
|
|
17412
|
-
await maybeCommentOnOrigin(deps, approved
|
|
17737
|
+
await maybeCommentOnOrigin(deps, approved);
|
|
17413
17738
|
return Result.ok(out);
|
|
17414
17739
|
};
|
|
17415
17740
|
var refineTicketInteractiveLeaf = (deps, ticket) => leaf(`refine-ticket-${String(ticket.id)}`, {
|
|
@@ -18015,9 +18340,7 @@ var createRefineFlow = (deps, opts) => {
|
|
|
18015
18340
|
writeFile: deps.writeFile,
|
|
18016
18341
|
eventBus: deps.eventBus,
|
|
18017
18342
|
model: opts.model,
|
|
18018
|
-
sprintId: String(opts.sprintId),
|
|
18019
18343
|
...opts.effort !== void 0 ? { effort: opts.effort } : {},
|
|
18020
|
-
...deps.postRefinementComment !== void 0 ? { postRefinementComment: deps.postRefinementComment } : {},
|
|
18021
18344
|
...deps.reviewBeforeApprove !== void 0 ? { reviewBeforeApprove: deps.reviewBeforeApprove } : {},
|
|
18022
18345
|
...deps.issuePusher !== void 0 ? { issuePusher: deps.issuePusher } : {}
|
|
18023
18346
|
},
|
|
@@ -18102,7 +18425,7 @@ var checkCli = async (flowId, settings, options = {}) => {
|
|
|
18102
18425
|
};
|
|
18103
18426
|
|
|
18104
18427
|
// src/application/ui/shared/launch/refine.ts
|
|
18105
|
-
var buildRefineOptions = (hasLink
|
|
18428
|
+
var buildRefineOptions = (hasLink) => {
|
|
18106
18429
|
const approveOption = {
|
|
18107
18430
|
label: "Approve",
|
|
18108
18431
|
value: "approve",
|
|
@@ -18113,11 +18436,10 @@ var buildRefineOptions = (hasLink, postRefinementComment) => {
|
|
|
18113
18436
|
value: "post_comment",
|
|
18114
18437
|
description: "Save locally AND post the body as a comment on the linked issue."
|
|
18115
18438
|
};
|
|
18116
|
-
const leadOptions = hasLink && postRefinementComment ? [commentOption, approveOption] : [approveOption];
|
|
18117
18439
|
return [
|
|
18118
|
-
|
|
18440
|
+
approveOption,
|
|
18119
18441
|
{ label: "Edit", value: "edit", description: "Open the body in an editor; come back here to decide." },
|
|
18120
|
-
...hasLink
|
|
18442
|
+
...hasLink ? [commentOption] : [],
|
|
18121
18443
|
{ label: "Reject", value: "reject", description: "Leave the ticket pending \u2014 no changes." }
|
|
18122
18444
|
];
|
|
18123
18445
|
};
|
|
@@ -18137,8 +18459,8 @@ var applyRefineDecision = async (interactive, ticket, decision, body) => {
|
|
|
18137
18459
|
}
|
|
18138
18460
|
}
|
|
18139
18461
|
};
|
|
18140
|
-
var buildReviewBeforeApprove = (interactive
|
|
18141
|
-
const options = buildRefineOptions(ticket.link !== void 0
|
|
18462
|
+
var buildReviewBeforeApprove = (interactive) => async (proposed, ticket) => {
|
|
18463
|
+
const options = buildRefineOptions(ticket.link !== void 0);
|
|
18142
18464
|
let body = proposed;
|
|
18143
18465
|
while (true) {
|
|
18144
18466
|
const message = `Approve refined requirements for "${ticket.title}"?
|
|
@@ -18161,8 +18483,7 @@ var launchRefine = async (ctx) => {
|
|
|
18161
18483
|
join49(sprintDir(deps.storage.dataRoot, snapshot.sprint.id, snapshot.sprint.slug), "refinement")
|
|
18162
18484
|
);
|
|
18163
18485
|
if (!refinementRoot.ok) return { ok: false, reason: refinementRoot.error.message };
|
|
18164
|
-
const
|
|
18165
|
-
const reviewBeforeApprove = buildReviewBeforeApprove(deps.interactive, postRefinementComment);
|
|
18486
|
+
const reviewBeforeApprove = buildReviewBeforeApprove(deps.interactive);
|
|
18166
18487
|
const element = createRefineFlow(
|
|
18167
18488
|
{
|
|
18168
18489
|
sprintRepo: deps.app.sprintRepo,
|
|
@@ -18176,7 +18497,6 @@ var launchRefine = async (ctx) => {
|
|
|
18176
18497
|
skillsAdapter,
|
|
18177
18498
|
skillSource,
|
|
18178
18499
|
reviewBeforeApprove,
|
|
18179
|
-
postRefinementComment,
|
|
18180
18500
|
...deps.app.issueFetcher !== void 0 ? { issueFetcher: deps.app.issueFetcher } : {},
|
|
18181
18501
|
...deps.app.issuePusher !== void 0 ? { issuePusher: deps.app.issuePusher } : {}
|
|
18182
18502
|
},
|
|
@@ -23651,7 +23971,7 @@ var decideEscalation = (props) => {
|
|
|
23651
23971
|
};
|
|
23652
23972
|
if (!props.flagOn) return { kind: "flag-off" };
|
|
23653
23973
|
if (budgetExhausted) return budgetExhaustedDecision;
|
|
23654
|
-
const merged = mergeEscalationMap(props.userMap);
|
|
23974
|
+
const merged = mergeEscalationMap(props.userMap, props.generatorProvider);
|
|
23655
23975
|
const next = merged[props.generatorModel];
|
|
23656
23976
|
if (hasStrongerModelRung(merged, props.generatorModel, next)) {
|
|
23657
23977
|
return { kind: "escalate", from: props.generatorModel, to: next, ...computeEvaluatorEffortCarry(props) };
|
|
@@ -23671,6 +23991,11 @@ var decideEscalation = (props) => {
|
|
|
23671
23991
|
}
|
|
23672
23992
|
return { kind: "nudge", currentModel: props.generatorModel };
|
|
23673
23993
|
};
|
|
23994
|
+
var effectiveGeneratorModel = (task, configuredModel, provider) => {
|
|
23995
|
+
const override = task.escalatedToModel;
|
|
23996
|
+
if (override === void 0) return configuredModel;
|
|
23997
|
+
return provider === void 0 ? override : remapRetiredModel(provider, override);
|
|
23998
|
+
};
|
|
23674
23999
|
var escalationBannerId = (taskId) => `model-escalation-${taskId}`;
|
|
23675
24000
|
var computeActionEntropy = (actionCounts) => {
|
|
23676
24001
|
const K = actionCounts.size;
|
|
@@ -24162,8 +24487,9 @@ var makeGeneratorCallImplement = (deps, taskId, args) => async (task) => {
|
|
|
24162
24487
|
// Per-task generator-model escalation: when the task carries an `escalatedToModel`
|
|
24163
24488
|
// (stamped by the prior plateau's escalation policy), spawn the generator on that
|
|
24164
24489
|
// upgraded model instead of the configured row. Evaluator model is intentionally
|
|
24165
|
-
// unaffected — escalation only touches the generator role.
|
|
24166
|
-
|
|
24490
|
+
// unaffected — escalation only touches the generator role. A persisted override naming a
|
|
24491
|
+
// since-retired slug is remapped to its live successor rather than spawned as-is.
|
|
24492
|
+
model: effectiveGeneratorModel(task, deps.model, deps.providerId),
|
|
24167
24493
|
// Per-task generator-EFFORT escalation: the same-model effort rung stamps `escalatedToEffort`
|
|
24168
24494
|
// (default → high) when the generator topped out on the model ladder but still had effort
|
|
24169
24495
|
// headroom. Prefer it over the configured `deps.effort` at spawn — mirrors the model override
|
|
@@ -24508,7 +24834,7 @@ var resolveImplementMetaInput = (ctx, taskId, role, providerId, model, effort) =
|
|
|
24508
24834
|
const outputDir = AbsolutePath.parse(dirname20(signalsPath));
|
|
24509
24835
|
if (!outputDir.ok) throw outputDir.error;
|
|
24510
24836
|
const task = ctx.currentTask;
|
|
24511
|
-
const effectiveModel = role === "generator"
|
|
24837
|
+
const effectiveModel = role === "generator" ? effectiveGeneratorModel(task, model, providerId) : model;
|
|
24512
24838
|
return {
|
|
24513
24839
|
outputDir: outputDir.value,
|
|
24514
24840
|
flow: `implement-${role}`,
|
|
@@ -24540,6 +24866,7 @@ var stampImplementEvaluatorSessionMetaLeaf = (deps, opts, taskId) => stampSessio
|
|
|
24540
24866
|
var withRoleSpawn = (shared, provider, role) => ({
|
|
24541
24867
|
...shared,
|
|
24542
24868
|
provider,
|
|
24869
|
+
providerId: role.providerId,
|
|
24543
24870
|
model: role.model,
|
|
24544
24871
|
...role.effort !== void 0 ? { effort: role.effort } : {},
|
|
24545
24872
|
...role.agentDefinitionSection !== void 0 ? { agentDefinition: role.agentDefinitionSection } : {},
|
|
@@ -26145,7 +26472,11 @@ var finalizeGenEvalLeaf = (deps, taskId) => leaf(`finalize-gen-eval-${String(tas
|
|
|
26145
26472
|
message: `finalize-gen-eval-${String(taskId)}: expected in_progress task`
|
|
26146
26473
|
});
|
|
26147
26474
|
}
|
|
26148
|
-
const generatorModel =
|
|
26475
|
+
const generatorModel = effectiveGeneratorModel(
|
|
26476
|
+
ctx.currentTask,
|
|
26477
|
+
deps.configuredGeneratorModel,
|
|
26478
|
+
deps.configuredGeneratorProvider
|
|
26479
|
+
);
|
|
26149
26480
|
const generatorEffort = ctx.currentTask.escalatedToEffort ?? deps.configuredGeneratorEffort;
|
|
26150
26481
|
const evaluatorEffort = ctx.currentTask.escalatedToEvaluatorEffort ?? deps.configuredEvaluatorEffort;
|
|
26151
26482
|
return {
|
|
@@ -30109,9 +30440,9 @@ var resolveImplementAgentBindings = async (deps, implementPair) => {
|
|
|
30109
30440
|
};
|
|
30110
30441
|
|
|
30111
30442
|
// src/business/settings/resolve-agent-override.ts
|
|
30112
|
-
var resolveAgentOverride = (row, globalEffort, binding) => ({
|
|
30443
|
+
var resolveAgentOverride = (row, globalEffort, binding, flow) => ({
|
|
30113
30444
|
model: binding?.model ?? row.model,
|
|
30114
|
-
effort: binding?.effort !== void 0 ? clampEffortToProvider(binding.effort, row.provider) : resolveEffortForRow(row, globalEffort)
|
|
30445
|
+
effort: binding?.effort !== void 0 ? clampEffortToProvider(binding.effort, row.provider) : resolveEffortForRow(row, globalEffort, flow)
|
|
30115
30446
|
});
|
|
30116
30447
|
|
|
30117
30448
|
// src/application/ui/shared/launch/implement-bags.ts
|
|
@@ -30143,12 +30474,14 @@ var buildImplementProviders = (implementPair, effectiveSettings, deps, agentDefi
|
|
|
30143
30474
|
const generatorResolved = resolveAgentOverride(
|
|
30144
30475
|
implementPair.generator,
|
|
30145
30476
|
effectiveSettings.ai.effort,
|
|
30146
|
-
agentDefinitions.generator
|
|
30477
|
+
agentDefinitions.generator,
|
|
30478
|
+
"implement"
|
|
30147
30479
|
);
|
|
30148
30480
|
const evaluatorResolved = resolveAgentOverride(
|
|
30149
30481
|
implementPair.evaluator,
|
|
30150
30482
|
effectiveSettings.ai.effort,
|
|
30151
|
-
agentDefinitions.evaluator
|
|
30483
|
+
agentDefinitions.evaluator,
|
|
30484
|
+
"implement"
|
|
30152
30485
|
);
|
|
30153
30486
|
return {
|
|
30154
30487
|
generatorProvider,
|
|
@@ -30909,6 +31242,7 @@ var callApplyFeedbackPhase = (deps, opts, paths, promptRef, signal) => async ()
|
|
|
30909
31242
|
cwd: paths.outputDir,
|
|
30910
31243
|
additionalRoots: opts.additionalRoots,
|
|
30911
31244
|
model: deps.model,
|
|
31245
|
+
...deps.effort !== void 0 ? { effort: deps.effort } : {},
|
|
30912
31246
|
permissions: FULL_AUTO,
|
|
30913
31247
|
signalsFile: paths.signalsFile,
|
|
30914
31248
|
outputDir: paths.outputDir,
|
|
@@ -31500,17 +31834,17 @@ var distillWriteLeaf = (deps, tool) => leaf(`distill-write-${tool}`, {
|
|
|
31500
31834
|
// src/application/flows/_shared/memory/distill-learnings.ts
|
|
31501
31835
|
var pickModelEffortForProvider = (ai, provider) => {
|
|
31502
31836
|
const rows = [
|
|
31503
|
-
ai.refine,
|
|
31504
|
-
ai.plan,
|
|
31505
|
-
ai.implement.generator,
|
|
31506
|
-
ai.implement.evaluator,
|
|
31507
|
-
ai.readiness,
|
|
31508
|
-
ai.ideate,
|
|
31509
|
-
ai.createPr
|
|
31837
|
+
["refine", ai.refine],
|
|
31838
|
+
["plan", ai.plan],
|
|
31839
|
+
["implement", ai.implement.generator],
|
|
31840
|
+
["implement", ai.implement.evaluator],
|
|
31841
|
+
["readiness", ai.readiness],
|
|
31842
|
+
["ideate", ai.ideate],
|
|
31843
|
+
["createPr", ai.createPr]
|
|
31510
31844
|
];
|
|
31511
|
-
for (const row of rows) {
|
|
31845
|
+
for (const [flow, row] of rows) {
|
|
31512
31846
|
if (row.provider === provider) {
|
|
31513
|
-
const effort = row
|
|
31847
|
+
const effort = resolveEffortForRow(row, ai.effort, flow);
|
|
31514
31848
|
return effort !== void 0 ? { model: row.model, effort } : { model: row.model };
|
|
31515
31849
|
}
|
|
31516
31850
|
}
|
|
@@ -31656,7 +31990,8 @@ var createReviewFlow = (deps, opts) => {
|
|
|
31656
31990
|
gitRunner: deps.gitRunner,
|
|
31657
31991
|
shellScriptRunner: deps.shellScriptRunner,
|
|
31658
31992
|
appendFile: deps.appendFile,
|
|
31659
|
-
model: deps.model
|
|
31993
|
+
model: deps.model,
|
|
31994
|
+
...deps.effort !== void 0 ? { effort: deps.effort } : {}
|
|
31660
31995
|
},
|
|
31661
31996
|
{
|
|
31662
31997
|
reviewRoot: opts.reviewRoot,
|
|
@@ -31772,7 +32107,7 @@ var sprintAffectedRepositories = (repositories, taskRepositoryIds) => {
|
|
|
31772
32107
|
};
|
|
31773
32108
|
var renderRepositoriesBlock = (affected) => affected.map((r) => `- \`${String(r.path)}\` (${r.name})`).join("\n");
|
|
31774
32109
|
var launchReview = async (ctx) => {
|
|
31775
|
-
const { deps, snapshot, settings, provider, bridge, sessionId: sessionId3 } = ctx;
|
|
32110
|
+
const { deps, snapshot, settings, provider, bridge, sessionId: sessionId3, effort } = ctx;
|
|
31776
32111
|
if (!snapshot.sprint) return { ok: false, reason: "No sprint selected." };
|
|
31777
32112
|
if (!snapshot.project) return { ok: false, reason: "No project loaded for the selected sprint." };
|
|
31778
32113
|
if (snapshot.project.repositories.length === 0) {
|
|
@@ -31817,11 +32152,13 @@ var launchReview = async (ctx) => {
|
|
|
31817
32152
|
fileLocker: deps.app.fileLocker,
|
|
31818
32153
|
locksRoot: deps.storage.locksRoot,
|
|
31819
32154
|
appendFile: deps.app.appendFile,
|
|
31820
|
-
// Review uses the implement generator model — same code-mutation profile, same
|
|
32155
|
+
// Review uses the implement generator model + effort — same code-mutation profile, same
|
|
31821
32156
|
// accuracy expectations. No per-flow `review` row in settings today. Override flows in
|
|
31822
32157
|
// through ctx.settings (launcher applied it to ai.implement.generator when the picker
|
|
31823
|
-
// emitted a non-empty override), so per-field fallback is automatic.
|
|
32158
|
+
// emitted a non-empty override), so per-field fallback is automatic; `ctx.effort` is the
|
|
32159
|
+
// launcher's `resolveEffort('implement', settings)` over those same settings.
|
|
31824
32160
|
model: settings.ai.implement.generator.model,
|
|
32161
|
+
...effort !== void 0 ? { effort } : {},
|
|
31825
32162
|
...distill !== void 0 ? { distill } : {}
|
|
31826
32163
|
},
|
|
31827
32164
|
{
|
|
@@ -33156,13 +33493,6 @@ var pickRowForProvider = (ai, provider) => {
|
|
|
33156
33493
|
}
|
|
33157
33494
|
throw new Error(`pickRowForProvider: provider ${provider} not referenced in ai settings`);
|
|
33158
33495
|
};
|
|
33159
|
-
var resolveEffortForRow2 = (ai, flow) => {
|
|
33160
|
-
const row = primaryFlowRow(ai, flow);
|
|
33161
|
-
if (row.effort !== void 0) return row.effort;
|
|
33162
|
-
const globalEffort = ai.effort;
|
|
33163
|
-
if (globalEffort === void 0) return void 0;
|
|
33164
|
-
return clampEffortToProvider(globalEffort, row.provider);
|
|
33165
|
-
};
|
|
33166
33496
|
var PROVIDER_INFRASTRUCTURE_ERROR_CODES = /* @__PURE__ */ new Set([ErrorCode.Probe, ErrorCode.RateLimit]);
|
|
33167
33497
|
var wrapProviderContinue = (eventBus, provider, inner) => tolerateErrors(
|
|
33168
33498
|
{
|
|
@@ -33181,7 +33511,7 @@ var wrapProviderContinue = (eventBus, provider, inner) => tolerateErrors(
|
|
|
33181
33511
|
var buildPerToolSubchain = (deps, opts, provider, tool) => {
|
|
33182
33512
|
const rowFlow = pickRowForProvider(opts.ai, provider);
|
|
33183
33513
|
const row = primaryFlowRow(opts.ai, rowFlow);
|
|
33184
|
-
const effort =
|
|
33514
|
+
const effort = resolveEffortForRow(row, opts.ai.effort, "readiness");
|
|
33185
33515
|
const provideAi = deps.providerFor(provider);
|
|
33186
33516
|
const skillsAdapter = deps.skillsAdapterFor(provider);
|
|
33187
33517
|
return sequential(`tool-${tool}`, [
|
|
@@ -37938,7 +38268,7 @@ var SprintsView = () => {
|
|
|
37938
38268
|
import "react";
|
|
37939
38269
|
|
|
37940
38270
|
// src/application/ui/tui/views/sprint-detail-internals/detail-body.tsx
|
|
37941
|
-
import { useEffect as useEffect26, useMemo as useMemo17, useState as useState31 } from "react";
|
|
38271
|
+
import { useEffect as useEffect26, useMemo as useMemo17, useRef as useRef14, useState as useState31 } from "react";
|
|
37942
38272
|
|
|
37943
38273
|
// src/business/task/evaluation-artifact.ts
|
|
37944
38274
|
import { isAbsolute as isAbsolute4, normalize } from "path";
|
|
@@ -38020,6 +38350,18 @@ var SHORTCUT_ROWS = [
|
|
|
38020
38350
|
if (focused?.kind === "ticket") args.beginRemove(focused.ticket);
|
|
38021
38351
|
}
|
|
38022
38352
|
},
|
|
38353
|
+
{
|
|
38354
|
+
// `p` is unused globally (`P` is pick-project) and unused elsewhere in this view. Fires
|
|
38355
|
+
// on any focused ticket row of an open sprint — draft or not — so the comment path is
|
|
38356
|
+
// reachable after the sprint leaves draft; inert once `done` (done sprints are immutable).
|
|
38357
|
+
// No prompt; the flow writes or surfaces the tracker error.
|
|
38358
|
+
key: (input) => input === "p",
|
|
38359
|
+
guard: (args, sprint) => sprint.status !== "done" && focusedItem(args)?.kind === "ticket",
|
|
38360
|
+
action: (args) => {
|
|
38361
|
+
const focused = focusedItem(args);
|
|
38362
|
+
if (focused?.kind === "ticket") args.handlePublish(focused.ticket);
|
|
38363
|
+
}
|
|
38364
|
+
},
|
|
38023
38365
|
{
|
|
38024
38366
|
key: (input) => input === "u",
|
|
38025
38367
|
guard: (args) => args.focusedStuckTask !== void 0,
|
|
@@ -38160,6 +38502,107 @@ var useSprintBundle = (args) => {
|
|
|
38160
38502
|
return { state, project, reload };
|
|
38161
38503
|
};
|
|
38162
38504
|
|
|
38505
|
+
// src/business/ticket/publish-to-tracker.ts
|
|
38506
|
+
var REFINEMENT_MARKER2 = "<!-- ralphctl:refined-requirements -->";
|
|
38507
|
+
var refinementBody = (requirements) => `${requirements}
|
|
38508
|
+
|
|
38509
|
+
${REFINEMENT_MARKER2}`;
|
|
38510
|
+
var publishTicketToTracker = async (props) => {
|
|
38511
|
+
const open = requireStatus(
|
|
38512
|
+
"sprint",
|
|
38513
|
+
props.sprint,
|
|
38514
|
+
["draft", "planned", "active", "review"],
|
|
38515
|
+
"publish-ticket",
|
|
38516
|
+
"Done sprints are immutable."
|
|
38517
|
+
);
|
|
38518
|
+
if (!open.ok) return Result.error(open.error);
|
|
38519
|
+
const ticket = props.sprint.tickets.find((t) => t.id === props.ticketId);
|
|
38520
|
+
if (ticket === void 0) {
|
|
38521
|
+
return Result.error(new NotFoundError({ entity: "ticket", id: String(props.ticketId) }));
|
|
38522
|
+
}
|
|
38523
|
+
if (ticket.link !== void 0) {
|
|
38524
|
+
return publishExistingLink(props, ticket.link, ticket.status === "approved" ? ticket.requirements : void 0);
|
|
38525
|
+
}
|
|
38526
|
+
const title = parseRequiredString("ticket.title", ticket.title);
|
|
38527
|
+
if (!title.ok) return Result.error(title.error);
|
|
38528
|
+
const origin = await props.issuePusher.resolveOrigin(props.cwd);
|
|
38529
|
+
if (!origin.ok) return Result.error(origin.error);
|
|
38530
|
+
if (origin.value === null) {
|
|
38531
|
+
return Result.error(
|
|
38532
|
+
new StorageError({
|
|
38533
|
+
subCode: "io",
|
|
38534
|
+
message: `no GitHub or GitLab origin at ${String(props.cwd)}`
|
|
38535
|
+
})
|
|
38536
|
+
);
|
|
38537
|
+
}
|
|
38538
|
+
const created = await props.issuePusher.create({
|
|
38539
|
+
cwd: props.cwd,
|
|
38540
|
+
title: title.value,
|
|
38541
|
+
body: ticket.description ?? ""
|
|
38542
|
+
});
|
|
38543
|
+
if (!created.ok) return Result.error(created.error);
|
|
38544
|
+
const attached = attachTicketLink(props.sprint, props.ticketId, created.value.url);
|
|
38545
|
+
if (!attached.ok) return Result.error(attached.error);
|
|
38546
|
+
return Result.ok({ sprint: attached.value, outcome: "created" });
|
|
38547
|
+
};
|
|
38548
|
+
var publishExistingLink = async (props, link, requirements) => {
|
|
38549
|
+
if (requirements === void 0) {
|
|
38550
|
+
return Result.ok({ sprint: props.sprint, outcome: "nothing-to-post" });
|
|
38551
|
+
}
|
|
38552
|
+
const body = refinementBody(requirements);
|
|
38553
|
+
const listed = await props.issuePusher.listComments(link);
|
|
38554
|
+
if (!listed.ok) return Result.error(listed.error);
|
|
38555
|
+
if (listed.value.includes(body)) {
|
|
38556
|
+
return Result.ok({ sprint: props.sprint, outcome: "already-up-to-date" });
|
|
38557
|
+
}
|
|
38558
|
+
const posted = await props.issuePusher.comment(link, { body });
|
|
38559
|
+
if (!posted.ok) return Result.error(posted.error);
|
|
38560
|
+
return Result.ok({ sprint: props.sprint, outcome: "commented" });
|
|
38561
|
+
};
|
|
38562
|
+
var publishSaveFailedError = (output, ticketId, saveError) => {
|
|
38563
|
+
if (output.outcome !== "created") return saveError;
|
|
38564
|
+
const url = output.sprint.tickets.find((t) => t.id === ticketId)?.link;
|
|
38565
|
+
if (url === void 0) return saveError;
|
|
38566
|
+
return new StorageError({
|
|
38567
|
+
subCode: "io",
|
|
38568
|
+
message: `Issue created at ${url} but saving the link failed \u2014 set the ticket link to this URL manually; re-publishing would open a duplicate.`,
|
|
38569
|
+
cause: saveError
|
|
38570
|
+
});
|
|
38571
|
+
};
|
|
38572
|
+
|
|
38573
|
+
// src/application/flows/publish-ticket/flow.ts
|
|
38574
|
+
var createTicketPublishFlow = (deps) => leaf("publish-ticket", {
|
|
38575
|
+
useCase: {
|
|
38576
|
+
async execute(input) {
|
|
38577
|
+
const sprint = await deps.sprintRepo.findById(input.sprintId);
|
|
38578
|
+
if (!sprint.ok) return Result.error(sprint.error);
|
|
38579
|
+
const project = await deps.projectRepo.findById(sprint.value.projectId);
|
|
38580
|
+
if (!project.ok) return Result.error(project.error);
|
|
38581
|
+
const originCwd = project.value.repositories[0]?.path;
|
|
38582
|
+
if (originCwd === void 0) {
|
|
38583
|
+
return Result.error(
|
|
38584
|
+
new StorageError({
|
|
38585
|
+
subCode: "io",
|
|
38586
|
+
message: "Project has no repositories \u2014 add one first."
|
|
38587
|
+
})
|
|
38588
|
+
);
|
|
38589
|
+
}
|
|
38590
|
+
const published = await publishTicketToTracker({
|
|
38591
|
+
sprint: sprint.value,
|
|
38592
|
+
ticketId: input.ticketId,
|
|
38593
|
+
cwd: originCwd,
|
|
38594
|
+
issuePusher: deps.issuePusher
|
|
38595
|
+
});
|
|
38596
|
+
if (!published.ok) return Result.error(published.error);
|
|
38597
|
+
const saved = await deps.sprintRepo.save(published.value.sprint);
|
|
38598
|
+
if (!saved.ok) return Result.error(publishSaveFailedError(published.value, input.ticketId, saved.error));
|
|
38599
|
+
return Result.ok(published.value);
|
|
38600
|
+
}
|
|
38601
|
+
},
|
|
38602
|
+
input: (c) => c.input,
|
|
38603
|
+
output: (c, o) => ({ ...c, output: o })
|
|
38604
|
+
});
|
|
38605
|
+
|
|
38163
38606
|
// src/application/flows/remove-ticket/flow.ts
|
|
38164
38607
|
var createTicketRemoveFlow = (deps) => leaf("remove-ticket", {
|
|
38165
38608
|
useCase: {
|
|
@@ -38303,8 +38746,37 @@ var runRemoveTicket = async (args) => {
|
|
|
38303
38746
|
setFeedback(`${glyphs.check} removed "${target.title}"`);
|
|
38304
38747
|
reload();
|
|
38305
38748
|
};
|
|
38749
|
+
var runPublishTicket = async (args) => {
|
|
38750
|
+
const { target, sprintId, sprintRepo, projectRepo, issuePusher, mountedRef, setFeedback, reload } = args;
|
|
38751
|
+
if (issuePusher === void 0) {
|
|
38752
|
+
if (mountedRef.current) setFeedback(`${glyphs.cross} issue tracker is unavailable`);
|
|
38753
|
+
return;
|
|
38754
|
+
}
|
|
38755
|
+
const flow = createTicketPublishFlow({ sprintRepo, projectRepo, issuePusher });
|
|
38756
|
+
const r = await flow.execute({ input: { sprintId, ticketId: target.id } });
|
|
38757
|
+
if (!r.ok) {
|
|
38758
|
+
if (mountedRef.current) setFeedback(`${glyphs.cross} ${r.error.error.message}`);
|
|
38759
|
+
return;
|
|
38760
|
+
}
|
|
38761
|
+
if (!mountedRef.current) return;
|
|
38762
|
+
const out = r.value.ctx.output;
|
|
38763
|
+
setFeedback(`${glyphs.check} ${out.outcome} "${target.title}"`);
|
|
38764
|
+
reload();
|
|
38765
|
+
};
|
|
38306
38766
|
var buildSprintDetailHandlers = (args) => {
|
|
38307
|
-
const {
|
|
38767
|
+
const {
|
|
38768
|
+
sprint,
|
|
38769
|
+
deps,
|
|
38770
|
+
focus,
|
|
38771
|
+
queue,
|
|
38772
|
+
edit,
|
|
38773
|
+
reload,
|
|
38774
|
+
mountedRef,
|
|
38775
|
+
setFeedback,
|
|
38776
|
+
unblockTask: unblockTask2,
|
|
38777
|
+
setConfirmRemove,
|
|
38778
|
+
publishInFlightRef
|
|
38779
|
+
} = args;
|
|
38308
38780
|
const handleEdit = () => {
|
|
38309
38781
|
if (sprint === void 0) return;
|
|
38310
38782
|
runEdit({
|
|
@@ -38322,6 +38794,24 @@ var buildSprintDetailHandlers = (args) => {
|
|
|
38322
38794
|
if (sprint === void 0) return;
|
|
38323
38795
|
await runUnblock({ target, sprintId: sprint.id, unblockTask: unblockTask2, mountedRef, setFeedback, reload });
|
|
38324
38796
|
};
|
|
38797
|
+
const handlePublish = async (target) => {
|
|
38798
|
+
if (sprint === void 0 || publishInFlightRef.current) return;
|
|
38799
|
+
publishInFlightRef.current = true;
|
|
38800
|
+
try {
|
|
38801
|
+
await runPublishTicket({
|
|
38802
|
+
target,
|
|
38803
|
+
sprintId: sprint.id,
|
|
38804
|
+
sprintRepo: deps.sprintRepo,
|
|
38805
|
+
projectRepo: deps.projectRepo,
|
|
38806
|
+
issuePusher: deps.issuePusher,
|
|
38807
|
+
mountedRef,
|
|
38808
|
+
setFeedback,
|
|
38809
|
+
reload
|
|
38810
|
+
});
|
|
38811
|
+
} finally {
|
|
38812
|
+
publishInFlightRef.current = false;
|
|
38813
|
+
}
|
|
38814
|
+
};
|
|
38325
38815
|
const handleRemoveConfirmed2 = async (target, confirmed) => {
|
|
38326
38816
|
setConfirmRemove(void 0);
|
|
38327
38817
|
if (!confirmed || sprint === void 0) return;
|
|
@@ -38334,7 +38824,7 @@ var buildSprintDetailHandlers = (args) => {
|
|
|
38334
38824
|
reload
|
|
38335
38825
|
});
|
|
38336
38826
|
};
|
|
38337
|
-
return { handleEdit, handleUnblock: handleUnblock2, handleRemoveConfirmed: handleRemoveConfirmed2 };
|
|
38827
|
+
return { handleEdit, handleUnblock: handleUnblock2, handlePublish, handleRemoveConfirmed: handleRemoveConfirmed2 };
|
|
38338
38828
|
};
|
|
38339
38829
|
|
|
38340
38830
|
// src/application/ui/tui/views/sprint-detail-internals/detail-shortcuts-actions.ts
|
|
@@ -38346,6 +38836,7 @@ var buildShortcutsActions = (args) => {
|
|
|
38346
38836
|
setConfirmRemove,
|
|
38347
38837
|
setFeedback,
|
|
38348
38838
|
onUnblock,
|
|
38839
|
+
onPublish,
|
|
38349
38840
|
sprintId,
|
|
38350
38841
|
openEvaluationOverlay,
|
|
38351
38842
|
reload
|
|
@@ -38367,6 +38858,9 @@ var buildShortcutsActions = (args) => {
|
|
|
38367
38858
|
handleUnblock: (task) => {
|
|
38368
38859
|
void onUnblock(task);
|
|
38369
38860
|
},
|
|
38861
|
+
handlePublish: (ticket) => {
|
|
38862
|
+
void onPublish(ticket);
|
|
38863
|
+
},
|
|
38370
38864
|
// The full target is assembled here (not inside the overlay) so its degrade arms never need a
|
|
38371
38865
|
// second repository read — see `runtime/evaluation-target.ts`.
|
|
38372
38866
|
openEvaluation: (task) => {
|
|
@@ -38397,11 +38891,12 @@ var deriveFocusedSelection = (focusList, cursorIdx, ticketsEditable, sprintStatu
|
|
|
38397
38891
|
const focusedNow = focusList[Math.min(cursorIdx, Math.max(0, focusList.length - 1))];
|
|
38398
38892
|
const focusedNowTask = focusedNow?.kind === "task" ? focusedNow.task : void 0;
|
|
38399
38893
|
const focusedStuckTask = focusedNowTask !== void 0 && isStuckTaskStatus(focusedNowTask.status, sprintStatus) ? focusedNowTask : void 0;
|
|
38400
|
-
const
|
|
38894
|
+
const focusedTicketRow = focusedNow?.kind === "ticket" ? focusedNow.ticket : void 0;
|
|
38895
|
+
const focusedTicket = ticketsEditable ? focusedTicketRow : void 0;
|
|
38401
38896
|
const focusedTodoTask = focusedNow?.kind === "task" && focusedNow.task.status === "todo" ? focusedNow.task : void 0;
|
|
38402
38897
|
const focusedEvaluatedTask = focusedNow?.kind === "task" && latestRecordedEvaluation(focusedNow.task) !== void 0 ? focusedNow.task : void 0;
|
|
38403
38898
|
const canEdit = focusedTicket !== void 0 || focusedTodoTask !== void 0;
|
|
38404
|
-
return { focusedTicket, focusedTodoTask, focusedStuckTask, focusedEvaluatedTask, canEdit };
|
|
38899
|
+
return { focusedTicket, focusedTicketRow, focusedTodoTask, focusedStuckTask, focusedEvaluatedTask, canEdit };
|
|
38405
38900
|
};
|
|
38406
38901
|
var focusItemId = (item) => item.kind === "ticket" ? `ticket:${String(item.ticket.id)}` : `task:${String(item.task.id)}`;
|
|
38407
38902
|
var useFocusModel = (args) => {
|
|
@@ -38416,7 +38911,7 @@ var useFocusModel = (args) => {
|
|
|
38416
38911
|
visibleRows: focusVisibleRows,
|
|
38417
38912
|
// Navigation keys (↑↓ j/k PgUp/PgDn Home/End) are owned by the hook — except once a jump
|
|
38418
38913
|
// override is active, when `shortcuts.ts`'s `jump.moveBy` / `moveToEdge` take over instead.
|
|
38419
|
-
// The shortcuts hook also provides the other view-local keys (a/e/m/d/u/B/↵/q).
|
|
38914
|
+
// The shortcuts hook also provides the other view-local keys (a/e/m/d/p/u/B/↵/q).
|
|
38420
38915
|
active: modalOpen === false && loaded && jumpOverrideIdx === void 0
|
|
38421
38916
|
});
|
|
38422
38917
|
const cursorIdx = jumpOverrideIdx !== void 0 ? clampFocusIndex(jumpOverrideIdx, focusList.length) : listCursorIdx;
|
|
@@ -38443,16 +38938,9 @@ var useFocusModel = (args) => {
|
|
|
38443
38938
|
};
|
|
38444
38939
|
};
|
|
38445
38940
|
var buildDetailHints = (args) => {
|
|
38446
|
-
const {
|
|
38447
|
-
|
|
38448
|
-
|
|
38449
|
-
canEdit,
|
|
38450
|
-
sprint,
|
|
38451
|
-
currentSprintId,
|
|
38452
|
-
focusedStuckTask,
|
|
38453
|
-
focusedEvaluatedTask,
|
|
38454
|
-
blockedCount
|
|
38455
|
-
} = args;
|
|
38941
|
+
const { inDetail, ticketsEditable, sprint, currentSprintId, focus } = args;
|
|
38942
|
+
const { canEdit, focusedTicketRow, focusedStuckTask, focusedEvaluatedTask, blockedCount } = focus;
|
|
38943
|
+
const canPublish = focusedTicketRow !== void 0 && sprint?.status !== "done";
|
|
38456
38944
|
return [
|
|
38457
38945
|
{ keys: "\u2191/\u2193", label: "move" },
|
|
38458
38946
|
{ keys: "n", label: "flows" },
|
|
@@ -38463,14 +38951,15 @@ var buildDetailHints = (args) => {
|
|
|
38463
38951
|
{ keys: "a", label: "add", enabledWhen: ticketsEditable },
|
|
38464
38952
|
{ keys: "e", label: "edit", enabledWhen: canEdit },
|
|
38465
38953
|
{ keys: "d", label: "remove", enabledWhen: ticketsEditable },
|
|
38954
|
+
{ keys: "p", label: "publish", enabledWhen: canPublish },
|
|
38466
38955
|
// Surface the `m` chord only when this sprint is not already the current one — once
|
|
38467
38956
|
// they match, the action is a no-op and the hint adds noise. Suppressed while a
|
|
38468
|
-
// stuck task is focused so
|
|
38469
|
-
//
|
|
38957
|
+
// stuck task or ticket is focused so `u unblock` / `p publish` stay on one 100-column
|
|
38958
|
+
// line without competing for horizontal space.
|
|
38470
38959
|
{
|
|
38471
38960
|
keys: "m",
|
|
38472
38961
|
label: "current",
|
|
38473
|
-
enabledWhen: sprint !== void 0 && currentSprintId !== sprint.id && focusedStuckTask === void 0
|
|
38962
|
+
enabledWhen: sprint !== void 0 && currentSprintId !== sprint.id && focusedStuckTask === void 0 && !canPublish
|
|
38474
38963
|
},
|
|
38475
38964
|
{ keys: "u", label: "unblock", enabledWhen: focusedStuckTask !== void 0 },
|
|
38476
38965
|
{ keys: "B", label: "next blocked", enabledWhen: blockedCount > 0 },
|
|
@@ -38564,6 +39053,7 @@ var useSprintDetailBody = () => {
|
|
|
38564
39053
|
const [feedback2, setFeedback] = useState31(void 0);
|
|
38565
39054
|
const inDetail = openIds.size > 0;
|
|
38566
39055
|
const mountedRef = useIsMounted();
|
|
39056
|
+
const publishInFlightRef = useRef14(false);
|
|
38567
39057
|
const edit = useEditField();
|
|
38568
39058
|
const queue = usePromptQueue();
|
|
38569
39059
|
useSprintStatusChipSync(sprint, selection);
|
|
@@ -38571,12 +39061,9 @@ var useSprintDetailBody = () => {
|
|
|
38571
39061
|
buildDetailHints({
|
|
38572
39062
|
inDetail,
|
|
38573
39063
|
ticketsEditable,
|
|
38574
|
-
canEdit: focus.canEdit,
|
|
38575
39064
|
sprint,
|
|
38576
39065
|
currentSprintId: selection.sprintId,
|
|
38577
|
-
|
|
38578
|
-
focusedEvaluatedTask: focus.focusedEvaluatedTask,
|
|
38579
|
-
blockedCount: focus.blockedCount
|
|
39066
|
+
focus
|
|
38580
39067
|
})
|
|
38581
39068
|
);
|
|
38582
39069
|
const unblockTask2 = useUnblockTask();
|
|
@@ -38590,7 +39077,8 @@ var useSprintDetailBody = () => {
|
|
|
38590
39077
|
mountedRef,
|
|
38591
39078
|
setFeedback,
|
|
38592
39079
|
unblockTask: unblockTask2,
|
|
38593
|
-
setConfirmRemove
|
|
39080
|
+
setConfirmRemove,
|
|
39081
|
+
publishInFlightRef
|
|
38594
39082
|
});
|
|
38595
39083
|
useSprintDetailShortcuts({
|
|
38596
39084
|
modalOpen: ui.modalOpen,
|
|
@@ -38612,6 +39100,7 @@ var useSprintDetailBody = () => {
|
|
|
38612
39100
|
setConfirmRemove,
|
|
38613
39101
|
setFeedback,
|
|
38614
39102
|
onUnblock: handlers.handleUnblock,
|
|
39103
|
+
onPublish: handlers.handlePublish,
|
|
38615
39104
|
sprintId: sprint?.id,
|
|
38616
39105
|
openEvaluationOverlay: ui.openEvaluation,
|
|
38617
39106
|
reload
|
|
@@ -39885,15 +40374,15 @@ var useTokenUsage = (bus, opts = {}) => useCoalescedMap(bus, {
|
|
|
39885
40374
|
});
|
|
39886
40375
|
|
|
39887
40376
|
// src/application/ui/tui/runtime/use-coalesced-buffer.ts
|
|
39888
|
-
import { useEffect as useEffect28, useRef as
|
|
40377
|
+
import { useEffect as useEffect28, useRef as useRef15, useState as useState33 } from "react";
|
|
39889
40378
|
var useCoalescedBuffer = (opts) => {
|
|
39890
40379
|
const limit = opts.limit ?? 100;
|
|
39891
40380
|
const [items, setItems] = useState33(() => opts.initial ? opts.initial.slice(-limit) : []);
|
|
39892
|
-
const subscribeRef =
|
|
40381
|
+
const subscribeRef = useRef15(opts.subscribe);
|
|
39893
40382
|
subscribeRef.current = opts.subscribe;
|
|
39894
|
-
const initialRef =
|
|
40383
|
+
const initialRef = useRef15(opts.initial);
|
|
39895
40384
|
initialRef.current = opts.initial;
|
|
39896
|
-
const mountedRef =
|
|
40385
|
+
const mountedRef = useRef15(false);
|
|
39897
40386
|
useEffect28(() => {
|
|
39898
40387
|
const buf = createCoalescedBuffer({
|
|
39899
40388
|
limit,
|
|
@@ -39928,10 +40417,10 @@ var useSinkStream = (bus, opts = {}) => {
|
|
|
39928
40417
|
};
|
|
39929
40418
|
|
|
39930
40419
|
// src/application/ui/tui/runtime/use-event-bus.ts
|
|
39931
|
-
import { useRef as
|
|
40420
|
+
import { useRef as useRef16 } from "react";
|
|
39932
40421
|
var useEventBusBuffer = (bus, opts) => {
|
|
39933
40422
|
const limit = opts.limit ?? 100;
|
|
39934
|
-
const filterRef =
|
|
40423
|
+
const filterRef = useRef16(opts.filter);
|
|
39935
40424
|
filterRef.current = opts.filter;
|
|
39936
40425
|
return useCoalescedBuffer({
|
|
39937
40426
|
limit,
|
|
@@ -42954,6 +43443,330 @@ var createSettingsShowFlow = (deps) => leaf("settings-show", {
|
|
|
42954
43443
|
// src/application/ui/tui/views/settings-editor.tsx
|
|
42955
43444
|
import { useState as useState38 } from "react";
|
|
42956
43445
|
|
|
43446
|
+
// src/business/settings/claude-preset-matrices.ts
|
|
43447
|
+
var CLAUDE_ONLY = {
|
|
43448
|
+
effort: "high",
|
|
43449
|
+
refine: { provider: CLAUDE, model: SONNET, effort: "medium" },
|
|
43450
|
+
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43451
|
+
implement: {
|
|
43452
|
+
generator: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43453
|
+
evaluator: { provider: CLAUDE, model: OPUS, effort: "xhigh" }
|
|
43454
|
+
},
|
|
43455
|
+
readiness: { provider: CLAUDE, model: SONNET, effort: "medium" },
|
|
43456
|
+
ideate: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43457
|
+
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43458
|
+
};
|
|
43459
|
+
var CLAUDE_ECONOMIC = {
|
|
43460
|
+
effort: "high",
|
|
43461
|
+
refine: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43462
|
+
plan: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43463
|
+
implement: {
|
|
43464
|
+
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43465
|
+
evaluator: { provider: CLAUDE, model: SONNET, effort: "high" }
|
|
43466
|
+
},
|
|
43467
|
+
readiness: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43468
|
+
ideate: { provider: CLAUDE, model: SONNET, effort: "medium" },
|
|
43469
|
+
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43470
|
+
};
|
|
43471
|
+
var CLAUDE_STRONG_GATE = {
|
|
43472
|
+
effort: "high",
|
|
43473
|
+
refine: { provider: CLAUDE, model: SONNET, effort: "medium" },
|
|
43474
|
+
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43475
|
+
implement: {
|
|
43476
|
+
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43477
|
+
evaluator: { provider: CLAUDE, model: OPUS, effort: "xhigh" }
|
|
43478
|
+
},
|
|
43479
|
+
readiness: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43480
|
+
ideate: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43481
|
+
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43482
|
+
};
|
|
43483
|
+
var CLAUDE_FAST = {
|
|
43484
|
+
effort: "low",
|
|
43485
|
+
refine: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43486
|
+
plan: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43487
|
+
implement: {
|
|
43488
|
+
generator: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43489
|
+
evaluator: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43490
|
+
},
|
|
43491
|
+
readiness: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43492
|
+
ideate: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43493
|
+
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43494
|
+
};
|
|
43495
|
+
var CLAUDE_FRONTIER = {
|
|
43496
|
+
effort: "max",
|
|
43497
|
+
refine: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43498
|
+
plan: { provider: CLAUDE, model: FABLE, effort: "max" },
|
|
43499
|
+
implement: {
|
|
43500
|
+
generator: { provider: CLAUDE, model: FABLE, effort: "max" },
|
|
43501
|
+
evaluator: { provider: CLAUDE, model: FABLE, effort: "max" }
|
|
43502
|
+
},
|
|
43503
|
+
readiness: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43504
|
+
ideate: { provider: CLAUDE, model: FABLE, effort: "high" },
|
|
43505
|
+
createPr: { provider: CLAUDE, model: OPUS, effort: "medium" }
|
|
43506
|
+
};
|
|
43507
|
+
|
|
43508
|
+
// src/business/settings/codex-preset-matrices.ts
|
|
43509
|
+
var CODEX_ONLY = {
|
|
43510
|
+
effort: "high",
|
|
43511
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "high" },
|
|
43512
|
+
plan: { provider: CODEX, model: GPT_6_SOL, effort: "xhigh" },
|
|
43513
|
+
implement: {
|
|
43514
|
+
generator: { provider: CODEX, model: GPT_6_SOL, effort: "xhigh" },
|
|
43515
|
+
evaluator: { provider: CODEX, model: GPT_6_SOL, effort: "xhigh" }
|
|
43516
|
+
},
|
|
43517
|
+
readiness: { provider: CODEX, model: GPT_6_LUNA, effort: "medium" },
|
|
43518
|
+
ideate: { provider: CODEX, model: GPT_6_SOL, effort: "high" },
|
|
43519
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43520
|
+
};
|
|
43521
|
+
var CODEX_ECONOMIC = {
|
|
43522
|
+
effort: "high",
|
|
43523
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "medium" },
|
|
43524
|
+
plan: { provider: CODEX, model: GPT_6_LUNA, effort: "xhigh" },
|
|
43525
|
+
implement: {
|
|
43526
|
+
generator: { provider: CODEX, model: GPT_6_LUNA, effort: "xhigh" },
|
|
43527
|
+
evaluator: { provider: CODEX, model: GPT_6_LUNA, effort: "xhigh" }
|
|
43528
|
+
},
|
|
43529
|
+
readiness: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43530
|
+
ideate: { provider: CODEX, model: GPT_6_LUNA, effort: "high" },
|
|
43531
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43532
|
+
};
|
|
43533
|
+
var CODEX_STRONG_GATE = {
|
|
43534
|
+
effort: "high",
|
|
43535
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "medium" },
|
|
43536
|
+
plan: { provider: CODEX, model: GPT_6_SOL, effort: "xhigh" },
|
|
43537
|
+
implement: {
|
|
43538
|
+
generator: { provider: CODEX, model: GPT_6_LUNA, effort: "xhigh" },
|
|
43539
|
+
evaluator: { provider: CODEX, model: GPT_6_SOL, effort: "xhigh" }
|
|
43540
|
+
},
|
|
43541
|
+
readiness: { provider: CODEX, model: GPT_6_LUNA, effort: "medium" },
|
|
43542
|
+
ideate: { provider: CODEX, model: GPT_6_SOL, effort: "high" },
|
|
43543
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43544
|
+
};
|
|
43545
|
+
var CODEX_FAST = {
|
|
43546
|
+
effort: "low",
|
|
43547
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43548
|
+
plan: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43549
|
+
implement: {
|
|
43550
|
+
generator: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43551
|
+
evaluator: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43552
|
+
},
|
|
43553
|
+
readiness: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43554
|
+
ideate: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43555
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43556
|
+
};
|
|
43557
|
+
var CODEX_FRONTIER = {
|
|
43558
|
+
effort: "max",
|
|
43559
|
+
refine: { provider: CODEX, model: GPT_6_SOL, effort: "high" },
|
|
43560
|
+
plan: { provider: CODEX, model: GPT_6_ASTRA, effort: "max" },
|
|
43561
|
+
implement: {
|
|
43562
|
+
generator: { provider: CODEX, model: GPT_6_ASTRA, effort: "max" },
|
|
43563
|
+
evaluator: { provider: CODEX, model: GPT_6_ASTRA, effort: "max" }
|
|
43564
|
+
},
|
|
43565
|
+
readiness: { provider: CODEX, model: GPT_6_SOL, effort: "high" },
|
|
43566
|
+
ideate: { provider: CODEX, model: GPT_6_ASTRA, effort: "high" },
|
|
43567
|
+
createPr: { provider: CODEX, model: GPT_6_SOL, effort: "medium" }
|
|
43568
|
+
};
|
|
43569
|
+
|
|
43570
|
+
// src/business/settings/copilot-preset-matrices.ts
|
|
43571
|
+
var COPILOT_ONLY = {
|
|
43572
|
+
effort: "high",
|
|
43573
|
+
refine: { provider: COPILOT, model: COPILOT_SONNET, effort: "medium" },
|
|
43574
|
+
plan: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" },
|
|
43575
|
+
implement: {
|
|
43576
|
+
generator: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" },
|
|
43577
|
+
evaluator: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" }
|
|
43578
|
+
},
|
|
43579
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43580
|
+
ideate: { provider: COPILOT, model: COPILOT_OPUS, effort: "high" },
|
|
43581
|
+
createPr: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" }
|
|
43582
|
+
};
|
|
43583
|
+
var COPILOT_ECONOMIC = {
|
|
43584
|
+
effort: "high",
|
|
43585
|
+
refine: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43586
|
+
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43587
|
+
implement: {
|
|
43588
|
+
generator: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43589
|
+
evaluator: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" }
|
|
43590
|
+
},
|
|
43591
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43592
|
+
ideate: { provider: COPILOT, model: COPILOT_SONNET, effort: "medium" },
|
|
43593
|
+
createPr: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" }
|
|
43594
|
+
};
|
|
43595
|
+
var COPILOT_STRONG_GATE = {
|
|
43596
|
+
effort: "high",
|
|
43597
|
+
refine: { provider: COPILOT, model: COPILOT_SONNET, effort: "medium" },
|
|
43598
|
+
plan: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" },
|
|
43599
|
+
implement: {
|
|
43600
|
+
generator: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43601
|
+
evaluator: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" }
|
|
43602
|
+
},
|
|
43603
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43604
|
+
ideate: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43605
|
+
createPr: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" }
|
|
43606
|
+
};
|
|
43607
|
+
var COPILOT_FAST = {
|
|
43608
|
+
effort: "low",
|
|
43609
|
+
refine: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" },
|
|
43610
|
+
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" },
|
|
43611
|
+
implement: {
|
|
43612
|
+
generator: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" },
|
|
43613
|
+
evaluator: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" }
|
|
43614
|
+
},
|
|
43615
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" },
|
|
43616
|
+
ideate: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" },
|
|
43617
|
+
createPr: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" }
|
|
43618
|
+
};
|
|
43619
|
+
var COPILOT_FRONTIER = {
|
|
43620
|
+
effort: "max",
|
|
43621
|
+
refine: { provider: COPILOT, model: COPILOT_OPUS, effort: "high" },
|
|
43622
|
+
plan: { provider: COPILOT, model: COPILOT_OPUS, effort: "max" },
|
|
43623
|
+
implement: {
|
|
43624
|
+
generator: { provider: COPILOT, model: COPILOT_OPUS, effort: "max" },
|
|
43625
|
+
evaluator: { provider: COPILOT, model: COPILOT_OPUS, effort: "max" }
|
|
43626
|
+
},
|
|
43627
|
+
readiness: { provider: COPILOT, model: COPILOT_OPUS, effort: "high" },
|
|
43628
|
+
ideate: { provider: COPILOT, model: COPILOT_OPUS, effort: "high" },
|
|
43629
|
+
createPr: { provider: COPILOT, model: COPILOT_OPUS, effort: "medium" }
|
|
43630
|
+
};
|
|
43631
|
+
|
|
43632
|
+
// src/business/settings/grok-preset-matrices.ts
|
|
43633
|
+
var GROK_ONLY = {
|
|
43634
|
+
effort: "high",
|
|
43635
|
+
refine: { provider: GROK, model: GROK_MID, effort: "medium" },
|
|
43636
|
+
plan: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" },
|
|
43637
|
+
implement: {
|
|
43638
|
+
generator: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" },
|
|
43639
|
+
evaluator: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" }
|
|
43640
|
+
},
|
|
43641
|
+
readiness: { provider: GROK, model: GROK_CHEAP, effort: "medium" },
|
|
43642
|
+
ideate: { provider: GROK, model: GROK_FLAGSHIP, effort: "high" },
|
|
43643
|
+
createPr: { provider: GROK, model: GROK_CHEAP, effort: "low" }
|
|
43644
|
+
};
|
|
43645
|
+
var GROK_ECONOMIC = {
|
|
43646
|
+
effort: "high",
|
|
43647
|
+
refine: { provider: GROK, model: GROK_CHEAP, effort: "medium" },
|
|
43648
|
+
plan: { provider: GROK, model: GROK_MID, effort: "high" },
|
|
43649
|
+
implement: {
|
|
43650
|
+
generator: { provider: GROK, model: GROK_MID, effort: "high" },
|
|
43651
|
+
evaluator: { provider: GROK, model: GROK_MID, effort: "high" }
|
|
43652
|
+
},
|
|
43653
|
+
readiness: { provider: GROK, model: GROK_CHEAP, effort: "medium" },
|
|
43654
|
+
ideate: { provider: GROK, model: GROK_MID, effort: "medium" },
|
|
43655
|
+
createPr: { provider: GROK, model: GROK_CHEAP, effort: "low" }
|
|
43656
|
+
};
|
|
43657
|
+
var GROK_STRONG_GATE = {
|
|
43658
|
+
effort: "high",
|
|
43659
|
+
refine: { provider: GROK, model: GROK_CHEAP, effort: "medium" },
|
|
43660
|
+
plan: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" },
|
|
43661
|
+
implement: {
|
|
43662
|
+
generator: { provider: GROK, model: GROK_MID, effort: "high" },
|
|
43663
|
+
evaluator: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" }
|
|
43664
|
+
},
|
|
43665
|
+
readiness: { provider: GROK, model: GROK_CHEAP, effort: "medium" },
|
|
43666
|
+
ideate: { provider: GROK, model: GROK_FLAGSHIP, effort: "high" },
|
|
43667
|
+
createPr: { provider: GROK, model: GROK_CHEAP, effort: "low" }
|
|
43668
|
+
};
|
|
43669
|
+
var GROK_FAST = {
|
|
43670
|
+
effort: "low",
|
|
43671
|
+
refine: { provider: GROK, model: GROK_CHEAP, effort: "low" },
|
|
43672
|
+
plan: { provider: GROK, model: GROK_CHEAP, effort: "low" },
|
|
43673
|
+
implement: {
|
|
43674
|
+
generator: { provider: GROK, model: GROK_CHEAP, effort: "low" },
|
|
43675
|
+
evaluator: { provider: GROK, model: GROK_CHEAP, effort: "low" }
|
|
43676
|
+
},
|
|
43677
|
+
readiness: { provider: GROK, model: GROK_CHEAP, effort: "low" },
|
|
43678
|
+
ideate: { provider: GROK, model: GROK_CHEAP, effort: "low" },
|
|
43679
|
+
createPr: { provider: GROK, model: GROK_CHEAP, effort: "low" }
|
|
43680
|
+
};
|
|
43681
|
+
var GROK_FRONTIER = {
|
|
43682
|
+
effort: "max",
|
|
43683
|
+
refine: { provider: GROK, model: GROK_FLAGSHIP, effort: "high" },
|
|
43684
|
+
plan: { provider: GROK, model: GROK_FLAGSHIP, effort: "max" },
|
|
43685
|
+
implement: {
|
|
43686
|
+
generator: { provider: GROK, model: GROK_FLAGSHIP, effort: "max" },
|
|
43687
|
+
evaluator: { provider: GROK, model: GROK_FLAGSHIP, effort: "max" }
|
|
43688
|
+
},
|
|
43689
|
+
readiness: { provider: GROK, model: GROK_FLAGSHIP, effort: "high" },
|
|
43690
|
+
ideate: { provider: GROK, model: GROK_FLAGSHIP, effort: "high" },
|
|
43691
|
+
createPr: { provider: GROK, model: GROK_FLAGSHIP, effort: "medium" }
|
|
43692
|
+
};
|
|
43693
|
+
|
|
43694
|
+
// src/business/settings/mixed-preset-matrices.ts
|
|
43695
|
+
var MIXED = {
|
|
43696
|
+
effort: "high",
|
|
43697
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "high" },
|
|
43698
|
+
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43699
|
+
implement: {
|
|
43700
|
+
generator: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43701
|
+
evaluator: { provider: CODEX, model: GPT_6_SOL, effort: "xhigh" }
|
|
43702
|
+
},
|
|
43703
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43704
|
+
ideate: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43705
|
+
// Summarising a diff does not need Opus tokens.
|
|
43706
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43707
|
+
};
|
|
43708
|
+
var MIXED_ECONOMIC = {
|
|
43709
|
+
effort: "high",
|
|
43710
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "medium" },
|
|
43711
|
+
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43712
|
+
implement: {
|
|
43713
|
+
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43714
|
+
evaluator: { provider: CODEX, model: GPT_6_LUNA, effort: "xhigh" }
|
|
43715
|
+
},
|
|
43716
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43717
|
+
ideate: { provider: CLAUDE, model: SONNET, effort: "medium" },
|
|
43718
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43719
|
+
};
|
|
43720
|
+
var MIXED_STRONG_GATE = {
|
|
43721
|
+
effort: "high",
|
|
43722
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "medium" },
|
|
43723
|
+
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43724
|
+
implement: {
|
|
43725
|
+
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43726
|
+
evaluator: { provider: CLAUDE, model: OPUS, effort: "xhigh" }
|
|
43727
|
+
},
|
|
43728
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "medium" },
|
|
43729
|
+
ideate: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43730
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43731
|
+
};
|
|
43732
|
+
var MIXED_FAST = {
|
|
43733
|
+
effort: "low",
|
|
43734
|
+
refine: { provider: CODEX, model: GPT_6_LUNA, effort: "low" },
|
|
43735
|
+
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" },
|
|
43736
|
+
implement: {
|
|
43737
|
+
generator: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43738
|
+
evaluator: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43739
|
+
},
|
|
43740
|
+
readiness: { provider: COPILOT, model: COPILOT_LUNA, effort: "low" },
|
|
43741
|
+
ideate: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43742
|
+
createPr: { provider: CODEX, model: GPT_6_LUNA, effort: "low" }
|
|
43743
|
+
};
|
|
43744
|
+
var MIXED_FRONTIER = {
|
|
43745
|
+
effort: "max",
|
|
43746
|
+
refine: { provider: CODEX, model: GPT_6_SOL, effort: "high" },
|
|
43747
|
+
plan: { provider: CLAUDE, model: FABLE, effort: "max" },
|
|
43748
|
+
implement: {
|
|
43749
|
+
generator: { provider: CLAUDE, model: FABLE, effort: "max" },
|
|
43750
|
+
evaluator: { provider: CODEX, model: GPT_6_ASTRA, effort: "max" }
|
|
43751
|
+
},
|
|
43752
|
+
readiness: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43753
|
+
ideate: { provider: CLAUDE, model: FABLE, effort: "high" },
|
|
43754
|
+
createPr: { provider: CODEX, model: GPT_6_SOL, effort: "medium" }
|
|
43755
|
+
};
|
|
43756
|
+
|
|
43757
|
+
// src/business/settings/opencode-preset-matrices.ts
|
|
43758
|
+
var OPENCODE_ONLY = {
|
|
43759
|
+
refine: { provider: OPENCODE, model: OPENCODE_MINI },
|
|
43760
|
+
plan: { provider: OPENCODE, model: OPENCODE_BIG },
|
|
43761
|
+
implement: {
|
|
43762
|
+
generator: { provider: OPENCODE, model: OPENCODE_BIG },
|
|
43763
|
+
evaluator: { provider: OPENCODE, model: OPENCODE_BIG }
|
|
43764
|
+
},
|
|
43765
|
+
readiness: { provider: OPENCODE, model: OPENCODE_MINI },
|
|
43766
|
+
ideate: { provider: OPENCODE, model: OPENCODE_BIG },
|
|
43767
|
+
createPr: { provider: OPENCODE, model: OPENCODE_MINI }
|
|
43768
|
+
};
|
|
43769
|
+
|
|
42957
43770
|
// src/business/settings/presets.ts
|
|
42958
43771
|
var PRESET_NAMES = [
|
|
42959
43772
|
"mixed",
|
|
@@ -42966,311 +43779,24 @@ var PRESET_NAMES = [
|
|
|
42966
43779
|
"claude-economic",
|
|
42967
43780
|
"copilot-economic",
|
|
42968
43781
|
"codex-economic",
|
|
43782
|
+
"grok-economic",
|
|
42969
43783
|
"mixed-strong-gate",
|
|
42970
43784
|
"claude-strong-gate",
|
|
42971
43785
|
"copilot-strong-gate",
|
|
42972
43786
|
"codex-strong-gate",
|
|
43787
|
+
"grok-strong-gate",
|
|
42973
43788
|
"mixed-fast",
|
|
42974
43789
|
"claude-fast",
|
|
42975
43790
|
"copilot-fast",
|
|
42976
43791
|
"codex-fast",
|
|
43792
|
+
"grok-fast",
|
|
42977
43793
|
"mixed-frontier",
|
|
42978
43794
|
"claude-frontier",
|
|
42979
43795
|
"copilot-frontier",
|
|
42980
|
-
"codex-frontier"
|
|
43796
|
+
"codex-frontier",
|
|
43797
|
+
"grok-frontier"
|
|
42981
43798
|
];
|
|
42982
43799
|
var isPresetName = (raw) => PRESET_NAMES.includes(raw);
|
|
42983
|
-
var CLAUDE = "claude-code";
|
|
42984
|
-
var COPILOT = "github-copilot";
|
|
42985
|
-
var CODEX = "openai-codex";
|
|
42986
|
-
var OPENCODE = "opencode";
|
|
42987
|
-
var GROK = "xai-grok";
|
|
42988
|
-
var GROK_FLAGSHIP = "grok-4.6";
|
|
42989
|
-
var GROK_PREV = "grok-4.5";
|
|
42990
|
-
var OPENCODE_BIG2 = "opencode/big-pickle";
|
|
42991
|
-
var OPENCODE_MINI2 = "opencode/deepseek-v4-flash-free";
|
|
42992
|
-
var OPUS = "claude-opus-5";
|
|
42993
|
-
var SONNET = "claude-sonnet-5";
|
|
42994
|
-
var COPILOT_OPUS = "claude-opus-4.8";
|
|
42995
|
-
var COPILOT_SONNET = "claude-sonnet-4.6";
|
|
42996
|
-
var GPT_5_6_SOL2 = "gpt-5.6-sol";
|
|
42997
|
-
var GPT_5_6_TERRA = "gpt-5.6-terra";
|
|
42998
|
-
var GPT_5_6_LUNA = "gpt-5.6-luna";
|
|
42999
|
-
var MIXED = {
|
|
43000
|
-
effort: "high",
|
|
43001
|
-
refine: { provider: CODEX, model: GPT_5_6_TERRA },
|
|
43002
|
-
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "xhigh" },
|
|
43003
|
-
implement: {
|
|
43004
|
-
generator: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43005
|
-
// Independent gate: a different provider's flagship grades the Opus author's work.
|
|
43006
|
-
evaluator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "xhigh" }
|
|
43007
|
-
},
|
|
43008
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43009
|
-
ideate: { provider: CLAUDE, model: OPUS },
|
|
43010
|
-
// PR content drafting mirrors refine's "light summary" reasoning profile — a fast Codex
|
|
43011
|
-
// model is fine, no need to pay for Opus tokens just to summarise a diff.
|
|
43012
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43013
|
-
};
|
|
43014
|
-
var CLAUDE_ONLY = {
|
|
43015
|
-
effort: "high",
|
|
43016
|
-
refine: { provider: CLAUDE, model: SONNET },
|
|
43017
|
-
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43018
|
-
implement: {
|
|
43019
|
-
generator: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43020
|
-
evaluator: { provider: CLAUDE, model: OPUS, effort: "xhigh" }
|
|
43021
|
-
},
|
|
43022
|
-
readiness: { provider: CLAUDE, model: SONNET, effort: "medium" },
|
|
43023
|
-
ideate: { provider: CLAUDE, model: OPUS },
|
|
43024
|
-
createPr: { provider: CLAUDE, model: SONNET }
|
|
43025
|
-
};
|
|
43026
|
-
var COPILOT_ONLY = {
|
|
43027
|
-
effort: "high",
|
|
43028
|
-
refine: { provider: COPILOT, model: COPILOT_SONNET },
|
|
43029
|
-
plan: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" },
|
|
43030
|
-
implement: {
|
|
43031
|
-
generator: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" },
|
|
43032
|
-
evaluator: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" }
|
|
43033
|
-
},
|
|
43034
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43035
|
-
ideate: { provider: COPILOT, model: COPILOT_OPUS },
|
|
43036
|
-
createPr: { provider: COPILOT, model: GPT_5_6_LUNA }
|
|
43037
|
-
};
|
|
43038
|
-
var OPENCODE_ONLY = {
|
|
43039
|
-
refine: { provider: OPENCODE, model: OPENCODE_MINI2 },
|
|
43040
|
-
plan: { provider: OPENCODE, model: OPENCODE_BIG2 },
|
|
43041
|
-
implement: {
|
|
43042
|
-
generator: { provider: OPENCODE, model: OPENCODE_BIG2 },
|
|
43043
|
-
evaluator: { provider: OPENCODE, model: OPENCODE_BIG2 }
|
|
43044
|
-
},
|
|
43045
|
-
readiness: { provider: OPENCODE, model: OPENCODE_MINI2 },
|
|
43046
|
-
ideate: { provider: OPENCODE, model: OPENCODE_BIG2 },
|
|
43047
|
-
createPr: { provider: OPENCODE, model: OPENCODE_MINI2 }
|
|
43048
|
-
};
|
|
43049
|
-
var GROK_ONLY = {
|
|
43050
|
-
effort: "high",
|
|
43051
|
-
refine: { provider: GROK, model: GROK_PREV },
|
|
43052
|
-
plan: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" },
|
|
43053
|
-
implement: {
|
|
43054
|
-
generator: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" },
|
|
43055
|
-
evaluator: { provider: GROK, model: GROK_FLAGSHIP, effort: "xhigh" }
|
|
43056
|
-
},
|
|
43057
|
-
readiness: { provider: GROK, model: GROK_PREV, effort: "medium" },
|
|
43058
|
-
ideate: { provider: GROK, model: GROK_FLAGSHIP },
|
|
43059
|
-
createPr: { provider: GROK, model: GROK_PREV }
|
|
43060
|
-
};
|
|
43061
|
-
var CODEX_ONLY = {
|
|
43062
|
-
effort: "high",
|
|
43063
|
-
refine: { provider: CODEX, model: GPT_5_6_TERRA },
|
|
43064
|
-
plan: { provider: CODEX, model: GPT_5_6_SOL2, effort: "xhigh" },
|
|
43065
|
-
implement: {
|
|
43066
|
-
generator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "xhigh" },
|
|
43067
|
-
evaluator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "xhigh" }
|
|
43068
|
-
},
|
|
43069
|
-
readiness: { provider: CODEX, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43070
|
-
ideate: { provider: CODEX, model: GPT_5_6_SOL2 },
|
|
43071
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43072
|
-
};
|
|
43073
|
-
var MIXED_ECONOMIC = {
|
|
43074
|
-
effort: "high",
|
|
43075
|
-
refine: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43076
|
-
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43077
|
-
implement: {
|
|
43078
|
-
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43079
|
-
evaluator: { provider: CLAUDE, model: SONNET, effort: "high" }
|
|
43080
|
-
},
|
|
43081
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43082
|
-
ideate: { provider: CLAUDE, model: SONNET },
|
|
43083
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43084
|
-
};
|
|
43085
|
-
var CLAUDE_ECONOMIC = {
|
|
43086
|
-
effort: "high",
|
|
43087
|
-
// Claude's cheap tier is sonnet-at-`low`, not a smaller model — see the note on SONNET. Effort
|
|
43088
|
-
// is pinned on every light row: unset would inherit this preset's global `high` and undo the
|
|
43089
|
-
// saving the row exists for.
|
|
43090
|
-
refine: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43091
|
-
plan: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43092
|
-
implement: {
|
|
43093
|
-
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43094
|
-
evaluator: { provider: CLAUDE, model: SONNET, effort: "high" }
|
|
43095
|
-
},
|
|
43096
|
-
readiness: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43097
|
-
ideate: { provider: CLAUDE, model: SONNET },
|
|
43098
|
-
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43099
|
-
};
|
|
43100
|
-
var COPILOT_ECONOMIC = {
|
|
43101
|
-
effort: "high",
|
|
43102
|
-
refine: { provider: COPILOT, model: GPT_5_6_LUNA },
|
|
43103
|
-
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43104
|
-
implement: {
|
|
43105
|
-
generator: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43106
|
-
evaluator: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" }
|
|
43107
|
-
},
|
|
43108
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43109
|
-
ideate: { provider: COPILOT, model: COPILOT_SONNET },
|
|
43110
|
-
createPr: { provider: COPILOT, model: GPT_5_6_LUNA }
|
|
43111
|
-
};
|
|
43112
|
-
var CODEX_ECONOMIC = {
|
|
43113
|
-
effort: "high",
|
|
43114
|
-
refine: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43115
|
-
plan: { provider: CODEX, model: GPT_5_6_TERRA, effort: "high" },
|
|
43116
|
-
implement: {
|
|
43117
|
-
generator: { provider: CODEX, model: GPT_5_6_TERRA, effort: "high" },
|
|
43118
|
-
evaluator: { provider: CODEX, model: GPT_5_6_TERRA, effort: "high" }
|
|
43119
|
-
},
|
|
43120
|
-
readiness: { provider: CODEX, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43121
|
-
ideate: { provider: CODEX, model: GPT_5_6_TERRA },
|
|
43122
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43123
|
-
};
|
|
43124
|
-
var CLAUDE_STRONG_GATE = {
|
|
43125
|
-
effort: "high",
|
|
43126
|
-
refine: { provider: CLAUDE, model: SONNET },
|
|
43127
|
-
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43128
|
-
implement: {
|
|
43129
|
-
// Cheap author: sonnet at high effort, climbs to opus on plateau via the default ladder.
|
|
43130
|
-
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43131
|
-
// Strong gate: opus from the first round, never cheapened.
|
|
43132
|
-
evaluator: { provider: CLAUDE, model: OPUS, effort: "xhigh" }
|
|
43133
|
-
},
|
|
43134
|
-
// Cheap light flows: sonnet pinned at `low` (see CLAUDE_ECONOMIC) — never inheriting global `high`.
|
|
43135
|
-
readiness: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43136
|
-
ideate: { provider: CLAUDE, model: SONNET },
|
|
43137
|
-
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43138
|
-
};
|
|
43139
|
-
var MIXED_STRONG_GATE = {
|
|
43140
|
-
effort: "high",
|
|
43141
|
-
refine: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43142
|
-
plan: { provider: CLAUDE, model: OPUS, effort: "xhigh" },
|
|
43143
|
-
implement: {
|
|
43144
|
-
generator: { provider: CLAUDE, model: SONNET, effort: "high" },
|
|
43145
|
-
evaluator: { provider: CLAUDE, model: OPUS, effort: "xhigh" }
|
|
43146
|
-
},
|
|
43147
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43148
|
-
ideate: { provider: CLAUDE, model: SONNET },
|
|
43149
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43150
|
-
};
|
|
43151
|
-
var COPILOT_STRONG_GATE = {
|
|
43152
|
-
effort: "high",
|
|
43153
|
-
refine: { provider: COPILOT, model: COPILOT_SONNET },
|
|
43154
|
-
plan: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" },
|
|
43155
|
-
implement: {
|
|
43156
|
-
generator: { provider: COPILOT, model: COPILOT_SONNET, effort: "high" },
|
|
43157
|
-
evaluator: { provider: COPILOT, model: COPILOT_OPUS, effort: "xhigh" }
|
|
43158
|
-
},
|
|
43159
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43160
|
-
ideate: { provider: COPILOT, model: COPILOT_SONNET },
|
|
43161
|
-
createPr: { provider: COPILOT, model: GPT_5_6_LUNA }
|
|
43162
|
-
};
|
|
43163
|
-
var CODEX_STRONG_GATE = {
|
|
43164
|
-
effort: "high",
|
|
43165
|
-
refine: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43166
|
-
plan: { provider: CODEX, model: GPT_5_6_SOL2, effort: "xhigh" },
|
|
43167
|
-
implement: {
|
|
43168
|
-
// Narrowest gate of the family: terra author climbs the single default-ladder rung to the
|
|
43169
|
-
// sol gate.
|
|
43170
|
-
generator: { provider: CODEX, model: GPT_5_6_TERRA, effort: "high" },
|
|
43171
|
-
evaluator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "xhigh" }
|
|
43172
|
-
},
|
|
43173
|
-
readiness: { provider: CODEX, model: GPT_5_6_LUNA, effort: "medium" },
|
|
43174
|
-
ideate: { provider: CODEX, model: GPT_5_6_SOL2 },
|
|
43175
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43176
|
-
};
|
|
43177
|
-
var MIXED_FAST = {
|
|
43178
|
-
effort: "low",
|
|
43179
|
-
refine: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43180
|
-
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" },
|
|
43181
|
-
implement: {
|
|
43182
|
-
generator: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43183
|
-
evaluator: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43184
|
-
},
|
|
43185
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "low" },
|
|
43186
|
-
ideate: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43187
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43188
|
-
};
|
|
43189
|
-
var CLAUDE_FAST = {
|
|
43190
|
-
effort: "low",
|
|
43191
|
-
refine: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43192
|
-
plan: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43193
|
-
implement: {
|
|
43194
|
-
generator: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43195
|
-
evaluator: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43196
|
-
},
|
|
43197
|
-
readiness: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43198
|
-
ideate: { provider: CLAUDE, model: SONNET, effort: "low" },
|
|
43199
|
-
createPr: { provider: CLAUDE, model: SONNET, effort: "low" }
|
|
43200
|
-
};
|
|
43201
|
-
var COPILOT_FAST = {
|
|
43202
|
-
effort: "low",
|
|
43203
|
-
refine: { provider: COPILOT, model: GPT_5_6_LUNA },
|
|
43204
|
-
plan: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" },
|
|
43205
|
-
implement: {
|
|
43206
|
-
generator: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" },
|
|
43207
|
-
evaluator: { provider: COPILOT, model: COPILOT_SONNET, effort: "low" }
|
|
43208
|
-
},
|
|
43209
|
-
readiness: { provider: COPILOT, model: GPT_5_6_LUNA, effort: "low" },
|
|
43210
|
-
ideate: { provider: COPILOT, model: GPT_5_6_LUNA },
|
|
43211
|
-
createPr: { provider: COPILOT, model: GPT_5_6_LUNA }
|
|
43212
|
-
};
|
|
43213
|
-
var CODEX_FAST = {
|
|
43214
|
-
effort: "low",
|
|
43215
|
-
refine: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43216
|
-
plan: { provider: CODEX, model: GPT_5_6_LUNA, effort: "low" },
|
|
43217
|
-
implement: {
|
|
43218
|
-
generator: { provider: CODEX, model: GPT_5_6_LUNA, effort: "low" },
|
|
43219
|
-
evaluator: { provider: CODEX, model: GPT_5_6_LUNA, effort: "low" }
|
|
43220
|
-
},
|
|
43221
|
-
readiness: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43222
|
-
ideate: { provider: CODEX, model: GPT_5_6_LUNA },
|
|
43223
|
-
createPr: { provider: CODEX, model: GPT_5_6_LUNA }
|
|
43224
|
-
};
|
|
43225
|
-
var MIXED_FRONTIER = {
|
|
43226
|
-
effort: "max",
|
|
43227
|
-
refine: { provider: CODEX, model: GPT_5_6_SOL2 },
|
|
43228
|
-
plan: { provider: CLAUDE, model: OPUS, effort: "max" },
|
|
43229
|
-
implement: {
|
|
43230
|
-
generator: { provider: CLAUDE, model: OPUS, effort: "max" },
|
|
43231
|
-
// Same cross-provider gate as `mixed`, at the frontier tier.
|
|
43232
|
-
evaluator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "max" }
|
|
43233
|
-
},
|
|
43234
|
-
readiness: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43235
|
-
ideate: { provider: CLAUDE, model: OPUS },
|
|
43236
|
-
createPr: { provider: CODEX, model: GPT_5_6_SOL2 }
|
|
43237
|
-
};
|
|
43238
|
-
var CLAUDE_FRONTIER = {
|
|
43239
|
-
effort: "max",
|
|
43240
|
-
refine: { provider: CLAUDE, model: OPUS },
|
|
43241
|
-
plan: { provider: CLAUDE, model: OPUS, effort: "max" },
|
|
43242
|
-
implement: {
|
|
43243
|
-
generator: { provider: CLAUDE, model: OPUS, effort: "max" },
|
|
43244
|
-
evaluator: { provider: CLAUDE, model: OPUS, effort: "max" }
|
|
43245
|
-
},
|
|
43246
|
-
readiness: { provider: CLAUDE, model: OPUS, effort: "high" },
|
|
43247
|
-
ideate: { provider: CLAUDE, model: OPUS },
|
|
43248
|
-
createPr: { provider: CLAUDE, model: OPUS }
|
|
43249
|
-
};
|
|
43250
|
-
var COPILOT_FRONTIER = {
|
|
43251
|
-
effort: "max",
|
|
43252
|
-
refine: { provider: COPILOT, model: COPILOT_OPUS },
|
|
43253
|
-
plan: { provider: COPILOT, model: COPILOT_OPUS, effort: "max" },
|
|
43254
|
-
implement: {
|
|
43255
|
-
generator: { provider: COPILOT, model: COPILOT_OPUS, effort: "max" },
|
|
43256
|
-
evaluator: { provider: COPILOT, model: COPILOT_OPUS, effort: "max" }
|
|
43257
|
-
},
|
|
43258
|
-
readiness: { provider: COPILOT, model: COPILOT_OPUS, effort: "high" },
|
|
43259
|
-
ideate: { provider: COPILOT, model: COPILOT_OPUS },
|
|
43260
|
-
createPr: { provider: COPILOT, model: COPILOT_OPUS }
|
|
43261
|
-
};
|
|
43262
|
-
var CODEX_FRONTIER = {
|
|
43263
|
-
effort: "max",
|
|
43264
|
-
refine: { provider: CODEX, model: GPT_5_6_SOL2 },
|
|
43265
|
-
plan: { provider: CODEX, model: GPT_5_6_SOL2, effort: "max" },
|
|
43266
|
-
implement: {
|
|
43267
|
-
generator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "max" },
|
|
43268
|
-
evaluator: { provider: CODEX, model: GPT_5_6_SOL2, effort: "max" }
|
|
43269
|
-
},
|
|
43270
|
-
readiness: { provider: CODEX, model: GPT_5_6_SOL2, effort: "high" },
|
|
43271
|
-
ideate: { provider: CODEX, model: GPT_5_6_SOL2 },
|
|
43272
|
-
createPr: { provider: CODEX, model: GPT_5_6_SOL2 }
|
|
43273
|
-
};
|
|
43274
43800
|
var PRESETS = {
|
|
43275
43801
|
mixed: { ai: MIXED, escalateOnPlateau: true },
|
|
43276
43802
|
"claude-only": { ai: CLAUDE_ONLY, escalateOnPlateau: true },
|
|
@@ -43282,18 +43808,22 @@ var PRESETS = {
|
|
|
43282
43808
|
"claude-economic": { ai: CLAUDE_ECONOMIC, escalateOnPlateau: true, bestOfNCandidates: 0 },
|
|
43283
43809
|
"copilot-economic": { ai: COPILOT_ECONOMIC, escalateOnPlateau: true, bestOfNCandidates: 0 },
|
|
43284
43810
|
"codex-economic": { ai: CODEX_ECONOMIC, escalateOnPlateau: true, bestOfNCandidates: 0 },
|
|
43811
|
+
"grok-economic": { ai: GROK_ECONOMIC, escalateOnPlateau: true, bestOfNCandidates: 0 },
|
|
43285
43812
|
"mixed-strong-gate": { ai: MIXED_STRONG_GATE, escalateOnPlateau: true },
|
|
43286
43813
|
"claude-strong-gate": { ai: CLAUDE_STRONG_GATE, escalateOnPlateau: true },
|
|
43287
43814
|
"copilot-strong-gate": { ai: COPILOT_STRONG_GATE, escalateOnPlateau: true },
|
|
43288
43815
|
"codex-strong-gate": { ai: CODEX_STRONG_GATE, escalateOnPlateau: true },
|
|
43816
|
+
"grok-strong-gate": { ai: GROK_STRONG_GATE, escalateOnPlateau: true },
|
|
43289
43817
|
"mixed-fast": { ai: MIXED_FAST, escalateOnPlateau: false },
|
|
43290
43818
|
"claude-fast": { ai: CLAUDE_FAST, escalateOnPlateau: false },
|
|
43291
43819
|
"copilot-fast": { ai: COPILOT_FAST, escalateOnPlateau: false },
|
|
43292
43820
|
"codex-fast": { ai: CODEX_FAST, escalateOnPlateau: false },
|
|
43821
|
+
"grok-fast": { ai: GROK_FAST, escalateOnPlateau: false },
|
|
43293
43822
|
"mixed-frontier": { ai: MIXED_FRONTIER, escalateOnPlateau: true },
|
|
43294
43823
|
"claude-frontier": { ai: CLAUDE_FRONTIER, escalateOnPlateau: true },
|
|
43295
43824
|
"copilot-frontier": { ai: COPILOT_FRONTIER, escalateOnPlateau: true },
|
|
43296
|
-
"codex-frontier": { ai: CODEX_FRONTIER, escalateOnPlateau: true }
|
|
43825
|
+
"codex-frontier": { ai: CODEX_FRONTIER, escalateOnPlateau: true },
|
|
43826
|
+
"grok-frontier": { ai: GROK_FRONTIER, escalateOnPlateau: true }
|
|
43297
43827
|
};
|
|
43298
43828
|
var applyPreset = (name, current) => {
|
|
43299
43829
|
const preset = PRESETS[name];
|
|
@@ -43321,18 +43851,22 @@ var PRESET_LABEL = {
|
|
|
43321
43851
|
"claude-economic": "Apply: Claude (economic)",
|
|
43322
43852
|
"copilot-economic": "Apply: Copilot (economic)",
|
|
43323
43853
|
"codex-economic": "Apply: Codex (economic)",
|
|
43854
|
+
"grok-economic": "Apply: Grok (economic)",
|
|
43324
43855
|
"mixed-strong-gate": "Apply: Mixed strong-gate",
|
|
43325
43856
|
"claude-strong-gate": "Apply: Claude strong-gate",
|
|
43326
43857
|
"copilot-strong-gate": "Apply: Copilot strong-gate",
|
|
43327
43858
|
"codex-strong-gate": "Apply: Codex strong-gate",
|
|
43859
|
+
"grok-strong-gate": "Apply: Grok strong-gate",
|
|
43328
43860
|
"mixed-fast": "Apply: Mixed (fast)",
|
|
43329
43861
|
"claude-fast": "Apply: Claude (fast)",
|
|
43330
43862
|
"copilot-fast": "Apply: Copilot (fast)",
|
|
43331
43863
|
"codex-fast": "Apply: Codex (fast)",
|
|
43864
|
+
"grok-fast": "Apply: Grok (fast)",
|
|
43332
43865
|
"mixed-frontier": "Apply: Mixed (frontier)",
|
|
43333
43866
|
"claude-frontier": "Apply: Claude (frontier)",
|
|
43334
43867
|
"copilot-frontier": "Apply: Copilot (frontier)",
|
|
43335
|
-
"codex-frontier": "Apply: Codex (frontier)"
|
|
43868
|
+
"codex-frontier": "Apply: Codex (frontier)",
|
|
43869
|
+
"grok-frontier": "Apply: Grok (frontier)"
|
|
43336
43870
|
};
|
|
43337
43871
|
var PRESET_FAMILY_LABEL = {
|
|
43338
43872
|
standard: "Standard",
|
|
@@ -43353,18 +43887,22 @@ var PRESET_FAMILY = {
|
|
|
43353
43887
|
"claude-economic": "economic",
|
|
43354
43888
|
"copilot-economic": "economic",
|
|
43355
43889
|
"codex-economic": "economic",
|
|
43890
|
+
"grok-economic": "economic",
|
|
43356
43891
|
"mixed-strong-gate": STRONG_GATE,
|
|
43357
43892
|
"claude-strong-gate": STRONG_GATE,
|
|
43358
43893
|
"copilot-strong-gate": STRONG_GATE,
|
|
43359
43894
|
"codex-strong-gate": STRONG_GATE,
|
|
43895
|
+
"grok-strong-gate": STRONG_GATE,
|
|
43360
43896
|
"mixed-fast": "fast",
|
|
43361
43897
|
"claude-fast": "fast",
|
|
43362
43898
|
"copilot-fast": "fast",
|
|
43363
43899
|
"codex-fast": "fast",
|
|
43900
|
+
"grok-fast": "fast",
|
|
43364
43901
|
"mixed-frontier": "frontier",
|
|
43365
43902
|
"claude-frontier": "frontier",
|
|
43366
43903
|
"copilot-frontier": "frontier",
|
|
43367
|
-
"codex-frontier": "frontier"
|
|
43904
|
+
"codex-frontier": "frontier",
|
|
43905
|
+
"grok-frontier": "frontier"
|
|
43368
43906
|
};
|
|
43369
43907
|
var LOG_LEVELS = ["silent", "debug", "info", "warn", "error"];
|
|
43370
43908
|
var DEFAULT_TOKEN = "Default";
|
|
@@ -43390,12 +43928,11 @@ var escalationTargetsFor = (from) => {
|
|
|
43390
43928
|
const pool = owning.length > 0 ? owning.flat() : MODEL_CATALOGS.flat();
|
|
43391
43929
|
return [...new Set(pool)].filter((m) => m !== from);
|
|
43392
43930
|
};
|
|
43393
|
-
var
|
|
43394
|
-
const merged = mergeEscalationMap(user);
|
|
43931
|
+
var chainsOf = (provider, merged, user, isRoot) => {
|
|
43395
43932
|
const targets = new Set(Object.values(merged));
|
|
43396
43933
|
const chains = [];
|
|
43397
43934
|
for (const root of Object.keys(merged)) {
|
|
43398
|
-
if (targets.has(root)) continue;
|
|
43935
|
+
if (targets.has(root) || !isRoot(root)) continue;
|
|
43399
43936
|
const models = [root];
|
|
43400
43937
|
const seen = /* @__PURE__ */ new Set([root]);
|
|
43401
43938
|
let customised = root in user;
|
|
@@ -43408,10 +43945,19 @@ var effectiveEscalationChains = (user) => {
|
|
|
43408
43945
|
prev = cur;
|
|
43409
43946
|
cur = merged[cur];
|
|
43410
43947
|
}
|
|
43411
|
-
chains.push({ models, customised });
|
|
43948
|
+
chains.push({ provider, models, customised });
|
|
43412
43949
|
}
|
|
43413
43950
|
return chains;
|
|
43414
43951
|
};
|
|
43952
|
+
var effectiveEscalationChains = (user) => {
|
|
43953
|
+
const perProvider = AI_PROVIDERS2.flatMap((provider) => {
|
|
43954
|
+
const catalog = new Set(PROVIDER_TRAITS[provider].modelCatalog);
|
|
43955
|
+
return chainsOf(provider, mergeEscalationMap(user, provider), user, (m) => catalog.has(m));
|
|
43956
|
+
});
|
|
43957
|
+
const catalogued = new Set(MODEL_CATALOGS.flat());
|
|
43958
|
+
const custom = chainsOf(void 0, mergeEscalationMap(user, void 0), user, (m) => !catalogued.has(m));
|
|
43959
|
+
return [...perProvider, ...custom];
|
|
43960
|
+
};
|
|
43415
43961
|
var modelOptionsFor = (provider) => PROVIDER_TRAITS[provider].modelCatalog;
|
|
43416
43962
|
var capitalize = (s) => s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
|
|
43417
43963
|
var FLOW_DISPLAY_LABEL = { createPr: "Create-PR" };
|
|
@@ -43971,6 +44517,8 @@ var applyFixedSettingsKey = (current, key2, raw) => {
|
|
|
43971
44517
|
return Result.ok({ ...current, logging: { level: raw } });
|
|
43972
44518
|
case "concurrency.maxParallelTasks":
|
|
43973
44519
|
return applyNumberField(current, key2, raw, (c, n) => ({ ...c, concurrency: { maxParallelTasks: n } }));
|
|
44520
|
+
// Key is still addressable so existing settings files and `settings set` keep parsing;
|
|
44521
|
+
// the flag does not post a comment.
|
|
43974
44522
|
case "scm.postRefinementComment":
|
|
43975
44523
|
return applyBooleanField(current, key2, raw, (c, b) => ({
|
|
43976
44524
|
...c,
|
|
@@ -44176,9 +44724,11 @@ var HarnessRow = ({ title, fields, valueFor }) => {
|
|
|
44176
44724
|
] }),
|
|
44177
44725
|
chains.map((chain) => /* @__PURE__ */ jsxs69(Text68, { dimColor: true, children: [
|
|
44178
44726
|
" ",
|
|
44727
|
+
chain.provider ?? "any provider",
|
|
44728
|
+
": ",
|
|
44179
44729
|
chain.models.join(` ${glyphs.arrowRight} `),
|
|
44180
44730
|
chain.customised ? " (customised)" : ""
|
|
44181
|
-
] }, chain.models[0]))
|
|
44731
|
+
] }, `${chain.provider ?? "custom"}:${chain.models[0] ?? ""}`))
|
|
44182
44732
|
] })
|
|
44183
44733
|
] });
|
|
44184
44734
|
};
|
|
@@ -45133,7 +45683,7 @@ import "react";
|
|
|
45133
45683
|
import { Box as Box78, Text as Text74 } from "ink";
|
|
45134
45684
|
|
|
45135
45685
|
// src/application/ui/tui/runtime/use-markdown-export.ts
|
|
45136
|
-
import { useCallback as useCallback18, useEffect as useEffect37, useRef as
|
|
45686
|
+
import { useCallback as useCallback18, useEffect as useEffect37, useRef as useRef17, useState as useState41 } from "react";
|
|
45137
45687
|
import { join as join81 } from "path";
|
|
45138
45688
|
import { useInput as useInput22 } from "ink";
|
|
45139
45689
|
var useMarkdownExport = (config) => {
|
|
@@ -45141,10 +45691,10 @@ var useMarkdownExport = (config) => {
|
|
|
45141
45691
|
const selection = useSelection();
|
|
45142
45692
|
const ui = useUiState();
|
|
45143
45693
|
const [run, setRun] = useState41({ kind: "idle" });
|
|
45144
|
-
const runGenRef =
|
|
45145
|
-
const runFnRef =
|
|
45694
|
+
const runGenRef = useRef17(0);
|
|
45695
|
+
const runFnRef = useRef17(config.run);
|
|
45146
45696
|
runFnRef.current = config.run;
|
|
45147
|
-
const filenameRef =
|
|
45697
|
+
const filenameRef = useRef17(config.filename);
|
|
45148
45698
|
filenameRef.current = config.filename;
|
|
45149
45699
|
useViewHints([{ keys: "r", label: "rerun" }]);
|
|
45150
45700
|
const runExport = useCallback18(async () => {
|
|
@@ -45945,6 +46495,7 @@ var generatePrContentLeaf = (deps) => leaf(LEAF_NAME11, {
|
|
|
45945
46495
|
cwd: input.unitRoot,
|
|
45946
46496
|
additionalRoots: [input.repoPath],
|
|
45947
46497
|
model: deps.model,
|
|
46498
|
+
...deps.effort !== void 0 ? { effort: deps.effort } : {},
|
|
45948
46499
|
permissions: PR_AUTHORING_PERMISSIONS,
|
|
45949
46500
|
signalsFile: signalsFilePathResult.value,
|
|
45950
46501
|
outputDir: input.unitRoot,
|
|
@@ -45996,11 +46547,11 @@ var createCreatePrFlow = (deps, opts = {}) => {
|
|
|
45996
46547
|
outputContractSection: renderContractSectionFor(generatePrContentOutputContract, currentUnitRoot)
|
|
45997
46548
|
});
|
|
45998
46549
|
},
|
|
45999
|
-
//
|
|
46000
|
-
// (see `CreateCreatePrFlowOpts.providerId`
|
|
46001
|
-
// failing the sidecar write.
|
|
46550
|
+
// The CLI / TUI surfaces thread `settings.ai.createPr.provider`; a caller that omits it
|
|
46551
|
+
// (see `CreateCreatePrFlowOpts.providerId`) gets a placeholder rather than a failed write.
|
|
46002
46552
|
providerId: opts.providerId ?? "unknown",
|
|
46003
|
-
model: deps.model
|
|
46553
|
+
model: deps.model,
|
|
46554
|
+
...deps.effort !== void 0 ? { effort: deps.effort } : {}
|
|
46004
46555
|
};
|
|
46005
46556
|
children.push(
|
|
46006
46557
|
createLoadCreatePrContextLeaf(deps),
|
|
@@ -46019,7 +46570,8 @@ var createCreatePrFlow = (deps, opts = {}) => {
|
|
|
46019
46570
|
writeFile: deps.writeFile,
|
|
46020
46571
|
eventBus: deps.eventBus,
|
|
46021
46572
|
logger: deps.logger,
|
|
46022
|
-
model: deps.model
|
|
46573
|
+
model: deps.model,
|
|
46574
|
+
...deps.effort !== void 0 ? { effort: deps.effort } : {}
|
|
46023
46575
|
}),
|
|
46024
46576
|
...aiUnitEpilogue({ skillsAdapter: deps.skillsAdapter }, unitOpts)
|
|
46025
46577
|
);
|
|
@@ -46131,6 +46683,7 @@ var resolveCreatePrInputs = async (deps, sprintId, useAi) => {
|
|
|
46131
46683
|
var executeCreatePrFlow = async (args) => {
|
|
46132
46684
|
const { deps, sprintId, sprintDir: sprintDir2, cwd, useAi } = args;
|
|
46133
46685
|
const resolvedProvider = deps.settings.ai.createPr.provider;
|
|
46686
|
+
const effort = resolveEffort("createPr", deps.settings);
|
|
46134
46687
|
const provider = createAiProvider({
|
|
46135
46688
|
flow: "createPr",
|
|
46136
46689
|
ai: deps.settings.ai,
|
|
@@ -46160,10 +46713,11 @@ var executeCreatePrFlow = async (args) => {
|
|
|
46160
46713
|
writeFile: deps.writeFile,
|
|
46161
46714
|
logger: deps.logger,
|
|
46162
46715
|
model: deps.settings.ai.createPr.model,
|
|
46716
|
+
...effort !== void 0 ? { effort } : {},
|
|
46163
46717
|
skillSource,
|
|
46164
46718
|
skillsAdapter
|
|
46165
46719
|
},
|
|
46166
|
-
{ useAi }
|
|
46720
|
+
{ useAi, providerId: resolvedProvider }
|
|
46167
46721
|
);
|
|
46168
46722
|
const result = await flow.execute({
|
|
46169
46723
|
input: {
|
|
@@ -46243,7 +46797,7 @@ var renderBody2 = (prep, run, useAi) => {
|
|
|
46243
46797
|
};
|
|
46244
46798
|
|
|
46245
46799
|
// src/application/ui/tui/views/welcome-view.tsx
|
|
46246
|
-
import { useCallback as useCallback20, useEffect as useEffect39, useRef as
|
|
46800
|
+
import { useCallback as useCallback20, useEffect as useEffect39, useRef as useRef18, useState as useState43 } from "react";
|
|
46247
46801
|
import { Box as Box80, Text as Text76, useInput as useInput24 } from "ink";
|
|
46248
46802
|
import { jsx as jsx101, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
46249
46803
|
var PRESET_FOR_PROVIDER = {
|
|
@@ -46275,7 +46829,7 @@ var useWelcomeSeeding = () => {
|
|
|
46275
46829
|
const [noCliDetected, setNoCliDetected] = useState43(false);
|
|
46276
46830
|
const [errorMsg, setErrorMsg] = useState43(void 0);
|
|
46277
46831
|
const [pendingRoute, setPendingRoute] = useState43(void 0);
|
|
46278
|
-
const seededRef =
|
|
46832
|
+
const seededRef = useRef18(false);
|
|
46279
46833
|
useEffect39(() => {
|
|
46280
46834
|
if (seededRef.current) return;
|
|
46281
46835
|
seededRef.current = true;
|
|
@@ -46967,12 +47521,67 @@ var createTicketAddFlow = (deps) => leaf("add-ticket", {
|
|
|
46967
47521
|
if (!updated.ok) return Result.error(updated.error);
|
|
46968
47522
|
const saved = await deps.sprintRepo.save(updated.value);
|
|
46969
47523
|
if (!saved.ok) return Result.error(saved.error);
|
|
46970
|
-
|
|
47524
|
+
if (input.createTrackerIssue !== true) {
|
|
47525
|
+
return Result.ok({ ticket: ticket.value });
|
|
47526
|
+
}
|
|
47527
|
+
const published = await publishAfterSave(deps, updated.value, ticket.value);
|
|
47528
|
+
return Result.ok(published);
|
|
46971
47529
|
}
|
|
46972
47530
|
},
|
|
46973
47531
|
input: (c) => c.input,
|
|
46974
|
-
output: (c, o) => ({
|
|
47532
|
+
output: (c, o) => ({
|
|
47533
|
+
...c,
|
|
47534
|
+
output: o.ticket,
|
|
47535
|
+
...o.trackerError !== void 0 ? { trackerError: o.trackerError } : {},
|
|
47536
|
+
...o.trackerIssueOrphaned === true ? { trackerIssueOrphaned: true } : {}
|
|
47537
|
+
})
|
|
46975
47538
|
});
|
|
47539
|
+
var publishAfterSave = async (deps, sprint, ticket) => {
|
|
47540
|
+
const tracker = deps.issuePusher;
|
|
47541
|
+
const projectRepo = deps.projectRepo;
|
|
47542
|
+
if (tracker === void 0 || projectRepo === void 0) {
|
|
47543
|
+
return {
|
|
47544
|
+
ticket,
|
|
47545
|
+
trackerError: new StorageError({
|
|
47546
|
+
subCode: "io",
|
|
47547
|
+
message: "issue tracker is unavailable"
|
|
47548
|
+
})
|
|
47549
|
+
};
|
|
47550
|
+
}
|
|
47551
|
+
const project = await projectRepo.findById(sprint.projectId);
|
|
47552
|
+
if (!project.ok) {
|
|
47553
|
+
return { ticket, trackerError: project.error };
|
|
47554
|
+
}
|
|
47555
|
+
const cwd = project.value.repositories[0]?.path;
|
|
47556
|
+
if (cwd === void 0) {
|
|
47557
|
+
return {
|
|
47558
|
+
ticket,
|
|
47559
|
+
trackerError: new StorageError({
|
|
47560
|
+
subCode: "io",
|
|
47561
|
+
message: "Project has no repositories \u2014 add one first."
|
|
47562
|
+
})
|
|
47563
|
+
};
|
|
47564
|
+
}
|
|
47565
|
+
const published = await publishTicketToTracker({
|
|
47566
|
+
sprint,
|
|
47567
|
+
ticketId: ticket.id,
|
|
47568
|
+
cwd,
|
|
47569
|
+
issuePusher: tracker
|
|
47570
|
+
});
|
|
47571
|
+
if (!published.ok) {
|
|
47572
|
+
return { ticket, trackerError: published.error };
|
|
47573
|
+
}
|
|
47574
|
+
const relinked = await deps.sprintRepo.save(published.value.sprint);
|
|
47575
|
+
if (!relinked.ok) {
|
|
47576
|
+
return {
|
|
47577
|
+
ticket,
|
|
47578
|
+
trackerError: publishSaveFailedError(published.value, ticket.id, relinked.error),
|
|
47579
|
+
...published.value.outcome === "created" ? { trackerIssueOrphaned: true } : {}
|
|
47580
|
+
};
|
|
47581
|
+
}
|
|
47582
|
+
const withLink = published.value.sprint.tickets.find((t) => t.id === ticket.id) ?? ticket;
|
|
47583
|
+
return { ticket: withLink };
|
|
47584
|
+
};
|
|
46976
47585
|
|
|
46977
47586
|
// src/application/ui/tui/views/add-ticket-internals/header-card.tsx
|
|
46978
47587
|
import "react";
|
|
@@ -47010,7 +47619,7 @@ var HeaderCard2 = ({
|
|
|
47010
47619
|
return /* @__PURE__ */ jsx105(Card, { title: "Progress", tone: "rule", children: /* @__PURE__ */ jsx105(Box84, { flexDirection: "column", paddingX: spacing.indent, children: /* @__PURE__ */ jsx105(FieldList, { fields: collected }) }) });
|
|
47011
47620
|
};
|
|
47012
47621
|
var collectedFields = (step) => {
|
|
47013
|
-
if (step.kind === "confirm") return [];
|
|
47622
|
+
if (step.kind === "confirm" || step.kind === "ask-create") return [];
|
|
47014
47623
|
const fields = [];
|
|
47015
47624
|
const linkFor = (s) => {
|
|
47016
47625
|
if (s.kind === "fetching" || s.kind === "fetch-failed" || s.kind === "title" || s.kind === "description") {
|
|
@@ -47057,9 +47666,17 @@ var backStep3 = (step) => {
|
|
|
47057
47666
|
title: step.title,
|
|
47058
47667
|
descriptionInitial: step.description
|
|
47059
47668
|
};
|
|
47669
|
+
case "ask-create":
|
|
47670
|
+
return {
|
|
47671
|
+
kind: "confirm",
|
|
47672
|
+
link: step.link,
|
|
47673
|
+
title: step.title,
|
|
47674
|
+
description: step.description
|
|
47675
|
+
};
|
|
47060
47676
|
case "saving":
|
|
47061
47677
|
case "added":
|
|
47062
47678
|
case "error":
|
|
47679
|
+
case "create-failed":
|
|
47063
47680
|
return void 0;
|
|
47064
47681
|
}
|
|
47065
47682
|
};
|
|
@@ -47228,6 +47845,17 @@ var renderConfirmStep2 = (step, ctx, onSubmit) => {
|
|
|
47228
47845
|
) })
|
|
47229
47846
|
] });
|
|
47230
47847
|
};
|
|
47848
|
+
var renderAskCreateStep = (step, ctx, onSubmit) => /* @__PURE__ */ jsx107(Box86, { flexDirection: "column", paddingX: spacing.indent, children: /* @__PURE__ */ jsx107(
|
|
47849
|
+
ConfirmPrompt,
|
|
47850
|
+
{
|
|
47851
|
+
message: "Create a tracker issue?",
|
|
47852
|
+
defaultYes: false,
|
|
47853
|
+
onSubmit: (value) => {
|
|
47854
|
+
void onSubmit({ ...step, createTrackerIssue: value });
|
|
47855
|
+
},
|
|
47856
|
+
onCancel: ctx.cancelOrBack
|
|
47857
|
+
}
|
|
47858
|
+
) });
|
|
47231
47859
|
var renderSavingStep = () => /* @__PURE__ */ jsx107(Spinner, { label: "saving sprint\u2026" });
|
|
47232
47860
|
var renderAddedStep = (step, onChange, onCancel) => {
|
|
47233
47861
|
const plural4 = step.count === 1 ? "ticket" : "tickets";
|
|
@@ -47255,12 +47883,43 @@ var renderAddedStep = (step, onChange, onCancel) => {
|
|
|
47255
47883
|
) })
|
|
47256
47884
|
] });
|
|
47257
47885
|
};
|
|
47258
|
-
var renderErrorStep2 = (step) => /* @__PURE__ */ jsxs82(Box86, { flexDirection: "column", paddingX: spacing.indent, children: [
|
|
47886
|
+
var renderErrorStep2 = (step, onChange, onCancel) => /* @__PURE__ */ jsxs82(Box86, { flexDirection: "column", paddingX: spacing.indent, children: [
|
|
47259
47887
|
/* @__PURE__ */ jsxs82(Text82, { color: inkColors.error, children: [
|
|
47260
|
-
|
|
47888
|
+
glyphs.cross,
|
|
47889
|
+
" ",
|
|
47890
|
+
step.message
|
|
47891
|
+
] }),
|
|
47892
|
+
/* @__PURE__ */ jsx107(Text82, { dimColor: true, children: "Nothing was saved." }),
|
|
47893
|
+
/* @__PURE__ */ jsx107(Box86, { marginTop: spacing.section, children: /* @__PURE__ */ jsx107(
|
|
47894
|
+
ConfirmPrompt,
|
|
47895
|
+
{
|
|
47896
|
+
message: "Start over with a new ticket?",
|
|
47897
|
+
onSubmit: (value) => {
|
|
47898
|
+
if (value) onChange({ kind: "link" });
|
|
47899
|
+
else onCancel();
|
|
47900
|
+
},
|
|
47901
|
+
onCancel
|
|
47902
|
+
}
|
|
47903
|
+
) })
|
|
47904
|
+
] });
|
|
47905
|
+
var renderCreateFailedStep = (step, onChange, onCancel) => /* @__PURE__ */ jsxs82(Box86, { flexDirection: "column", paddingX: spacing.indent, children: [
|
|
47906
|
+
/* @__PURE__ */ jsxs82(Text82, { color: inkColors.error, children: [
|
|
47907
|
+
glyphs.cross,
|
|
47908
|
+
" ",
|
|
47261
47909
|
step.message
|
|
47262
47910
|
] }),
|
|
47263
|
-
/* @__PURE__ */ jsx107(Text82, { dimColor: true, children:
|
|
47911
|
+
/* @__PURE__ */ jsx107(Text82, { dimColor: true, children: step.hint }),
|
|
47912
|
+
/* @__PURE__ */ jsx107(Box86, { marginTop: spacing.section, children: /* @__PURE__ */ jsx107(
|
|
47913
|
+
ConfirmPrompt,
|
|
47914
|
+
{
|
|
47915
|
+
message: "Add another ticket?",
|
|
47916
|
+
onSubmit: (value) => {
|
|
47917
|
+
if (value) onChange({ kind: "link" });
|
|
47918
|
+
else onCancel();
|
|
47919
|
+
},
|
|
47920
|
+
onCancel
|
|
47921
|
+
}
|
|
47922
|
+
) })
|
|
47264
47923
|
] });
|
|
47265
47924
|
var StepView3 = ({ step, onChange, onCancel, onSubmit }) => {
|
|
47266
47925
|
const prev = backStep3(step);
|
|
@@ -47280,12 +47939,16 @@ var StepView3 = ({ step, onChange, onCancel, onSubmit }) => {
|
|
|
47280
47939
|
return renderDescriptionStep2(step, ctx);
|
|
47281
47940
|
case "confirm":
|
|
47282
47941
|
return renderConfirmStep2(step, ctx, onSubmit);
|
|
47942
|
+
case "ask-create":
|
|
47943
|
+
return renderAskCreateStep(step, ctx, onSubmit);
|
|
47283
47944
|
case "saving":
|
|
47284
47945
|
return renderSavingStep();
|
|
47285
47946
|
case "added":
|
|
47286
47947
|
return renderAddedStep(step, onChange, onCancel);
|
|
47287
47948
|
case "error":
|
|
47288
|
-
return renderErrorStep2(step);
|
|
47949
|
+
return renderErrorStep2(step, onChange, onCancel);
|
|
47950
|
+
case "create-failed":
|
|
47951
|
+
return renderCreateFailedStep(step, onChange, onCancel);
|
|
47289
47952
|
}
|
|
47290
47953
|
};
|
|
47291
47954
|
var runFetch = async (fetcher, url) => {
|
|
@@ -47304,6 +47967,58 @@ var runFetch = async (fetcher, url) => {
|
|
|
47304
47967
|
|
|
47305
47968
|
// src/application/ui/tui/views/add-ticket-view.tsx
|
|
47306
47969
|
import { jsx as jsx108, jsxs as jsxs83 } from "react/jsx-runtime";
|
|
47970
|
+
var originResolves = async (deps, sprintId) => {
|
|
47971
|
+
const pusher = deps.issuePusher;
|
|
47972
|
+
if (pusher === void 0) return false;
|
|
47973
|
+
const sprint = await deps.sprintRepo.findById(sprintId);
|
|
47974
|
+
if (!sprint.ok) return false;
|
|
47975
|
+
const project = await deps.projectRepo?.findById(sprint.value.projectId);
|
|
47976
|
+
if (project === void 0 || !project.ok) return false;
|
|
47977
|
+
const cwd = project.value.repositories[0]?.path;
|
|
47978
|
+
if (cwd === void 0) return false;
|
|
47979
|
+
const origin = await pusher.resolveOrigin(cwd);
|
|
47980
|
+
return origin.ok && origin.value !== null;
|
|
47981
|
+
};
|
|
47982
|
+
var createFailedHint = (sprintId, ticketId, orphaned) => {
|
|
47983
|
+
if (orphaned) return "The ticket was saved locally without the link \u2014 do not re-publish it.";
|
|
47984
|
+
const target = ticketId ?? "<ticket-id>";
|
|
47985
|
+
return `The ticket was saved locally \u2014 retry with: ralphctl ticket publish --sprint ${String(sprintId)} ${target}`;
|
|
47986
|
+
};
|
|
47987
|
+
var persistTicket = async (deps, sprintId, draft) => {
|
|
47988
|
+
const description = draft.description.trim();
|
|
47989
|
+
const link = draft.link.trim();
|
|
47990
|
+
const flow = createTicketAddFlow({
|
|
47991
|
+
sprintRepo: deps.sprintRepo,
|
|
47992
|
+
...deps.projectRepo !== void 0 ? { projectRepo: deps.projectRepo } : {},
|
|
47993
|
+
...deps.issuePusher !== void 0 ? { issuePusher: deps.issuePusher } : {}
|
|
47994
|
+
});
|
|
47995
|
+
const result = await flow.execute({
|
|
47996
|
+
input: {
|
|
47997
|
+
sprintId,
|
|
47998
|
+
title: draft.title.trim(),
|
|
47999
|
+
...description.length > 0 ? { description } : {},
|
|
48000
|
+
...link.length > 0 ? { link } : {},
|
|
48001
|
+
...draft.createTrackerIssue === true ? { createTrackerIssue: true } : {}
|
|
48002
|
+
}
|
|
48003
|
+
});
|
|
48004
|
+
if (!result.ok) {
|
|
48005
|
+
return { kind: "error", message: result.error.error.message };
|
|
48006
|
+
}
|
|
48007
|
+
const trackerError = result.value.ctx.trackerError;
|
|
48008
|
+
if (trackerError !== void 0) {
|
|
48009
|
+
const ticketId = result.value.ctx.output?.id;
|
|
48010
|
+
return {
|
|
48011
|
+
kind: "create-failed",
|
|
48012
|
+
message: trackerError.message,
|
|
48013
|
+
hint: createFailedHint(
|
|
48014
|
+
sprintId,
|
|
48015
|
+
ticketId !== void 0 ? String(ticketId) : void 0,
|
|
48016
|
+
result.value.ctx.trackerIssueOrphaned === true
|
|
48017
|
+
)
|
|
48018
|
+
};
|
|
48019
|
+
}
|
|
48020
|
+
return { kind: "added" };
|
|
48021
|
+
};
|
|
47307
48022
|
var AddTicketView = () => {
|
|
47308
48023
|
const deps = useDeps();
|
|
47309
48024
|
const router = useRouter();
|
|
@@ -47330,28 +48045,36 @@ var AddTicketView = () => {
|
|
|
47330
48045
|
cancelled = true;
|
|
47331
48046
|
};
|
|
47332
48047
|
}, [step, deps.issueFetcher]);
|
|
47333
|
-
const
|
|
48048
|
+
const persist = async (draft) => {
|
|
47334
48049
|
setStep({ kind: "saving" });
|
|
47335
|
-
const
|
|
47336
|
-
|
|
47337
|
-
|
|
47338
|
-
|
|
47339
|
-
input: {
|
|
47340
|
-
sprintId,
|
|
47341
|
-
title: s.title.trim(),
|
|
47342
|
-
...description.length > 0 ? { description } : {},
|
|
47343
|
-
...link.length > 0 ? { link } : {}
|
|
47344
|
-
}
|
|
47345
|
-
});
|
|
47346
|
-
if (!result.ok) {
|
|
47347
|
-
setStep({ kind: "error", message: result.error.error.message });
|
|
48050
|
+
const outcome = await persistTicket(deps, sprintId, draft);
|
|
48051
|
+
if (outcome.kind === "create-failed") {
|
|
48052
|
+
setAddedCount((prev) => prev + 1);
|
|
48053
|
+
setStep(outcome);
|
|
47348
48054
|
return;
|
|
47349
48055
|
}
|
|
47350
|
-
|
|
47351
|
-
|
|
47352
|
-
|
|
47353
|
-
|
|
47354
|
-
|
|
48056
|
+
if (outcome.kind === "added") {
|
|
48057
|
+
setAddedCount((prev) => {
|
|
48058
|
+
const count2 = prev + 1;
|
|
48059
|
+
setStep({ kind: "added", title: draft.title.trim(), count: count2 });
|
|
48060
|
+
return count2;
|
|
48061
|
+
});
|
|
48062
|
+
return;
|
|
48063
|
+
}
|
|
48064
|
+
setStep(outcome);
|
|
48065
|
+
};
|
|
48066
|
+
const submit = async (draft) => {
|
|
48067
|
+
const shouldAsk = draft.createTrackerIssue === void 0 && draft.link.trim().length === 0 && await originResolves(deps, sprintId);
|
|
48068
|
+
if (shouldAsk) {
|
|
48069
|
+
setStep({
|
|
48070
|
+
kind: "ask-create",
|
|
48071
|
+
link: draft.link,
|
|
48072
|
+
title: draft.title,
|
|
48073
|
+
description: draft.description
|
|
48074
|
+
});
|
|
48075
|
+
return;
|
|
48076
|
+
}
|
|
48077
|
+
await persist(draft);
|
|
47355
48078
|
};
|
|
47356
48079
|
return /* @__PURE__ */ jsx108(ViewShell, { title: "Add ticket", subtitle: "Append a pending ticket to the current sprint.", children: /* @__PURE__ */ jsxs83(Box87, { flexDirection: "column", children: [
|
|
47357
48080
|
/* @__PURE__ */ jsx108(HeaderCard2, { step, addedCount }),
|
|
@@ -47949,7 +48672,7 @@ var renderView = (entry) => {
|
|
|
47949
48672
|
};
|
|
47950
48673
|
|
|
47951
48674
|
// src/application/ui/tui/runtime/use-global-keys.ts
|
|
47952
|
-
import { useEffect as useEffect45, useMemo as useMemo33, useRef as
|
|
48675
|
+
import { useEffect as useEffect45, useMemo as useMemo33, useRef as useRef19 } from "react";
|
|
47953
48676
|
import { useApp, useInput as useInput29 } from "ink";
|
|
47954
48677
|
|
|
47955
48678
|
// src/integration/io/clipboard.ts
|
|
@@ -48059,7 +48782,7 @@ var useGlobalKeys = (opts = {}) => {
|
|
|
48059
48782
|
() => opts.copyToClipboard ?? createCopyToClipboard(),
|
|
48060
48783
|
[opts.copyToClipboard]
|
|
48061
48784
|
);
|
|
48062
|
-
const clearTimerRef =
|
|
48785
|
+
const clearTimerRef = useRef19(void 0);
|
|
48063
48786
|
useEffect45(
|
|
48064
48787
|
() => () => {
|
|
48065
48788
|
if (clearTimerRef.current !== void 0) clearTimeout(clearTimerRef.current);
|
|
@@ -48971,7 +49694,7 @@ import { useState as useState57 } from "react";
|
|
|
48971
49694
|
import { useApp as useApp2 } from "ink";
|
|
48972
49695
|
|
|
48973
49696
|
// src/application/ui/tui/migration/migration-gate.tsx
|
|
48974
|
-
import { useEffect as useEffect51, useRef as
|
|
49697
|
+
import { useEffect as useEffect51, useRef as useRef20, useState as useState56 } from "react";
|
|
48975
49698
|
import { Box as Box97, Text as Text91, useInput as useInput31 } from "ink";
|
|
48976
49699
|
|
|
48977
49700
|
// src/application/ui/tui/migration/learnings-backfill-adapter.ts
|
|
@@ -49018,7 +49741,7 @@ var summarize = (report) => {
|
|
|
49018
49741
|
var useMigrationScan = (args) => {
|
|
49019
49742
|
const { engine, dataRoot, stateRoot, appVersion, now, writeFile: writeFile4, onResolve } = args;
|
|
49020
49743
|
const [state, setState] = useState56({ kind: "scanning" });
|
|
49021
|
-
const scannedRef =
|
|
49744
|
+
const scannedRef = useRef20(false);
|
|
49022
49745
|
useEffect51(() => {
|
|
49023
49746
|
if (scannedRef.current) return;
|
|
49024
49747
|
scannedRef.current = true;
|
|
@@ -50590,6 +51313,7 @@ var registerExportContextCommand = (program) => {
|
|
|
50590
51313
|
// src/application/ui/cli/commands/create-pr.ts
|
|
50591
51314
|
var buildCreatePrFlow = (deps, storage2, useAi) => {
|
|
50592
51315
|
const resolvedProvider = deps.settings.ai.createPr.provider;
|
|
51316
|
+
const effort = resolveEffort("createPr", deps.settings);
|
|
50593
51317
|
const provider = createAiProvider({
|
|
50594
51318
|
flow: "createPr",
|
|
50595
51319
|
ai: deps.settings.ai,
|
|
@@ -50619,10 +51343,11 @@ var buildCreatePrFlow = (deps, storage2, useAi) => {
|
|
|
50619
51343
|
writeFile: deps.writeFile,
|
|
50620
51344
|
logger: deps.logger,
|
|
50621
51345
|
model: deps.settings.ai.createPr.model,
|
|
51346
|
+
...effort !== void 0 ? { effort } : {},
|
|
50622
51347
|
skillSource,
|
|
50623
51348
|
skillsAdapter
|
|
50624
51349
|
},
|
|
50625
|
-
{ useAi }
|
|
51350
|
+
{ useAi, providerId: resolvedProvider }
|
|
50626
51351
|
);
|
|
50627
51352
|
};
|
|
50628
51353
|
var createPrAction = async (opts) => {
|
|
@@ -52109,11 +52834,47 @@ var removeTicketAction = async (rawTicketId, opts) => {
|
|
|
52109
52834
|
`
|
|
52110
52835
|
);
|
|
52111
52836
|
};
|
|
52837
|
+
var publishTicketAction = async (rawTicketId, opts) => {
|
|
52838
|
+
const { deps, storage: storage2 } = await bootstrapCli();
|
|
52839
|
+
const sprintId = await resolveSprintId(opts.sprint, storage2.stateRoot);
|
|
52840
|
+
if (!sprintId.ok) {
|
|
52841
|
+
fail(sprintId.error.message);
|
|
52842
|
+
return;
|
|
52843
|
+
}
|
|
52844
|
+
const ticketId = TicketId.parse(rawTicketId);
|
|
52845
|
+
if (!ticketId.ok) {
|
|
52846
|
+
fail(`invalid ticket id: ${ticketId.error.message}`);
|
|
52847
|
+
return;
|
|
52848
|
+
}
|
|
52849
|
+
if (sprintId.value.fromPin) process.stderr.write(pinFallbackNotice(sprintId.value.sprintId));
|
|
52850
|
+
if (deps.issuePusher === void 0) {
|
|
52851
|
+
fail("issue tracker is unavailable");
|
|
52852
|
+
return;
|
|
52853
|
+
}
|
|
52854
|
+
const flow = createTicketPublishFlow({
|
|
52855
|
+
sprintRepo: deps.sprintRepo,
|
|
52856
|
+
projectRepo: deps.projectRepo,
|
|
52857
|
+
issuePusher: deps.issuePusher
|
|
52858
|
+
});
|
|
52859
|
+
const result = await flow.execute({
|
|
52860
|
+
input: { sprintId: sprintId.value.sprintId, ticketId: ticketId.value }
|
|
52861
|
+
});
|
|
52862
|
+
if (!result.ok) {
|
|
52863
|
+
fail(result.error.error.message);
|
|
52864
|
+
return;
|
|
52865
|
+
}
|
|
52866
|
+
const out = result.value.ctx.output;
|
|
52867
|
+
process.stdout.write(
|
|
52868
|
+
`published ticket ${rawTicketId} on sprint ${String(sprintId.value.sprintId)} \u2014 ${out.outcome}
|
|
52869
|
+
`
|
|
52870
|
+
);
|
|
52871
|
+
};
|
|
52112
52872
|
var registerTicketCommand = (program) => {
|
|
52113
52873
|
const ticketCmd = program.command("ticket").description("inspect and manage tickets within a sprint");
|
|
52114
52874
|
ticketCmd.command("list").description("list every ticket on the sprint").option(SPRINT_OPTION_FLAGS, SPRINT_OPTION_DESC).action(listTicketsAction);
|
|
52115
52875
|
ticketCmd.command("show <ticketId>").description("print a single ticket as JSON").option(SPRINT_OPTION_FLAGS, SPRINT_OPTION_DESC).action(showTicketAction);
|
|
52116
52876
|
ticketCmd.command("add").description("append a pending ticket to a draft sprint").option(SPRINT_OPTION_FLAGS, SPRINT_OPTION_DESC).requiredOption("-t, --title <title>", "ticket title").option("-d, --description <text>", "optional description").option("-l, --link <url>", "optional issue link (http/https)").action(addTicketAction);
|
|
52877
|
+
ticketCmd.command("publish <ticketId>").description("create a tracker issue or post an approved-requirements comment").option(SPRINT_OPTION_FLAGS, SPRINT_OPTION_DESC).action(publishTicketAction);
|
|
52117
52878
|
ticketCmd.command("remove <ticketId>").description("drop a ticket from a draft sprint").option(SPRINT_OPTION_FLAGS, SPRINT_OPTION_DESC).option("-y, --yes", "skip the interactive y/N confirmation").action(removeTicketAction);
|
|
52118
52879
|
};
|
|
52119
52880
|
var formatTicketLine = (t) => {
|