ralphctl 0.8.3 → 0.8.4
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/dist/cli.mjs +588 -343
- package/dist/manifest.json +4 -2
- package/dist/prompts/_partials/conventions-agents-md.md +63 -0
- package/dist/prompts/_partials/conventions-claude-md.md +58 -0
- package/dist/prompts/_partials/conventions-copilot-instructions.md +53 -0
- package/dist/prompts/_partials/decisions.md +4 -0
- package/dist/prompts/_partials/harness-context.md +3 -3
- package/dist/prompts/_partials/validation-checklist.md +3 -2
- package/dist/prompts/apply-feedback/template.md +97 -78
- package/dist/prompts/create-pr/template.md +70 -49
- package/dist/prompts/detect-scripts/template.md +101 -36
- package/dist/prompts/detect-skills/template.md +120 -99
- package/dist/prompts/evaluate/template.md +350 -167
- package/dist/prompts/ideate/template.md +167 -134
- package/dist/prompts/implement/template.md +168 -122
- package/dist/prompts/plan/template.md +202 -168
- package/dist/prompts/readiness/template.md +115 -90
- package/dist/prompts/refine/template.md +104 -88
- package/dist/skills/ralphctl-abstraction-first/SKILL.md +3 -1
- package/dist/skills/ralphctl-alignment/SKILL.md +2 -1
- package/dist/skills/ralphctl-iterative-review/SKILL.md +3 -1
- package/package.json +1 -1
- package/dist/prompts/_partials/signals-feedback.md +0 -18
package/dist/cli.mjs
CHANGED
|
@@ -390,7 +390,7 @@ import { z } from "zod";
|
|
|
390
390
|
var CLAUDE_MODELS = [
|
|
391
391
|
"claude-haiku-4-5",
|
|
392
392
|
"claude-sonnet-4-6",
|
|
393
|
-
"claude-opus-4-
|
|
393
|
+
"claude-opus-4-8"
|
|
394
394
|
];
|
|
395
395
|
var isClaudeModel = (s) => CLAUDE_MODELS.includes(s);
|
|
396
396
|
|
|
@@ -481,7 +481,35 @@ var seedLegacyCreatePrRow = (ai) => {
|
|
|
481
481
|
if (!("provider" in refine)) return ai;
|
|
482
482
|
return { ...aiObj, createPr: { ...refine } };
|
|
483
483
|
};
|
|
484
|
-
var
|
|
484
|
+
var RETIRED_CLAUDE_OPUS = "claude-opus-4-7";
|
|
485
|
+
var SUCCESSOR_CLAUDE_OPUS = "claude-opus-4-8";
|
|
486
|
+
var migrateRetiredOpusRow = (row) => {
|
|
487
|
+
if (typeof row !== "object" || row === null) return row;
|
|
488
|
+
const rowObj = row;
|
|
489
|
+
if (rowObj["provider"] === "claude-code" && rowObj["model"] === RETIRED_CLAUDE_OPUS) {
|
|
490
|
+
return { ...rowObj, model: SUCCESSOR_CLAUDE_OPUS };
|
|
491
|
+
}
|
|
492
|
+
return row;
|
|
493
|
+
};
|
|
494
|
+
var migrateRetiredClaudeOpus = (ai) => {
|
|
495
|
+
if (typeof ai !== "object" || ai === null) return ai;
|
|
496
|
+
const aiObj = ai;
|
|
497
|
+
const next = { ...aiObj };
|
|
498
|
+
for (const flow of ["refine", "plan", "readiness", "ideate", "createPr"]) {
|
|
499
|
+
if (flow in next) next[flow] = migrateRetiredOpusRow(next[flow]);
|
|
500
|
+
}
|
|
501
|
+
const implement = next["implement"];
|
|
502
|
+
if (typeof implement === "object" && implement !== null) {
|
|
503
|
+
const implObj = implement;
|
|
504
|
+
next["implement"] = {
|
|
505
|
+
...implObj,
|
|
506
|
+
generator: migrateRetiredOpusRow(implObj["generator"]),
|
|
507
|
+
evaluator: migrateRetiredOpusRow(implObj["evaluator"])
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
return next;
|
|
511
|
+
};
|
|
512
|
+
var promoteLegacyAiRows = (ai) => migrateRetiredClaudeOpus(seedLegacyCreatePrRow(promoteLegacyImplementRow(ai)));
|
|
485
513
|
var AiSettingsSchema = z.preprocess(
|
|
486
514
|
promoteLegacyAiRows,
|
|
487
515
|
z.object({
|
|
@@ -575,10 +603,10 @@ var primaryFlowRow = (ai, flow) => {
|
|
|
575
603
|
var DEFAULT_MODELS_BY_PROVIDER = {
|
|
576
604
|
"claude-code": {
|
|
577
605
|
refine: "claude-sonnet-4-6",
|
|
578
|
-
plan: "claude-opus-4-
|
|
579
|
-
implement: "claude-opus-4-
|
|
606
|
+
plan: "claude-opus-4-8",
|
|
607
|
+
implement: "claude-opus-4-8",
|
|
580
608
|
readiness: "claude-sonnet-4-6",
|
|
581
|
-
ideate: "claude-opus-4-
|
|
609
|
+
ideate: "claude-opus-4-8",
|
|
582
610
|
// PR-content drafting is a single-shot summarisation task — Sonnet matches refine's
|
|
583
611
|
// light reasoning profile and avoids the Opus premium for a few-paragraph diff write-up.
|
|
584
612
|
createPr: "claude-sonnet-4-6"
|
|
@@ -617,7 +645,7 @@ var DEFAULT_SETTINGS = {
|
|
|
617
645
|
ai: {
|
|
618
646
|
...defaultAiSettingsForProvider("claude-code"),
|
|
619
647
|
implement: {
|
|
620
|
-
generator: { provider: "claude-code", model: "claude-opus-4-
|
|
648
|
+
generator: { provider: "claude-code", model: "claude-opus-4-8" },
|
|
621
649
|
evaluator: { provider: "openai-codex", model: "gpt-5.5" }
|
|
622
650
|
}
|
|
623
651
|
},
|
|
@@ -2475,13 +2503,21 @@ var CONTEXT_WINDOW = {
|
|
|
2475
2503
|
// Claude (claude-code adapter — direct from Anthropic)
|
|
2476
2504
|
"claude-haiku-4-5": 2e5,
|
|
2477
2505
|
"claude-sonnet-4-6": 2e5,
|
|
2478
|
-
"claude-opus-4-
|
|
2506
|
+
"claude-opus-4-8": 2e5
|
|
2479
2507
|
};
|
|
2480
2508
|
var contextWindowFor = (model) => {
|
|
2481
2509
|
if (model === void 0) return void 0;
|
|
2482
2510
|
return CONTEXT_WINDOW[model];
|
|
2483
2511
|
};
|
|
2484
2512
|
|
|
2513
|
+
// src/integration/ai/providers/_engine/truncate-debug-field.ts
|
|
2514
|
+
var truncateField = (value, max = 120) => {
|
|
2515
|
+
if (value === void 0 || value === null) return void 0;
|
|
2516
|
+
if (value.length === 0) return void 0;
|
|
2517
|
+
if (value.length <= max) return value;
|
|
2518
|
+
return `${value.slice(0, max)}\u2026`;
|
|
2519
|
+
};
|
|
2520
|
+
|
|
2485
2521
|
// src/domain/value/error/abort-error.ts
|
|
2486
2522
|
var AbortError = class extends Error {
|
|
2487
2523
|
code = ErrorCode.Aborted;
|
|
@@ -2561,6 +2597,101 @@ var classifySpawnExit = async (input) => {
|
|
|
2561
2597
|
|
|
2562
2598
|
// src/integration/ai/providers/claude/headless.ts
|
|
2563
2599
|
var RATE_LIMIT_RE = /rate.?limit/i;
|
|
2600
|
+
var isRecord2 = (v) => typeof v === "object" && v !== null;
|
|
2601
|
+
var asString = (v) => typeof v === "string" ? v : void 0;
|
|
2602
|
+
var previewArgs = (input) => {
|
|
2603
|
+
if (input === void 0 || input === null) return void 0;
|
|
2604
|
+
if (typeof input === "string") return input;
|
|
2605
|
+
try {
|
|
2606
|
+
const json = JSON.stringify(input);
|
|
2607
|
+
return json === void 0 || json === "{}" || json === "[]" ? void 0 : json;
|
|
2608
|
+
} catch {
|
|
2609
|
+
return void 0;
|
|
2610
|
+
}
|
|
2611
|
+
};
|
|
2612
|
+
var previewToolResult = (content) => {
|
|
2613
|
+
if (typeof content === "string") return content;
|
|
2614
|
+
if (Array.isArray(content)) {
|
|
2615
|
+
const texts = [];
|
|
2616
|
+
for (const part of content) {
|
|
2617
|
+
if (isRecord2(part)) {
|
|
2618
|
+
const t = asString(part["text"]);
|
|
2619
|
+
if (t !== void 0) texts.push(t);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
if (texts.length > 0) return texts.join("\n");
|
|
2623
|
+
}
|
|
2624
|
+
return void 0;
|
|
2625
|
+
};
|
|
2626
|
+
var publishStreamLineEvents = (eventBus, line) => {
|
|
2627
|
+
const json = line.json;
|
|
2628
|
+
if (json === void 0) return;
|
|
2629
|
+
const type = asString(json["type"]);
|
|
2630
|
+
if (type !== "assistant" && type !== "user") return;
|
|
2631
|
+
const message = json["message"];
|
|
2632
|
+
if (!isRecord2(message)) return;
|
|
2633
|
+
const content = message["content"];
|
|
2634
|
+
if (!Array.isArray(content)) return;
|
|
2635
|
+
if (type === "assistant") {
|
|
2636
|
+
const texts = [];
|
|
2637
|
+
const toolUses = [];
|
|
2638
|
+
for (const block of content) {
|
|
2639
|
+
if (!isRecord2(block)) continue;
|
|
2640
|
+
const blockType = asString(block["type"]);
|
|
2641
|
+
if (blockType === "text") {
|
|
2642
|
+
const t = asString(block["text"]);
|
|
2643
|
+
if (t !== void 0) texts.push(t);
|
|
2644
|
+
} else if (blockType === "tool_use") {
|
|
2645
|
+
const name = asString(block["name"]) ?? "";
|
|
2646
|
+
toolUses.push({ name, input: block["input"] });
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
if (texts.length > 0) {
|
|
2650
|
+
const text = truncateField(texts.join("\n"));
|
|
2651
|
+
if (text !== void 0) {
|
|
2652
|
+
eventBus.publish({
|
|
2653
|
+
type: "log",
|
|
2654
|
+
level: "debug",
|
|
2655
|
+
message: "claude-provider: assistant",
|
|
2656
|
+
meta: { text },
|
|
2657
|
+
at: IsoTimestamp.now()
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
for (const tool of toolUses) {
|
|
2662
|
+
const args = truncateField(previewArgs(tool.input));
|
|
2663
|
+
eventBus.publish({
|
|
2664
|
+
type: "log",
|
|
2665
|
+
level: "debug",
|
|
2666
|
+
message: "claude-provider: tool_use",
|
|
2667
|
+
meta: {
|
|
2668
|
+
tool: tool.name,
|
|
2669
|
+
...args !== void 0 ? { args } : {}
|
|
2670
|
+
},
|
|
2671
|
+
at: IsoTimestamp.now()
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
for (const block of content) {
|
|
2677
|
+
if (!isRecord2(block)) continue;
|
|
2678
|
+
if (asString(block["type"]) !== "tool_result") continue;
|
|
2679
|
+
const tool = asString(block["name"]) ?? asString(block["tool_use_id"]) ?? "";
|
|
2680
|
+
const status = block["is_error"] === true ? "error" : "ok";
|
|
2681
|
+
const preview = truncateField(previewToolResult(block["content"]));
|
|
2682
|
+
eventBus.publish({
|
|
2683
|
+
type: "log",
|
|
2684
|
+
level: "debug",
|
|
2685
|
+
message: "claude-provider: tool_result",
|
|
2686
|
+
meta: {
|
|
2687
|
+
tool,
|
|
2688
|
+
status,
|
|
2689
|
+
...preview !== void 0 ? { preview } : {}
|
|
2690
|
+
},
|
|
2691
|
+
at: IsoTimestamp.now()
|
|
2692
|
+
});
|
|
2693
|
+
}
|
|
2694
|
+
};
|
|
2564
2695
|
var TOOL_EDIT = ["Edit", "MultiEdit", "NotebookEdit"];
|
|
2565
2696
|
var TOOL_SHELL = ["Bash"];
|
|
2566
2697
|
var TOOL_NETWORK = ["WebFetch", "WebSearch"];
|
|
@@ -2677,6 +2808,7 @@ var spawnAttempt = async (input) => {
|
|
|
2677
2808
|
let stderrBuf = "";
|
|
2678
2809
|
const onLine = (line) => {
|
|
2679
2810
|
parser.ingest(line);
|
|
2811
|
+
publishStreamLineEvents(deps.eventBus, line);
|
|
2680
2812
|
};
|
|
2681
2813
|
const watchdogBannerId = `watchdog-claude-${String(child.pid ?? "unknown")}`;
|
|
2682
2814
|
const { code, signal } = await runHeadlessSpawn({
|
|
@@ -2906,7 +3038,7 @@ var createCodexProvider = (deps) => {
|
|
|
2906
3038
|
}
|
|
2907
3039
|
};
|
|
2908
3040
|
};
|
|
2909
|
-
var consumeMetaLines = (buffer, onMeta) => {
|
|
3041
|
+
var consumeMetaLines = (buffer, onMeta, onLine) => {
|
|
2910
3042
|
let remaining = buffer;
|
|
2911
3043
|
while (true) {
|
|
2912
3044
|
const nl = remaining.indexOf("\n");
|
|
@@ -2915,23 +3047,101 @@ var consumeMetaLines = (buffer, onMeta) => {
|
|
|
2915
3047
|
remaining = remaining.slice(nl + 1);
|
|
2916
3048
|
const trimmed = line.trim();
|
|
2917
3049
|
if (trimmed.length === 0 || !trimmed.startsWith("{")) continue;
|
|
3050
|
+
let obj;
|
|
2918
3051
|
try {
|
|
2919
|
-
|
|
2920
|
-
const id = stringField2(obj, "thread_id", "session_id", "sessionId");
|
|
2921
|
-
const model = stringField2(obj, "model");
|
|
2922
|
-
const usageObj = obj["usage"];
|
|
2923
|
-
const source = isRecord2(usageObj) ? usageObj : obj;
|
|
2924
|
-
const i = numberField2(source, "input_tokens", "inputTokens", "prompt_tokens");
|
|
2925
|
-
const o = numberField2(source, "output_tokens", "outputTokens", "completion_tokens");
|
|
2926
|
-
if (id === void 0 && model === void 0 && i === void 0 && o === void 0) continue;
|
|
2927
|
-
onMeta({
|
|
2928
|
-
...id !== void 0 ? { sessionId: id } : {},
|
|
2929
|
-
...model !== void 0 ? { model } : {},
|
|
2930
|
-
...i !== void 0 ? { inputTokens: i } : {},
|
|
2931
|
-
...o !== void 0 ? { outputTokens: o } : {}
|
|
2932
|
-
});
|
|
3052
|
+
obj = JSON.parse(trimmed);
|
|
2933
3053
|
} catch {
|
|
3054
|
+
continue;
|
|
3055
|
+
}
|
|
3056
|
+
if (onLine !== void 0) onLine(obj);
|
|
3057
|
+
const id = stringField2(obj, "thread_id", "session_id", "sessionId");
|
|
3058
|
+
const model = stringField2(obj, "model");
|
|
3059
|
+
const usageObj = obj["usage"];
|
|
3060
|
+
const source = isRecord3(usageObj) ? usageObj : obj;
|
|
3061
|
+
const i = numberField2(source, "input_tokens", "inputTokens", "prompt_tokens");
|
|
3062
|
+
const o = numberField2(source, "output_tokens", "outputTokens", "completion_tokens");
|
|
3063
|
+
if (id === void 0 && model === void 0 && i === void 0 && o === void 0) continue;
|
|
3064
|
+
onMeta({
|
|
3065
|
+
...id !== void 0 ? { sessionId: id } : {},
|
|
3066
|
+
...model !== void 0 ? { model } : {},
|
|
3067
|
+
...i !== void 0 ? { inputTokens: i } : {},
|
|
3068
|
+
...o !== void 0 ? { outputTokens: o } : {}
|
|
3069
|
+
});
|
|
3070
|
+
}
|
|
3071
|
+
};
|
|
3072
|
+
var publishCodexStreamLineEvents = (eventBus, obj) => {
|
|
3073
|
+
if (stringField2(obj, "type") !== "item.completed") return;
|
|
3074
|
+
const item = obj["item"];
|
|
3075
|
+
if (!isRecord3(item)) return;
|
|
3076
|
+
const itemType = stringField2(item, "type");
|
|
3077
|
+
if (itemType === "agent_message") {
|
|
3078
|
+
const text = truncateField(stringField2(item, "text"));
|
|
3079
|
+
if (text !== void 0) {
|
|
3080
|
+
eventBus.publish({
|
|
3081
|
+
type: "log",
|
|
3082
|
+
level: "debug",
|
|
3083
|
+
message: "codex-provider: assistant",
|
|
3084
|
+
meta: { text },
|
|
3085
|
+
at: IsoTimestamp.now()
|
|
3086
|
+
});
|
|
2934
3087
|
}
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
3090
|
+
if (itemType === "command_execution") {
|
|
3091
|
+
const args = truncateField(stringField2(item, "command"));
|
|
3092
|
+
eventBus.publish({
|
|
3093
|
+
type: "log",
|
|
3094
|
+
level: "debug",
|
|
3095
|
+
message: "codex-provider: tool_use",
|
|
3096
|
+
meta: {
|
|
3097
|
+
tool: "command_execution",
|
|
3098
|
+
...args !== void 0 ? { args } : {}
|
|
3099
|
+
},
|
|
3100
|
+
at: IsoTimestamp.now()
|
|
3101
|
+
});
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
if (itemType === "function_call") {
|
|
3105
|
+
const tool = stringField2(item, "name") ?? "";
|
|
3106
|
+
const rawArgs = item["arguments"];
|
|
3107
|
+
const argsPreview = typeof rawArgs === "string" ? rawArgs : safeJson(rawArgs);
|
|
3108
|
+
const args = truncateField(argsPreview);
|
|
3109
|
+
eventBus.publish({
|
|
3110
|
+
type: "log",
|
|
3111
|
+
level: "debug",
|
|
3112
|
+
message: "codex-provider: tool_use",
|
|
3113
|
+
meta: {
|
|
3114
|
+
tool,
|
|
3115
|
+
...args !== void 0 ? { args } : {}
|
|
3116
|
+
},
|
|
3117
|
+
at: IsoTimestamp.now()
|
|
3118
|
+
});
|
|
3119
|
+
return;
|
|
3120
|
+
}
|
|
3121
|
+
if (itemType === "function_call_output") {
|
|
3122
|
+
const tool = stringField2(item, "name") ?? stringField2(item, "call_id") ?? "";
|
|
3123
|
+
const status = item["is_error"] === true || stringField2(item, "status") === "error" ? "error" : "ok";
|
|
3124
|
+
const preview = truncateField(stringField2(item, "output"));
|
|
3125
|
+
eventBus.publish({
|
|
3126
|
+
type: "log",
|
|
3127
|
+
level: "debug",
|
|
3128
|
+
message: "codex-provider: tool_result",
|
|
3129
|
+
meta: {
|
|
3130
|
+
tool,
|
|
3131
|
+
status,
|
|
3132
|
+
...preview !== void 0 ? { preview } : {}
|
|
3133
|
+
},
|
|
3134
|
+
at: IsoTimestamp.now()
|
|
3135
|
+
});
|
|
3136
|
+
}
|
|
3137
|
+
};
|
|
3138
|
+
var safeJson = (v) => {
|
|
3139
|
+
if (v === void 0 || v === null) return void 0;
|
|
3140
|
+
try {
|
|
3141
|
+
const s = JSON.stringify(v);
|
|
3142
|
+
return s === "{}" || s === "[]" ? void 0 : s;
|
|
3143
|
+
} catch {
|
|
3144
|
+
return void 0;
|
|
2935
3145
|
}
|
|
2936
3146
|
};
|
|
2937
3147
|
var stringField2 = (obj, ...names) => {
|
|
@@ -2948,7 +3158,7 @@ var numberField2 = (obj, ...names) => {
|
|
|
2948
3158
|
}
|
|
2949
3159
|
return void 0;
|
|
2950
3160
|
};
|
|
2951
|
-
var
|
|
3161
|
+
var isRecord3 = (v) => typeof v === "object" && v !== null;
|
|
2952
3162
|
var spawnAttempt2 = async (input) => {
|
|
2953
3163
|
const { deps, spawnFn, command, args, session, readFile: readFile2, outputFile } = input;
|
|
2954
3164
|
const child = spawnFn(command, args, { stdio: ["pipe", "pipe", "pipe"], cwd: String(session.cwd) });
|
|
@@ -2962,23 +3172,27 @@ var spawnAttempt2 = async (input) => {
|
|
|
2962
3172
|
const { code, signal } = await runHeadlessSpawn({
|
|
2963
3173
|
child,
|
|
2964
3174
|
onStdout: (chunk) => {
|
|
2965
|
-
stdoutLineBuf = consumeMetaLines(
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
3175
|
+
stdoutLineBuf = consumeMetaLines(
|
|
3176
|
+
stdoutLineBuf + chunk,
|
|
3177
|
+
(update) => {
|
|
3178
|
+
if (update.sessionId !== void 0 && sessionId2 === void 0) {
|
|
3179
|
+
sessionId2 = update.sessionId;
|
|
3180
|
+
deps.eventBus.publish({
|
|
3181
|
+
type: "log",
|
|
3182
|
+
level: "debug",
|
|
3183
|
+
message: "codex-provider: session id captured",
|
|
3184
|
+
meta: { sessionId: update.sessionId },
|
|
3185
|
+
at: IsoTimestamp.now()
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
if (update.model !== void 0 && model === void 0) {
|
|
3189
|
+
model = update.model;
|
|
3190
|
+
}
|
|
3191
|
+
if (update.inputTokens !== void 0) inputTokens = update.inputTokens;
|
|
3192
|
+
if (update.outputTokens !== void 0) outputTokens = update.outputTokens;
|
|
3193
|
+
},
|
|
3194
|
+
(obj) => publishCodexStreamLineEvents(deps.eventBus, obj)
|
|
3195
|
+
);
|
|
2982
3196
|
},
|
|
2983
3197
|
onStderr: (chunk) => {
|
|
2984
3198
|
stderrBuf += chunk;
|
|
@@ -3100,7 +3314,7 @@ var numberField3 = (obj, ...names) => {
|
|
|
3100
3314
|
}
|
|
3101
3315
|
return void 0;
|
|
3102
3316
|
};
|
|
3103
|
-
var
|
|
3317
|
+
var isRecord4 = (v) => typeof v === "object" && v !== null;
|
|
3104
3318
|
var extractUsage = (json) => {
|
|
3105
3319
|
const ti = numberField3(json, "input_tokens", "inputTokens", "prompt_tokens");
|
|
3106
3320
|
const to = numberField3(json, "output_tokens", "outputTokens", "completion_tokens");
|
|
@@ -3111,7 +3325,7 @@ var extractUsage = (json) => {
|
|
|
3111
3325
|
};
|
|
3112
3326
|
}
|
|
3113
3327
|
const u = json["usage"];
|
|
3114
|
-
if (!
|
|
3328
|
+
if (!isRecord4(u)) return void 0;
|
|
3115
3329
|
const ni = numberField3(u, "input_tokens", "inputTokens", "prompt_tokens");
|
|
3116
3330
|
const no = numberField3(u, "output_tokens", "outputTokens", "completion_tokens");
|
|
3117
3331
|
if (ni === void 0 && no === void 0) return void 0;
|
|
@@ -3123,10 +3337,10 @@ var extractUsage = (json) => {
|
|
|
3123
3337
|
var extractBodyText = (json) => {
|
|
3124
3338
|
const eventType = stringField3(json, "type");
|
|
3125
3339
|
const data = json["data"];
|
|
3126
|
-
if (eventType === "assistant.message_delta" &&
|
|
3340
|
+
if (eventType === "assistant.message_delta" && isRecord4(data)) {
|
|
3127
3341
|
return stringField3(data, "deltaContent");
|
|
3128
3342
|
}
|
|
3129
|
-
if (eventType === "assistant.message" &&
|
|
3343
|
+
if (eventType === "assistant.message" && isRecord4(data)) {
|
|
3130
3344
|
return stringField3(data, "content");
|
|
3131
3345
|
}
|
|
3132
3346
|
if (eventType === "response.output_text.delta") {
|
|
@@ -3134,7 +3348,7 @@ var extractBodyText = (json) => {
|
|
|
3134
3348
|
}
|
|
3135
3349
|
if (eventType === "content_block_delta") {
|
|
3136
3350
|
const delta = json["delta"];
|
|
3137
|
-
if (
|
|
3351
|
+
if (isRecord4(delta)) return stringField3(delta, "text");
|
|
3138
3352
|
}
|
|
3139
3353
|
if (eventType === "message") {
|
|
3140
3354
|
const c = stringField3(json, "content");
|
|
@@ -3325,6 +3539,16 @@ var spawnAttempt3 = async (input) => {
|
|
|
3325
3539
|
}
|
|
3326
3540
|
if (line.bodyText !== void 0 && line.bodyText.length > 0) {
|
|
3327
3541
|
events.push({ assistant: true, text: line.bodyText });
|
|
3542
|
+
const text = truncateField(line.bodyText);
|
|
3543
|
+
if (text !== void 0) {
|
|
3544
|
+
deps.eventBus.publish({
|
|
3545
|
+
type: "log",
|
|
3546
|
+
level: "debug",
|
|
3547
|
+
message: "copilot-provider: assistant",
|
|
3548
|
+
meta: { text },
|
|
3549
|
+
at: IsoTimestamp.now()
|
|
3550
|
+
});
|
|
3551
|
+
}
|
|
3328
3552
|
} else if (line.sessionId === void 0 && line.model === void 0 && line.usage === void 0) {
|
|
3329
3553
|
events.push({ assistant: false, text: line.raw });
|
|
3330
3554
|
}
|
|
@@ -4734,7 +4958,7 @@ var createNpmVersionChecker = (deps) => {
|
|
|
4734
4958
|
// package.json
|
|
4735
4959
|
var package_default = {
|
|
4736
4960
|
name: "ralphctl",
|
|
4737
|
-
version: "0.8.
|
|
4961
|
+
version: "0.8.4",
|
|
4738
4962
|
description: "Agent harness for long-running AI coding tasks \u2014 orchestrates Claude Code, GitHub Copilot, and OpenAI Codex across repositories",
|
|
4739
4963
|
homepage: "https://github.com/lukas-grigis/ralphctl",
|
|
4740
4964
|
type: "module",
|
|
@@ -4840,7 +5064,7 @@ var CLI_METADATA = {
|
|
|
4840
5064
|
var DEFAULT_ESCALATION_MAP = {
|
|
4841
5065
|
// Claude — Sonnet escalates to Opus; Haiku escalates to Sonnet.
|
|
4842
5066
|
"claude-haiku-4-5": "claude-sonnet-4-6",
|
|
4843
|
-
"claude-sonnet-4-6": "claude-opus-4-
|
|
5067
|
+
"claude-sonnet-4-6": "claude-opus-4-8",
|
|
4844
5068
|
// Copilot/Codex — mini variants step up to their full-tier frontier.
|
|
4845
5069
|
"gpt-5-mini": "gpt-5.5",
|
|
4846
5070
|
"gpt-5.4-mini": "gpt-5.5"
|
|
@@ -6163,7 +6387,12 @@ var SelectionProvider = ({
|
|
|
6163
6387
|
onChangeRef.current = onChange;
|
|
6164
6388
|
const projectIdRef = useRef3(projectId);
|
|
6165
6389
|
projectIdRef.current = projectId;
|
|
6390
|
+
const isFirstPersist = useRef3(true);
|
|
6166
6391
|
useEffect3(() => {
|
|
6392
|
+
if (isFirstPersist.current) {
|
|
6393
|
+
isFirstPersist.current = false;
|
|
6394
|
+
return;
|
|
6395
|
+
}
|
|
6167
6396
|
onChangeRef.current?.({
|
|
6168
6397
|
...projectId !== void 0 ? { projectId } : {},
|
|
6169
6398
|
...projectLabel !== void 0 ? { projectLabel } : {},
|
|
@@ -8635,7 +8864,6 @@ var signalReference = {
|
|
|
8635
8864
|
{ keys: [], label: "blocked", description: "task halted \u2014 check gate failed or AI self-reported stuck" },
|
|
8636
8865
|
{ keys: [], label: "commit", description: "proposed commit message for the task" },
|
|
8637
8866
|
{ keys: [], label: "note", description: "general annotation" },
|
|
8638
|
-
{ keys: [], label: "progress", description: "milestone marker from the AI" },
|
|
8639
8867
|
{ keys: [], label: "script", description: "setup or check script discovered or run" },
|
|
8640
8868
|
{ keys: [], label: "proposal", description: "AI-authored context file or skill draft" },
|
|
8641
8869
|
{ keys: [], label: "skills", description: "skill suggestions surfaced for this run" }
|
|
@@ -8767,8 +8995,6 @@ var SIGNAL_LABEL_COLOR = {
|
|
|
8767
8995
|
decision: inkColors.highlight,
|
|
8768
8996
|
commit: inkColors.info,
|
|
8769
8997
|
note: inkColors.muted,
|
|
8770
|
-
progress: inkColors.info,
|
|
8771
|
-
"progress-entry": inkColors.info,
|
|
8772
8998
|
done: inkColors.success,
|
|
8773
8999
|
verified: inkColors.success,
|
|
8774
9000
|
blocked: inkColors.error,
|
|
@@ -8789,10 +9015,6 @@ var rowForSignal = (sig) => {
|
|
|
8789
9015
|
}
|
|
8790
9016
|
case "note":
|
|
8791
9017
|
return { label: "note", text: sig.text };
|
|
8792
|
-
case "progress":
|
|
8793
|
-
return { label: "progress", text: sig.summary };
|
|
8794
|
-
case "progress-entry":
|
|
8795
|
-
return { label: "progress-entry", text: sig.task };
|
|
8796
9018
|
case "task-complete":
|
|
8797
9019
|
return { label: "done", text: "task complete" };
|
|
8798
9020
|
case "task-verified":
|
|
@@ -11350,6 +11572,11 @@ var refineExampleSignals = [
|
|
|
11350
11572
|
type: "refined-ticket",
|
|
11351
11573
|
body: "# Export to CSV\n\n## Problem\n\nUsers cannot move their data out of the app.\n\n## Acceptance criteria\n\n### AC1 \u2014 CSV export\n\n- **Given** a logged-in user, **When** they click Export, **Then** a CSV download starts.",
|
|
11352
11574
|
timestamp: EXAMPLE_TS
|
|
11575
|
+
},
|
|
11576
|
+
{
|
|
11577
|
+
type: "decision",
|
|
11578
|
+
text: "Scoped export to CSV only for v1; XLSX deferred to a follow-up ticket.",
|
|
11579
|
+
timestamp: EXAMPLE_TS
|
|
11353
11580
|
}
|
|
11354
11581
|
];
|
|
11355
11582
|
var refineOutputContract = {
|
|
@@ -11622,7 +11849,7 @@ var refinePromptDef = {
|
|
|
11622
11849
|
partials: {
|
|
11623
11850
|
HARNESS_CONTEXT: "harness-context"
|
|
11624
11851
|
},
|
|
11625
|
-
expectedSignals: ["refined-ticket"]
|
|
11852
|
+
expectedSignals: ["refined-ticket", "note", "learning", "decision"]
|
|
11626
11853
|
};
|
|
11627
11854
|
var renderTicket = (ticket) => {
|
|
11628
11855
|
const lines = [`**Title:** ${ticket.title}`, `**ID:** ${String(ticket.id)}`];
|
|
@@ -11679,8 +11906,8 @@ var renderContractSection = (params) => {
|
|
|
11679
11906
|
lines.push("other files \u2014 the harness renders every operator-readable sidecar from the validated");
|
|
11680
11907
|
lines.push("signals.");
|
|
11681
11908
|
lines.push("");
|
|
11682
|
-
lines.push("
|
|
11683
|
-
lines.push("
|
|
11909
|
+
lines.push("Always write to the **absolute path** shown above \u2014 do not use a relative path, which");
|
|
11910
|
+
lines.push("would resolve against your working directory and may land in the wrong place.");
|
|
11684
11911
|
lines.push("");
|
|
11685
11912
|
if (params.sidecars.length > 0) {
|
|
11686
11913
|
lines.push("Files the harness will render from your signals (you must NOT write these):");
|
|
@@ -13637,7 +13864,18 @@ var implementPromptDef = {
|
|
|
13637
13864
|
},
|
|
13638
13865
|
// Documents the harness signals the implement response is expected to carry. Validation is
|
|
13639
13866
|
// not enforced at parse time — this list drives test authors and future scoped parsers.
|
|
13640
|
-
|
|
13867
|
+
// Aligned with generator.contract.ts: narrative fan-out (change, decision, learning, note)
|
|
13868
|
+
// plus lifecycle signals (task-verified, task-complete, task-blocked, commit-message).
|
|
13869
|
+
expectedSignals: [
|
|
13870
|
+
"change",
|
|
13871
|
+
"decision",
|
|
13872
|
+
"learning",
|
|
13873
|
+
"note",
|
|
13874
|
+
"task-verified",
|
|
13875
|
+
"task-complete",
|
|
13876
|
+
"task-blocked",
|
|
13877
|
+
"commit-message"
|
|
13878
|
+
]
|
|
13641
13879
|
};
|
|
13642
13880
|
var buildImplementPrompt = async (deps, input) => buildPrompt(deps, implementPromptDef, {
|
|
13643
13881
|
taskName: input.task.name,
|
|
@@ -13656,7 +13894,7 @@ var buildImplementPrompt = async (deps, input) => buildPrompt(deps, implementPro
|
|
|
13656
13894
|
});
|
|
13657
13895
|
|
|
13658
13896
|
// src/application/flows/implement/leaves/generator.contract.ts
|
|
13659
|
-
import { z as
|
|
13897
|
+
import { z as z30 } from "zod";
|
|
13660
13898
|
|
|
13661
13899
|
// src/integration/ai/contract/_engine/signals/change/schema.ts
|
|
13662
13900
|
import { z as z25 } from "zod";
|
|
@@ -13675,44 +13913,33 @@ var commitMessageSignalSchema = z26.object({
|
|
|
13675
13913
|
timestamp: IsoTimestampSchema
|
|
13676
13914
|
});
|
|
13677
13915
|
|
|
13678
|
-
// src/integration/ai/contract/_engine/signals/progress-entry/schema.ts
|
|
13679
|
-
import { z as z27 } from "zod";
|
|
13680
|
-
var progressEntrySignalSchema = z27.object({
|
|
13681
|
-
type: z27.literal("progress-entry"),
|
|
13682
|
-
task: z27.string(),
|
|
13683
|
-
filesChanged: z27.array(z27.string()).readonly(),
|
|
13684
|
-
learnings: z27.string(),
|
|
13685
|
-
notesForNext: z27.string(),
|
|
13686
|
-
timestamp: IsoTimestampSchema
|
|
13687
|
-
});
|
|
13688
|
-
|
|
13689
13916
|
// src/integration/ai/contract/_engine/signals/task-blocked/schema.ts
|
|
13690
|
-
import { z as
|
|
13691
|
-
var taskBlockedSignalSchema =
|
|
13692
|
-
type:
|
|
13693
|
-
reason:
|
|
13917
|
+
import { z as z27 } from "zod";
|
|
13918
|
+
var taskBlockedSignalSchema = z27.object({
|
|
13919
|
+
type: z27.literal("task-blocked"),
|
|
13920
|
+
reason: z27.string(),
|
|
13694
13921
|
timestamp: IsoTimestampSchema
|
|
13695
13922
|
});
|
|
13696
13923
|
|
|
13697
13924
|
// src/integration/ai/contract/_engine/signals/task-complete/schema.ts
|
|
13698
|
-
import { z as
|
|
13699
|
-
var taskCompleteSignalSchema =
|
|
13700
|
-
type:
|
|
13925
|
+
import { z as z28 } from "zod";
|
|
13926
|
+
var taskCompleteSignalSchema = z28.object({
|
|
13927
|
+
type: z28.literal("task-complete"),
|
|
13701
13928
|
timestamp: IsoTimestampSchema
|
|
13702
13929
|
});
|
|
13703
13930
|
|
|
13704
13931
|
// src/integration/ai/contract/_engine/signals/task-verified/schema.ts
|
|
13705
|
-
import { z as
|
|
13706
|
-
var taskVerifiedSignalSchema =
|
|
13707
|
-
type:
|
|
13708
|
-
output:
|
|
13932
|
+
import { z as z29 } from "zod";
|
|
13933
|
+
var taskVerifiedSignalSchema = z29.object({
|
|
13934
|
+
type: z29.literal("task-verified"),
|
|
13935
|
+
output: z29.string(),
|
|
13709
13936
|
timestamp: IsoTimestampSchema
|
|
13710
13937
|
});
|
|
13711
13938
|
|
|
13712
13939
|
// src/application/flows/implement/leaves/generator.contract.ts
|
|
13713
13940
|
var atMostOneCommitMessage = (signals) => signals.filter((s) => s.type === "commit-message").length <= 1;
|
|
13714
|
-
var signalsArraySchemaRaw3 =
|
|
13715
|
-
|
|
13941
|
+
var signalsArraySchemaRaw3 = z30.array(
|
|
13942
|
+
z30.union([
|
|
13716
13943
|
changeSignalSchema,
|
|
13717
13944
|
learningSignalSchema,
|
|
13718
13945
|
noteSignalSchema,
|
|
@@ -13720,8 +13947,7 @@ var signalsArraySchemaRaw3 = z31.array(
|
|
|
13720
13947
|
taskVerifiedSignalSchema,
|
|
13721
13948
|
taskCompleteSignalSchema,
|
|
13722
13949
|
taskBlockedSignalSchema,
|
|
13723
|
-
commitMessageSignalSchema
|
|
13724
|
-
progressEntrySignalSchema
|
|
13950
|
+
commitMessageSignalSchema
|
|
13725
13951
|
])
|
|
13726
13952
|
).refine(atMostOneCommitMessage, "at most one commit-message signal per generator spawn");
|
|
13727
13953
|
var signalsArraySchema3 = brandSignalArray(signalsArraySchemaRaw3);
|
|
@@ -14812,15 +15038,15 @@ var implementSession = (sandboxCwd, repoPath, sprintDir2, prompt, model, signals
|
|
|
14812
15038
|
};
|
|
14813
15039
|
|
|
14814
15040
|
// src/application/flows/implement/leaves/evaluator.contract.ts
|
|
14815
|
-
import { z as
|
|
15041
|
+
import { z as z32 } from "zod";
|
|
14816
15042
|
|
|
14817
15043
|
// src/integration/ai/contract/_engine/signals/evaluation/schema.ts
|
|
14818
|
-
import { z as
|
|
14819
|
-
var dimensionScoreSchema =
|
|
14820
|
-
dimension:
|
|
14821
|
-
passed:
|
|
14822
|
-
finding:
|
|
14823
|
-
executionEvidence:
|
|
15044
|
+
import { z as z31 } from "zod";
|
|
15045
|
+
var dimensionScoreSchema = z31.object({
|
|
15046
|
+
dimension: z31.string(),
|
|
15047
|
+
passed: z31.boolean(),
|
|
15048
|
+
finding: z31.string(),
|
|
15049
|
+
executionEvidence: z31.string().optional()
|
|
14824
15050
|
}).superRefine((d, ctx) => {
|
|
14825
15051
|
if (!d.passed && d.finding.trim().length === 0) {
|
|
14826
15052
|
ctx.addIssue({
|
|
@@ -14830,11 +15056,11 @@ var dimensionScoreSchema = z32.object({
|
|
|
14830
15056
|
});
|
|
14831
15057
|
}
|
|
14832
15058
|
});
|
|
14833
|
-
var evaluationSignalSchema =
|
|
14834
|
-
type:
|
|
14835
|
-
status:
|
|
14836
|
-
dimensions:
|
|
14837
|
-
critique:
|
|
15059
|
+
var evaluationSignalSchema = z31.object({
|
|
15060
|
+
type: z31.literal("evaluation"),
|
|
15061
|
+
status: z31.union([z31.literal("passed"), z31.literal("failed"), z31.literal("malformed")]),
|
|
15062
|
+
dimensions: z31.array(dimensionScoreSchema).readonly(),
|
|
15063
|
+
critique: z31.string().optional(),
|
|
14838
15064
|
timestamp: IsoTimestampSchema
|
|
14839
15065
|
}).superRefine((s, ctx) => {
|
|
14840
15066
|
if (s.status === "passed") {
|
|
@@ -14894,8 +15120,8 @@ var renderEvaluationMarkdown = (signal) => {
|
|
|
14894
15120
|
|
|
14895
15121
|
// src/application/flows/implement/leaves/evaluator.contract.ts
|
|
14896
15122
|
var exactlyOneEvaluation = (signals) => signals.filter((s) => s.type === "evaluation").length === 1;
|
|
14897
|
-
var signalsArraySchemaRaw4 =
|
|
14898
|
-
|
|
15123
|
+
var signalsArraySchemaRaw4 = z32.array(
|
|
15124
|
+
z32.union([
|
|
14899
15125
|
changeSignalSchema,
|
|
14900
15126
|
learningSignalSchema,
|
|
14901
15127
|
noteSignalSchema,
|
|
@@ -18055,12 +18281,12 @@ var buildApplyFeedbackPrompt = async (deps, input) => buildPrompt(deps, applyFee
|
|
|
18055
18281
|
});
|
|
18056
18282
|
|
|
18057
18283
|
// src/application/flows/review/leaves/review-round.contract.ts
|
|
18058
|
-
import { z as
|
|
18284
|
+
import { z as z33 } from "zod";
|
|
18059
18285
|
var hasExactlyOneTerminal = (signals) => {
|
|
18060
18286
|
const terminals = signals.filter((s) => s.type === "task-complete" || s.type === "task-blocked");
|
|
18061
18287
|
return terminals.length === 1;
|
|
18062
18288
|
};
|
|
18063
|
-
var signalsArraySchemaRaw5 =
|
|
18289
|
+
var signalsArraySchemaRaw5 = z33.array(z33.union([taskCompleteSignalSchema, taskBlockedSignalSchema])).refine(hasExactlyOneTerminal, "exactly one of `task-complete` or `task-blocked` is required per round");
|
|
18064
18290
|
var signalsArraySchema5 = brandSignalArray(signalsArraySchemaRaw5);
|
|
18065
18291
|
var wrapLegacyArray5 = (raw) => {
|
|
18066
18292
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -18718,6 +18944,16 @@ var wireTagFor = (tool) => {
|
|
|
18718
18944
|
return "agents-md";
|
|
18719
18945
|
}
|
|
18720
18946
|
};
|
|
18947
|
+
var conventionsPartialName = (tool) => {
|
|
18948
|
+
switch (tool) {
|
|
18949
|
+
case "claude-code":
|
|
18950
|
+
return "conventions-claude-md";
|
|
18951
|
+
case "copilot":
|
|
18952
|
+
return "conventions-copilot-instructions";
|
|
18953
|
+
case "codex":
|
|
18954
|
+
return "conventions-agents-md";
|
|
18955
|
+
}
|
|
18956
|
+
};
|
|
18721
18957
|
var readinessPromptDef = {
|
|
18722
18958
|
templateName: "readiness",
|
|
18723
18959
|
description: "One-shot read-only repo inventory. The AI proposes a project context file body the harness writes to the tool-native target path.",
|
|
@@ -18749,6 +18985,10 @@ var readinessPromptDef = {
|
|
|
18749
18985
|
placeholder: "DETECTED_ARTEFACTS",
|
|
18750
18986
|
description: 'Bullet list of artefact paths discovered by the probe, or "no artefacts detected".'
|
|
18751
18987
|
},
|
|
18988
|
+
targetFileConventions: {
|
|
18989
|
+
placeholder: "TARGET_FILE_CONVENTIONS",
|
|
18990
|
+
description: "Per-provider style guide for the target context file (CLAUDE.md / .github/copilot-instructions.md / AGENTS.md). Loaded from the matching conventions partial."
|
|
18991
|
+
},
|
|
18752
18992
|
outputContractSection: {
|
|
18753
18993
|
placeholder: "OUTPUT_CONTRACT_SECTION",
|
|
18754
18994
|
description: "Audit-[09] output contract block rendered from the readiness contract \u2014 instructs the AI to write `signals.json` directly with the proposal signals.",
|
|
@@ -18799,54 +19039,60 @@ var collectArtefactPaths = (state) => {
|
|
|
18799
19039
|
}
|
|
18800
19040
|
return paths;
|
|
18801
19041
|
};
|
|
18802
|
-
var buildReadinessPrompt = async (deps, input) =>
|
|
18803
|
-
|
|
18804
|
-
|
|
18805
|
-
|
|
18806
|
-
|
|
18807
|
-
|
|
18808
|
-
|
|
18809
|
-
|
|
19042
|
+
var buildReadinessPrompt = async (deps, input) => {
|
|
19043
|
+
const partialName = conventionsPartialName(input.currentTool);
|
|
19044
|
+
const conventionsResult = await deps.load(partialName);
|
|
19045
|
+
if (!conventionsResult.ok) return Result.error(conventionsResult.error);
|
|
19046
|
+
return buildPrompt(deps, readinessPromptDef, {
|
|
19047
|
+
repositoryPath: input.repositoryPath,
|
|
19048
|
+
currentTool: renderCurrentTool(input.currentTool),
|
|
19049
|
+
wireTag: wireTagFor(input.currentTool),
|
|
19050
|
+
existingContextFile: renderExistingContextFile(input.existingContextFile),
|
|
19051
|
+
detectedArtefacts: renderDetectedArtefacts(collectArtefactPaths(input.probedState)),
|
|
19052
|
+
targetFileConventions: conventionsResult.value.trim(),
|
|
19053
|
+
outputContractSection: input.outputContractSection
|
|
19054
|
+
});
|
|
19055
|
+
};
|
|
18810
19056
|
|
|
18811
19057
|
// src/application/flows/readiness/leaves/readiness.contract.ts
|
|
18812
|
-
import { z as
|
|
19058
|
+
import { z as z38 } from "zod";
|
|
18813
19059
|
|
|
18814
19060
|
// src/integration/ai/contract/_engine/signals/agents-md-proposal/schema.ts
|
|
18815
|
-
import { z as
|
|
18816
|
-
var agentsMdProposalSignalSchema =
|
|
18817
|
-
type:
|
|
18818
|
-
tag:
|
|
18819
|
-
content:
|
|
19061
|
+
import { z as z34 } from "zod";
|
|
19062
|
+
var agentsMdProposalSignalSchema = z34.object({
|
|
19063
|
+
type: z34.literal("agents-md-proposal"),
|
|
19064
|
+
tag: z34.union([z34.literal("claude-md"), z34.literal("copilot-instructions"), z34.literal("agents-md")]),
|
|
19065
|
+
content: z34.string(),
|
|
18820
19066
|
timestamp: IsoTimestampSchema
|
|
18821
19067
|
});
|
|
18822
19068
|
|
|
18823
19069
|
// src/integration/ai/contract/_engine/signals/setup-skill-proposal/schema.ts
|
|
18824
|
-
import { z as
|
|
18825
|
-
var setupSkillProposalSignalSchema =
|
|
18826
|
-
type:
|
|
18827
|
-
content:
|
|
19070
|
+
import { z as z35 } from "zod";
|
|
19071
|
+
var setupSkillProposalSignalSchema = z35.object({
|
|
19072
|
+
type: z35.literal("setup-skill-proposal"),
|
|
19073
|
+
content: z35.string(),
|
|
18828
19074
|
timestamp: IsoTimestampSchema
|
|
18829
19075
|
});
|
|
18830
19076
|
|
|
18831
19077
|
// src/integration/ai/contract/_engine/signals/skill-suggestions/schema.ts
|
|
18832
|
-
import { z as
|
|
18833
|
-
var skillSuggestionsSignalSchema =
|
|
18834
|
-
type:
|
|
18835
|
-
names:
|
|
19078
|
+
import { z as z36 } from "zod";
|
|
19079
|
+
var skillSuggestionsSignalSchema = z36.object({
|
|
19080
|
+
type: z36.literal("skill-suggestions"),
|
|
19081
|
+
names: z36.array(z36.string()).readonly(),
|
|
18836
19082
|
timestamp: IsoTimestampSchema
|
|
18837
19083
|
});
|
|
18838
19084
|
|
|
18839
19085
|
// src/integration/ai/contract/_engine/signals/verify-skill-proposal/schema.ts
|
|
18840
|
-
import { z as
|
|
18841
|
-
var verifySkillProposalSignalSchema =
|
|
18842
|
-
type:
|
|
18843
|
-
content:
|
|
19086
|
+
import { z as z37 } from "zod";
|
|
19087
|
+
var verifySkillProposalSignalSchema = z37.object({
|
|
19088
|
+
type: z37.literal("verify-skill-proposal"),
|
|
19089
|
+
content: z37.string(),
|
|
18844
19090
|
timestamp: IsoTimestampSchema
|
|
18845
19091
|
});
|
|
18846
19092
|
|
|
18847
19093
|
// src/application/flows/readiness/leaves/readiness.contract.ts
|
|
18848
|
-
var signalsArraySchemaRaw6 =
|
|
18849
|
-
|
|
19094
|
+
var signalsArraySchemaRaw6 = z38.array(
|
|
19095
|
+
z38.union([
|
|
18850
19096
|
learningSignalSchema,
|
|
18851
19097
|
noteSignalSchema,
|
|
18852
19098
|
agentsMdProposalSignalSchema,
|
|
@@ -19411,9 +19657,9 @@ var buildDetectSkillsPrompt = async (loader, input) => buildPrompt(loader, detec
|
|
|
19411
19657
|
});
|
|
19412
19658
|
|
|
19413
19659
|
// src/application/flows/detect-skills/leaves/propose.contract.ts
|
|
19414
|
-
import { z as
|
|
19660
|
+
import { z as z39 } from "zod";
|
|
19415
19661
|
var atMostOneOf = (kind) => (signals) => signals.filter((s) => s.type === kind).length <= 1;
|
|
19416
|
-
var signalsArraySchemaRaw7 =
|
|
19662
|
+
var signalsArraySchemaRaw7 = z39.array(z39.union([setupSkillProposalSignalSchema, verifySkillProposalSignalSchema, noteSignalSchema])).refine(atMostOneOf("setup-skill-proposal"), "at most one setup-skill-proposal per detect-skills spawn").refine(atMostOneOf("verify-skill-proposal"), "at most one verify-skill-proposal per detect-skills spawn");
|
|
19417
19663
|
var signalsArraySchema7 = brandSignalArray(signalsArraySchemaRaw7);
|
|
19418
19664
|
var wrapLegacyArray7 = (raw) => {
|
|
19419
19665
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -20168,27 +20414,27 @@ var buildDetectScriptsPrompt = async (loader, input) => buildPrompt(loader, dete
|
|
|
20168
20414
|
});
|
|
20169
20415
|
|
|
20170
20416
|
// src/application/flows/detect-scripts/leaves/propose.contract.ts
|
|
20171
|
-
import { z as
|
|
20417
|
+
import { z as z42 } from "zod";
|
|
20172
20418
|
|
|
20173
20419
|
// src/integration/ai/contract/_engine/signals/setup-script/schema.ts
|
|
20174
|
-
import { z as
|
|
20175
|
-
var setupScriptSignalSchema =
|
|
20176
|
-
type:
|
|
20177
|
-
command:
|
|
20420
|
+
import { z as z40 } from "zod";
|
|
20421
|
+
var setupScriptSignalSchema = z40.object({
|
|
20422
|
+
type: z40.literal("setup-script"),
|
|
20423
|
+
command: z40.string(),
|
|
20178
20424
|
timestamp: IsoTimestampSchema
|
|
20179
20425
|
});
|
|
20180
20426
|
|
|
20181
20427
|
// src/integration/ai/contract/_engine/signals/verify-script/schema.ts
|
|
20182
|
-
import { z as
|
|
20183
|
-
var verifyScriptSignalSchema =
|
|
20184
|
-
type:
|
|
20185
|
-
command:
|
|
20428
|
+
import { z as z41 } from "zod";
|
|
20429
|
+
var verifyScriptSignalSchema = z41.object({
|
|
20430
|
+
type: z41.literal("verify-script"),
|
|
20431
|
+
command: z41.string(),
|
|
20186
20432
|
timestamp: IsoTimestampSchema
|
|
20187
20433
|
});
|
|
20188
20434
|
|
|
20189
20435
|
// src/application/flows/detect-scripts/leaves/propose.contract.ts
|
|
20190
20436
|
var atMostOneOf2 = (kind) => (signals) => signals.filter((s) => s.type === kind).length <= 1;
|
|
20191
|
-
var signalsArraySchemaRaw8 =
|
|
20437
|
+
var signalsArraySchemaRaw8 = z42.array(z42.union([setupScriptSignalSchema, verifyScriptSignalSchema, noteSignalSchema])).refine(atMostOneOf2("setup-script"), "at most one setup-script signal per detect-scripts spawn").refine(atMostOneOf2("verify-script"), "at most one verify-script signal per detect-scripts spawn");
|
|
20192
20438
|
var signalsArraySchema8 = brandSignalArray(signalsArraySchemaRaw8);
|
|
20193
20439
|
var wrapLegacyArray8 = (raw) => {
|
|
20194
20440
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -20664,7 +20910,7 @@ var ideatePromptDef = {
|
|
|
20664
20910
|
partials: {
|
|
20665
20911
|
HARNESS_CONTEXT: "harness-context"
|
|
20666
20912
|
},
|
|
20667
|
-
expectedSignals: ["ideated-tickets"]
|
|
20913
|
+
expectedSignals: ["ideated-tickets", "note", "learning", "decision"]
|
|
20668
20914
|
};
|
|
20669
20915
|
var renderRepositories2 = (project) => {
|
|
20670
20916
|
if (project.repositories.length === 0) return "_no repositories configured_";
|
|
@@ -20682,19 +20928,19 @@ var buildIdeatePrompt = async (deps, input) => buildPrompt(deps, ideatePromptDef
|
|
|
20682
20928
|
var project_name = (project) => project.displayName;
|
|
20683
20929
|
|
|
20684
20930
|
// src/application/flows/ideate/leaves/ideate.contract.ts
|
|
20685
|
-
import { z as
|
|
20931
|
+
import { z as z44 } from "zod";
|
|
20686
20932
|
|
|
20687
20933
|
// src/integration/ai/contract/_engine/signals/ideated-tickets/schema.ts
|
|
20688
|
-
import { z as
|
|
20689
|
-
var ideatedTicketsSignalSchema =
|
|
20690
|
-
type:
|
|
20691
|
-
outputJson:
|
|
20934
|
+
import { z as z43 } from "zod";
|
|
20935
|
+
var ideatedTicketsSignalSchema = z43.object({
|
|
20936
|
+
type: z43.literal("ideated-tickets"),
|
|
20937
|
+
outputJson: z43.string(),
|
|
20692
20938
|
timestamp: IsoTimestampSchema
|
|
20693
20939
|
});
|
|
20694
20940
|
|
|
20695
20941
|
// src/application/flows/ideate/leaves/ideate.contract.ts
|
|
20696
20942
|
var exactlyOneIdeatedTickets = (signals) => signals.filter((s) => s.type === "ideated-tickets").length === 1;
|
|
20697
|
-
var signalsArraySchemaRaw9 =
|
|
20943
|
+
var signalsArraySchemaRaw9 = z44.array(z44.union([learningSignalSchema, noteSignalSchema, decisionSignalSchema, ideatedTicketsSignalSchema])).refine(exactlyOneIdeatedTickets, "exactly one ideated-tickets signal per ideate spawn");
|
|
20698
20944
|
var signalsArraySchema9 = brandSignalArray(signalsArraySchemaRaw9);
|
|
20699
20945
|
var wrapLegacyArray9 = (raw) => {
|
|
20700
20946
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -22767,7 +23013,7 @@ var ProjectsView = () => {
|
|
|
22767
23013
|
};
|
|
22768
23014
|
|
|
22769
23015
|
// src/application/ui/tui/views/project-detail-view.tsx
|
|
22770
|
-
import React49, { useEffect as useEffect19, useState as useState28 } from "react";
|
|
23016
|
+
import React49, { useEffect as useEffect19, useMemo as useMemo13, useState as useState28 } from "react";
|
|
22771
23017
|
import { Box as Box35, Text as Text37, useInput as useInput16 } from "ink";
|
|
22772
23018
|
|
|
22773
23019
|
// src/application/ui/tui/components/field-list.tsx
|
|
@@ -22806,7 +23052,6 @@ var ProjectDetailView = () => {
|
|
|
22806
23052
|
useViewHints([
|
|
22807
23053
|
{ keys: "r", label: "sprints" },
|
|
22808
23054
|
{ keys: "a", label: "add repo" },
|
|
22809
|
-
{ keys: "e", label: "edit project / repo field" },
|
|
22810
23055
|
{ keys: "d", label: "remove repo" },
|
|
22811
23056
|
{ keys: "c", label: "detect scripts" },
|
|
22812
23057
|
{ keys: "S", label: "detect skills" }
|
|
@@ -22830,7 +23075,21 @@ var ProjectDetailView = () => {
|
|
|
22830
23075
|
const [confirmRemove, setConfirmRemove] = useState28(void 0);
|
|
22831
23076
|
const [feedback, setFeedback] = useState28(void 0);
|
|
22832
23077
|
const project = state.kind === "ok" ? state.value : void 0;
|
|
22833
|
-
const
|
|
23078
|
+
const fields = useMemo13(() => {
|
|
23079
|
+
if (project === void 0) return [];
|
|
23080
|
+
return [
|
|
23081
|
+
{ kind: "project", field: "displayName" },
|
|
23082
|
+
...project.repositories.flatMap((r) => [
|
|
23083
|
+
{ kind: "repo", field: "name", repo: r },
|
|
23084
|
+
{ kind: "repo", field: "setupScript", repo: r },
|
|
23085
|
+
{ kind: "repo", field: "verifyScript", repo: r }
|
|
23086
|
+
])
|
|
23087
|
+
];
|
|
23088
|
+
}, [project]);
|
|
23089
|
+
const focused = fields[Math.min(cursorIdx, Math.max(0, fields.length - 1))];
|
|
23090
|
+
useEffect19(() => {
|
|
23091
|
+
if (state.kind === "ok") setCursorIdx(0);
|
|
23092
|
+
}, [state.kind, projectId]);
|
|
22834
23093
|
const launchPerRepoFlow = async (flowId, target) => {
|
|
22835
23094
|
if (project === void 0) return;
|
|
22836
23095
|
setFeedback(void 0);
|
|
@@ -22904,30 +23163,11 @@ var ProjectDetailView = () => {
|
|
|
22904
23163
|
};
|
|
22905
23164
|
};
|
|
22906
23165
|
const handleEdit = () => {
|
|
22907
|
-
if (project === void 0) return;
|
|
23166
|
+
if (project === void 0 || focused === void 0) return;
|
|
22908
23167
|
setFeedback(void 0);
|
|
22909
|
-
const
|
|
22910
|
-
const
|
|
22911
|
-
|
|
22912
|
-
...focusedRepo !== void 0 ? [
|
|
22913
|
-
{ label: `Repo "${focusedRepo.name}": name`, value: { kind: "repo", field: "name", repo: focusedRepo } },
|
|
22914
|
-
{
|
|
22915
|
-
label: `Repo "${focusedRepo.name}": setupScript`,
|
|
22916
|
-
value: { kind: "repo", field: "setupScript", repo: focusedRepo }
|
|
22917
|
-
},
|
|
22918
|
-
{
|
|
22919
|
-
label: `Repo "${focusedRepo.name}": verifyScript`,
|
|
22920
|
-
value: { kind: "repo", field: "verifyScript", repo: focusedRepo }
|
|
22921
|
-
}
|
|
22922
|
-
] : []
|
|
22923
|
-
];
|
|
22924
|
-
new Promise((resolve, reject) => {
|
|
22925
|
-
queue.enqueue({ kind: "choice", message: "Edit which field?", options, resolve, reject });
|
|
22926
|
-
}).then((target) => {
|
|
22927
|
-
const cfg = renderEditPrompt(target);
|
|
22928
|
-
if (cfg !== void 0) void edit.openEditPrompt(cfg);
|
|
22929
|
-
}).catch(() => {
|
|
22930
|
-
});
|
|
23168
|
+
const target = focused.kind === "project" ? { kind: "project" } : { kind: "repo", field: focused.field, repo: focused.repo };
|
|
23169
|
+
const cfg = renderEditPrompt(target);
|
|
23170
|
+
if (cfg !== void 0) void edit.openEditPrompt(cfg);
|
|
22931
23171
|
};
|
|
22932
23172
|
useInput16((input, key) => {
|
|
22933
23173
|
if (ui.helpOpen || ui.promptActive || confirmRemove !== void 0 || project === void 0) return;
|
|
@@ -22935,31 +23175,28 @@ var ProjectDetailView = () => {
|
|
|
22935
23175
|
router.push({ id: "add-repository", props: { projectId: project.id } });
|
|
22936
23176
|
return;
|
|
22937
23177
|
}
|
|
22938
|
-
if (input === "e") {
|
|
23178
|
+
if (input === "e" || key.return) {
|
|
22939
23179
|
handleEdit();
|
|
22940
23180
|
return;
|
|
22941
23181
|
}
|
|
22942
|
-
if (
|
|
22943
|
-
setCursorIdx((c) => Math.min(
|
|
23182
|
+
if (key.downArrow || input === "j") {
|
|
23183
|
+
setCursorIdx((c) => Math.min(Math.max(0, fields.length - 1), c + 1));
|
|
22944
23184
|
return;
|
|
22945
23185
|
}
|
|
22946
|
-
if (
|
|
23186
|
+
if (key.upArrow || input === "k") {
|
|
22947
23187
|
setCursorIdx((c) => Math.max(0, c - 1));
|
|
22948
23188
|
return;
|
|
22949
23189
|
}
|
|
22950
|
-
if (input === "d" &&
|
|
22951
|
-
|
|
22952
|
-
if (target !== void 0) setConfirmRemove(target);
|
|
23190
|
+
if (input === "d" && focused?.kind === "repo") {
|
|
23191
|
+
setConfirmRemove(focused.repo);
|
|
22953
23192
|
return;
|
|
22954
23193
|
}
|
|
22955
|
-
if (input === "c" &&
|
|
22956
|
-
|
|
22957
|
-
if (target !== void 0) void launchPerRepoFlow("detect-scripts", target);
|
|
23194
|
+
if (input === "c" && focused?.kind === "repo") {
|
|
23195
|
+
void launchPerRepoFlow("detect-scripts", focused.repo);
|
|
22958
23196
|
return;
|
|
22959
23197
|
}
|
|
22960
|
-
if (input === "S" &&
|
|
22961
|
-
|
|
22962
|
-
if (target !== void 0) void launchPerRepoFlow("detect-skills", target);
|
|
23198
|
+
if (input === "S" && focused?.kind === "repo") {
|
|
23199
|
+
void launchPerRepoFlow("detect-skills", focused.repo);
|
|
22963
23200
|
}
|
|
22964
23201
|
});
|
|
22965
23202
|
const claimPrompt = ui.claimPrompt;
|
|
@@ -22991,14 +23228,7 @@ var ProjectDetailView = () => {
|
|
|
22991
23228
|
onCancel: () => setConfirmRemove(void 0)
|
|
22992
23229
|
}
|
|
22993
23230
|
) })
|
|
22994
|
-
] }) : /* @__PURE__ */ jsx47(
|
|
22995
|
-
Body,
|
|
22996
|
-
{
|
|
22997
|
-
project: state.value,
|
|
22998
|
-
cursorIdx: Math.min(cursorIdx, Math.max(0, repos.length - 1)),
|
|
22999
|
-
feedback: feedback ?? edit.feedback
|
|
23000
|
-
}
|
|
23001
|
-
) });
|
|
23231
|
+
] }) : /* @__PURE__ */ jsx47(Body, { project: state.value, focused, feedback: feedback ?? edit.feedback }) });
|
|
23002
23232
|
};
|
|
23003
23233
|
var removeRepoFromProject = async (project, repoId, projectRepo) => {
|
|
23004
23234
|
const updated = removeRepository(project, repoId);
|
|
@@ -23007,85 +23237,91 @@ var removeRepoFromProject = async (project, repoId, projectRepo) => {
|
|
|
23007
23237
|
if (!saved.ok) return { ok: false, error: saved.error.message };
|
|
23008
23238
|
return { ok: true };
|
|
23009
23239
|
};
|
|
23010
|
-
var
|
|
23011
|
-
|
|
23012
|
-
|
|
23240
|
+
var focusable = (focused, node) => /* @__PURE__ */ jsxs36(Text37, { ...focused ? { color: inkColors.primary } : {}, bold: focused, children: [
|
|
23241
|
+
focused ? `${glyphs.actionCursor} ` : " ",
|
|
23242
|
+
node
|
|
23243
|
+
] });
|
|
23244
|
+
var noneText = /* @__PURE__ */ jsx47(Text37, { dimColor: true, italic: true, children: "(none)" });
|
|
23245
|
+
var RepoCard = ({ repo, focused }) => {
|
|
23246
|
+
const repoFocused = focused?.kind === "repo" && focused.repo.id === repo.id;
|
|
23247
|
+
const nameFocused = repoFocused && focused.field === "name";
|
|
23248
|
+
const setupFocused = repoFocused && focused.field === "setupScript";
|
|
23249
|
+
const verifyFocused = repoFocused && focused.field === "verifyScript";
|
|
23250
|
+
return /* @__PURE__ */ jsxs36(
|
|
23251
|
+
Box35,
|
|
23013
23252
|
{
|
|
23014
|
-
|
|
23015
|
-
|
|
23016
|
-
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23253
|
+
flexDirection: "column",
|
|
23254
|
+
borderStyle: "round",
|
|
23255
|
+
borderColor: inkColors.rule,
|
|
23256
|
+
paddingX: spacing.cardPadX,
|
|
23257
|
+
marginTop: 1,
|
|
23258
|
+
children: [
|
|
23259
|
+
/* @__PURE__ */ jsxs36(Text37, { bold: true, ...nameFocused ? { color: inkColors.primary } : {}, children: [
|
|
23260
|
+
nameFocused ? `${glyphs.actionCursor} ` : " ",
|
|
23261
|
+
repo.name,
|
|
23262
|
+
" ",
|
|
23263
|
+
/* @__PURE__ */ jsxs36(Text37, { dimColor: true, children: [
|
|
23264
|
+
"(",
|
|
23265
|
+
repo.slug,
|
|
23266
|
+
")"
|
|
23267
|
+
] })
|
|
23268
|
+
] }),
|
|
23269
|
+
/* @__PURE__ */ jsx47(
|
|
23270
|
+
FieldList,
|
|
23271
|
+
{
|
|
23272
|
+
fields: [
|
|
23273
|
+
{ label: "Path", value: /* @__PURE__ */ jsx47(Text37, { dimColor: true, children: repo.path }) },
|
|
23274
|
+
{ label: "Setup", value: focusable(setupFocused, repo.setupScript ?? noneText) },
|
|
23275
|
+
{ label: "Verify", value: focusable(verifyFocused, repo.verifyScript ?? noneText) }
|
|
23276
|
+
]
|
|
23277
|
+
}
|
|
23278
|
+
)
|
|
23020
23279
|
]
|
|
23021
23280
|
}
|
|
23022
|
-
)
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
|
|
23033
|
-
|
|
23034
|
-
|
|
23035
|
-
|
|
23036
|
-
|
|
23037
|
-
|
|
23038
|
-
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
|
|
23042
|
-
|
|
23043
|
-
|
|
23044
|
-
|
|
23045
|
-
|
|
23046
|
-
|
|
23047
|
-
|
|
23048
|
-
|
|
23049
|
-
|
|
23050
|
-
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
|
|
23054
|
-
|
|
23055
|
-
|
|
23056
|
-
|
|
23057
|
-
|
|
23058
|
-
|
|
23059
|
-
|
|
23060
|
-
|
|
23061
|
-
|
|
23062
|
-
|
|
23063
|
-
|
|
23064
|
-
|
|
23065
|
-
|
|
23066
|
-
]
|
|
23067
|
-
},
|
|
23068
|
-
repo.id
|
|
23069
|
-
);
|
|
23070
|
-
}),
|
|
23071
|
-
/* @__PURE__ */ jsx47(Box35, { paddingX: spacing.indent, marginTop: spacing.section, children: /* @__PURE__ */ jsxs36(Text37, { dimColor: true, children: [
|
|
23072
|
-
glyphs.bullet,
|
|
23073
|
-
" a add ",
|
|
23074
|
-
glyphs.bullet,
|
|
23075
|
-
" \u2191/\u2193 select ",
|
|
23076
|
-
glyphs.bullet,
|
|
23077
|
-
" e edit field ",
|
|
23078
|
-
glyphs.bullet,
|
|
23079
|
-
" c detect scripts",
|
|
23080
|
-
" ",
|
|
23081
|
-
glyphs.bullet,
|
|
23082
|
-
" S detect skills ",
|
|
23083
|
-
glyphs.bullet,
|
|
23084
|
-
" d remove (keeps \u2265 1)"
|
|
23085
|
-
] }) }),
|
|
23086
|
-
feedback !== void 0 && /* @__PURE__ */ jsx47(Box35, { paddingX: spacing.indent, marginTop: 1, children: /* @__PURE__ */ jsx47(Text37, { color: feedback.startsWith("\u2717") ? inkColors.error : inkColors.primary, children: feedback }) })
|
|
23087
|
-
] })
|
|
23088
|
-
] });
|
|
23281
|
+
);
|
|
23282
|
+
};
|
|
23283
|
+
var Body = ({ project, focused, feedback }) => {
|
|
23284
|
+
const projectNameFocused = focused?.kind === "project";
|
|
23285
|
+
return /* @__PURE__ */ jsxs36(Box35, { flexDirection: "column", children: [
|
|
23286
|
+
/* @__PURE__ */ jsx47(Card, { title: "Project", tone: "primary", children: /* @__PURE__ */ jsx47(
|
|
23287
|
+
FieldList,
|
|
23288
|
+
{
|
|
23289
|
+
fields: [
|
|
23290
|
+
{
|
|
23291
|
+
label: "Name",
|
|
23292
|
+
value: focusable(projectNameFocused, /* @__PURE__ */ jsx47(Text37, { bold: true, children: project.displayName }))
|
|
23293
|
+
},
|
|
23294
|
+
{ label: "Slug", value: project.slug },
|
|
23295
|
+
{ label: "Id", value: /* @__PURE__ */ jsx47(Text37, { dimColor: true, children: project.id }) },
|
|
23296
|
+
...project.description !== void 0 ? [{ label: "Description", value: project.description }] : [],
|
|
23297
|
+
{ label: "Repositories", value: String(project.repositories.length) }
|
|
23298
|
+
]
|
|
23299
|
+
}
|
|
23300
|
+
) }),
|
|
23301
|
+
/* @__PURE__ */ jsxs36(Box35, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
23302
|
+
/* @__PURE__ */ jsxs36(Text37, { bold: true, children: [
|
|
23303
|
+
glyphs.badge,
|
|
23304
|
+
" Repositories"
|
|
23305
|
+
] }),
|
|
23306
|
+
project.repositories.map((repo) => /* @__PURE__ */ jsx47(RepoCard, { repo, focused }, repo.id)),
|
|
23307
|
+
/* @__PURE__ */ jsx47(Box35, { paddingX: spacing.indent, marginTop: spacing.section, children: /* @__PURE__ */ jsxs36(Text37, { dimColor: true, children: [
|
|
23308
|
+
"a add ",
|
|
23309
|
+
glyphs.bullet,
|
|
23310
|
+
" \u2191/\u2193 navigate ",
|
|
23311
|
+
glyphs.bullet,
|
|
23312
|
+
" e/\u21B5 edit field ",
|
|
23313
|
+
glyphs.bullet,
|
|
23314
|
+
" c detect scripts",
|
|
23315
|
+
" ",
|
|
23316
|
+
glyphs.bullet,
|
|
23317
|
+
" S detect skills ",
|
|
23318
|
+
glyphs.bullet,
|
|
23319
|
+
" d remove (keeps \u2265 1)"
|
|
23320
|
+
] }) }),
|
|
23321
|
+
feedback !== void 0 && /* @__PURE__ */ jsx47(Box35, { paddingX: spacing.indent, marginTop: 1, children: /* @__PURE__ */ jsx47(Text37, { color: feedback.startsWith("\u2717") ? inkColors.error : inkColors.primary, children: feedback }) })
|
|
23322
|
+
] })
|
|
23323
|
+
] });
|
|
23324
|
+
};
|
|
23089
23325
|
|
|
23090
23326
|
// src/application/ui/tui/views/sprints-view.tsx
|
|
23091
23327
|
import { useEffect as useEffect20, useState as useState29 } from "react";
|
|
@@ -23138,8 +23374,8 @@ var SprintsView = () => {
|
|
|
23138
23374
|
const { state, reload } = useAsyncLoad(async () => {
|
|
23139
23375
|
const r = await deps.sprintRepo.list();
|
|
23140
23376
|
if (!r.ok) throw new Error(r.error.message);
|
|
23141
|
-
const
|
|
23142
|
-
return
|
|
23377
|
+
const scoped = selection.projectId !== void 0 ? r.value.filter((s) => s.projectId === selection.projectId) : r.value;
|
|
23378
|
+
return [...scoped].sort((a, b) => a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
|
|
23143
23379
|
}, [selection.projectId]);
|
|
23144
23380
|
const items = state.kind === "ok" ? state.value : [];
|
|
23145
23381
|
const [cursorId, setCursorId] = useState29(void 0);
|
|
@@ -23392,7 +23628,7 @@ var SprintsView = () => {
|
|
|
23392
23628
|
};
|
|
23393
23629
|
|
|
23394
23630
|
// src/application/ui/tui/views/sprint-detail-view.tsx
|
|
23395
|
-
import { useEffect as useEffect22, useMemo as
|
|
23631
|
+
import { useEffect as useEffect22, useMemo as useMemo14, useState as useState31 } from "react";
|
|
23396
23632
|
import { Box as Box44, Text as Text46 } from "ink";
|
|
23397
23633
|
|
|
23398
23634
|
// src/application/flows/ticket-remove/flow.ts
|
|
@@ -24308,8 +24544,8 @@ var SprintDetailView = () => {
|
|
|
24308
24544
|
const selection = useSelection();
|
|
24309
24545
|
const { state, project, reload } = useSprintBundle({ sprintId, deps });
|
|
24310
24546
|
const sprint = state.kind === "ok" ? state.value.sprint : void 0;
|
|
24311
|
-
const tasks =
|
|
24312
|
-
const focusList =
|
|
24547
|
+
const tasks = useMemo14(() => state.kind === "ok" ? state.value.tasks : [], [state]);
|
|
24548
|
+
const focusList = useMemo14(() => sprint !== void 0 ? buildFocusList(sprint, tasks) : [], [sprint, tasks]);
|
|
24313
24549
|
const [cursorIdx, setCursorIdx] = useState31(0);
|
|
24314
24550
|
const [openIds, setOpenIds] = useState31(() => /* @__PURE__ */ new Set());
|
|
24315
24551
|
const [confirmRemove, setConfirmRemove] = useState31(void 0);
|
|
@@ -24527,13 +24763,12 @@ var useSinkStream = (bus, opts = {}) => {
|
|
|
24527
24763
|
const [items, setItems] = useState33(() => replay ? bus.entries.slice(-limit) : []);
|
|
24528
24764
|
useEffect24(() => {
|
|
24529
24765
|
if (replay) setItems(bus.entries.slice(-limit));
|
|
24530
|
-
|
|
24766
|
+
return bus.subscribe((value) => {
|
|
24531
24767
|
setItems((prev) => {
|
|
24532
24768
|
const next = [...prev, value];
|
|
24533
24769
|
return next.length > limit ? next.slice(next.length - limit) : next;
|
|
24534
24770
|
});
|
|
24535
24771
|
});
|
|
24536
|
-
return unsub;
|
|
24537
24772
|
}, [bus, limit, replay]);
|
|
24538
24773
|
return items;
|
|
24539
24774
|
};
|
|
@@ -24546,14 +24781,13 @@ var useEventBusBuffer = (bus, opts) => {
|
|
|
24546
24781
|
const filterRef = useRef11(opts.filter);
|
|
24547
24782
|
filterRef.current = opts.filter;
|
|
24548
24783
|
useEffect25(() => {
|
|
24549
|
-
|
|
24784
|
+
return bus.subscribe((event) => {
|
|
24550
24785
|
if (!filterRef.current(event)) return;
|
|
24551
24786
|
setItems((prev) => {
|
|
24552
24787
|
const next = [...prev, event];
|
|
24553
24788
|
return next.length > limit ? next.slice(next.length - limit) : next;
|
|
24554
24789
|
});
|
|
24555
24790
|
});
|
|
24556
|
-
return unsub;
|
|
24557
24791
|
}, [bus, limit]);
|
|
24558
24792
|
return items;
|
|
24559
24793
|
};
|
|
@@ -24888,7 +25122,7 @@ import "react";
|
|
|
24888
25122
|
import { Box as Box53 } from "ink";
|
|
24889
25123
|
|
|
24890
25124
|
// src/application/ui/tui/components/baseline-health-card.tsx
|
|
24891
|
-
import { useMemo as
|
|
25125
|
+
import { useMemo as useMemo15 } from "react";
|
|
24892
25126
|
import { Box as Box49, Text as Text51 } from "ink";
|
|
24893
25127
|
import { jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
24894
25128
|
var tierColor3 = (tier) => {
|
|
@@ -25026,14 +25260,14 @@ var CompactCleanRow = ({ rows }) => {
|
|
|
25026
25260
|
};
|
|
25027
25261
|
var BaselineHealthCard = ({ execution, tasks, now, width }) => {
|
|
25028
25262
|
const tNow = now ?? Date.now();
|
|
25029
|
-
const taskList =
|
|
25263
|
+
const taskList = useMemo15(() => tasks ?? [], [tasks]);
|
|
25030
25264
|
const cardWidth = width ?? CONTEXT_WIDTH;
|
|
25031
|
-
const setupData =
|
|
25032
|
-
const preRun =
|
|
25033
|
-
const postRun =
|
|
25265
|
+
const setupData = useMemo15(() => setupRowData(execution, tNow), [execution, tNow]);
|
|
25266
|
+
const preRun = useMemo15(() => latestVerifyRun(taskList, "pre"), [taskList]);
|
|
25267
|
+
const postRun = useMemo15(() => latestVerifyRun(taskList, "post"), [taskList]);
|
|
25034
25268
|
const preData = verifyRowData(preRun, tNow, "Pre verify");
|
|
25035
25269
|
const postData = verifyRowData(postRun, tNow, "Post verify");
|
|
25036
|
-
const counts =
|
|
25270
|
+
const counts = useMemo15(() => countAttributions(taskList), [taskList]);
|
|
25037
25271
|
const attribData = attributionRowData(counts);
|
|
25038
25272
|
const rows = [setupData, preData, postData, attribData];
|
|
25039
25273
|
const health = synthesiseBaselineHealth({
|
|
@@ -25155,7 +25389,7 @@ var Section2 = ({
|
|
|
25155
25389
|
import "react";
|
|
25156
25390
|
|
|
25157
25391
|
// src/application/ui/tui/components/step-trace.tsx
|
|
25158
|
-
import { useMemo as
|
|
25392
|
+
import { useMemo as useMemo16 } from "react";
|
|
25159
25393
|
import { Box as Box52, Text as Text54 } from "ink";
|
|
25160
25394
|
import { Fragment as Fragment5, jsx as jsx64, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
25161
25395
|
var glyphFor2 = (status) => {
|
|
@@ -25237,12 +25471,12 @@ var StepTrace = ({
|
|
|
25237
25471
|
railWidth
|
|
25238
25472
|
}) => {
|
|
25239
25473
|
const traceLastEntry = trace[trace.length - 1];
|
|
25240
|
-
const merged =
|
|
25474
|
+
const merged = useMemo16(
|
|
25241
25475
|
() => plan !== void 0 ? mergePlanWithTrace(plan, trace, running, labelByName) : traceToRows(trace),
|
|
25242
25476
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- in-place ring-buffer mutation; see comment above
|
|
25243
25477
|
[plan, labelByName, trace, trace.length, traceLastEntry, running]
|
|
25244
25478
|
);
|
|
25245
|
-
const filtered =
|
|
25479
|
+
const filtered = useMemo16(
|
|
25246
25480
|
() => filter !== void 0 ? merged.filter((r) => filter(r.name)) : merged,
|
|
25247
25481
|
[merged, filter]
|
|
25248
25482
|
);
|
|
@@ -25791,7 +26025,7 @@ var ExecuteBody = ({
|
|
|
25791
26025
|
] });
|
|
25792
26026
|
|
|
25793
26027
|
// src/application/ui/tui/views/execute-view-internals/tasks-panel-host.tsx
|
|
25794
|
-
import { useMemo as
|
|
26028
|
+
import { useMemo as useMemo17 } from "react";
|
|
25795
26029
|
import { jsx as jsx72 } from "react/jsx-runtime";
|
|
25796
26030
|
var TasksPanelHost = ({
|
|
25797
26031
|
bucketed,
|
|
@@ -25802,7 +26036,7 @@ var TasksPanelHost = ({
|
|
|
25802
26036
|
now,
|
|
25803
26037
|
taskState
|
|
25804
26038
|
}) => {
|
|
25805
|
-
const taskCriteriaById =
|
|
26039
|
+
const taskCriteriaById = useMemo17(() => {
|
|
25806
26040
|
if (taskState === void 0) return void 0;
|
|
25807
26041
|
const m = /* @__PURE__ */ new Map();
|
|
25808
26042
|
for (const t of taskState) {
|
|
@@ -25951,25 +26185,31 @@ var useBaselineHealthData = ({
|
|
|
25951
26185
|
};
|
|
25952
26186
|
|
|
25953
26187
|
// src/application/ui/tui/views/execute-view-internals/use-bucketed-tasks.ts
|
|
25954
|
-
import { useMemo as
|
|
26188
|
+
import { useMemo as useMemo18 } from "react";
|
|
25955
26189
|
|
|
25956
26190
|
// src/application/ui/tui/runtime/use-task-round-tracker.ts
|
|
25957
26191
|
import { useEffect as useEffect28, useState as useState35 } from "react";
|
|
26192
|
+
var TASK_ROUND_CAP = 500;
|
|
25958
26193
|
var isTaskRoundStarted = (e) => e.type === "task-round-started";
|
|
25959
26194
|
var useTaskRoundTracker = (bus) => {
|
|
25960
26195
|
const [rounds, setRounds] = useState35(() => /* @__PURE__ */ new Map());
|
|
25961
26196
|
useEffect28(() => {
|
|
25962
|
-
|
|
26197
|
+
return bus.subscribe((event) => {
|
|
25963
26198
|
if (!isTaskRoundStarted(event)) return;
|
|
25964
26199
|
setRounds((prev) => {
|
|
25965
26200
|
const existing = prev.get(event.taskId);
|
|
25966
26201
|
if (existing !== void 0 && existing.roundN >= event.roundN) return prev;
|
|
25967
26202
|
const next = new Map(prev);
|
|
26203
|
+
next.delete(event.taskId);
|
|
25968
26204
|
next.set(event.taskId, { roundN: event.roundN, totalCap: event.totalCap });
|
|
26205
|
+
while (next.size > TASK_ROUND_CAP) {
|
|
26206
|
+
const oldest = next.keys().next().value;
|
|
26207
|
+
if (oldest === void 0) break;
|
|
26208
|
+
next.delete(oldest);
|
|
26209
|
+
}
|
|
25969
26210
|
return next;
|
|
25970
26211
|
});
|
|
25971
26212
|
});
|
|
25972
|
-
return unsub;
|
|
25973
26213
|
}, [bus]);
|
|
25974
26214
|
return rounds;
|
|
25975
26215
|
};
|
|
@@ -25981,7 +26221,7 @@ var useBucketedTasks = ({
|
|
|
25981
26221
|
signals,
|
|
25982
26222
|
eventBus
|
|
25983
26223
|
}) => {
|
|
25984
|
-
const rawBucketed =
|
|
26224
|
+
const rawBucketed = useMemo18(
|
|
25985
26225
|
() => descriptor ? bucketTaskSignals(descriptor.trace, chainEvents, signals, {
|
|
25986
26226
|
...descriptor.maxTurns !== void 0 ? { maxTurns: descriptor.maxTurns } : {},
|
|
25987
26227
|
...descriptor.terminalSubstepName !== void 0 ? { terminalSubstepName: descriptor.terminalSubstepName } : {},
|
|
@@ -25994,7 +26234,7 @@ var useBucketedTasks = ({
|
|
|
25994
26234
|
[descriptor, chainEvents, signals]
|
|
25995
26235
|
);
|
|
25996
26236
|
const taskRounds = useTaskRoundTracker(eventBus);
|
|
25997
|
-
const bucketed =
|
|
26237
|
+
const bucketed = useMemo18(() => {
|
|
25998
26238
|
if (rawBucketed === void 0) return void 0;
|
|
25999
26239
|
const tasks = rawBucketed.tasks.map((t) => {
|
|
26000
26240
|
const tracked = taskRounds.get(t.id);
|
|
@@ -26102,14 +26342,14 @@ var useCancelHandlers = ({
|
|
|
26102
26342
|
};
|
|
26103
26343
|
|
|
26104
26344
|
// src/application/ui/tui/views/execute-view-internals/use-cancel-scope-stats.ts
|
|
26105
|
-
import { useMemo as
|
|
26345
|
+
import { useMemo as useMemo19 } from "react";
|
|
26106
26346
|
var useCancelScopeStats = ({
|
|
26107
26347
|
chainEvents,
|
|
26108
26348
|
currentTask,
|
|
26109
26349
|
bucketed,
|
|
26110
26350
|
now
|
|
26111
26351
|
}) => {
|
|
26112
|
-
const attemptElapsedMs2 =
|
|
26352
|
+
const attemptElapsedMs2 = useMemo19(() => {
|
|
26113
26353
|
if (currentTask === void 0) return void 0;
|
|
26114
26354
|
let latestStartMs;
|
|
26115
26355
|
for (const ev of chainEvents) {
|
|
@@ -26120,7 +26360,7 @@ var useCancelScopeStats = ({
|
|
|
26120
26360
|
}
|
|
26121
26361
|
return latestStartMs !== void 0 ? Math.max(0, now - latestStartMs) : void 0;
|
|
26122
26362
|
}, [chainEvents, currentTask, now]);
|
|
26123
|
-
const remainingTaskCount =
|
|
26363
|
+
const remainingTaskCount = useMemo19(() => {
|
|
26124
26364
|
if (bucketed === void 0) return 0;
|
|
26125
26365
|
return bucketed.tasks.reduce((n, t) => t.status === "completed" ? n : n + 1, 0);
|
|
26126
26366
|
}, [bucketed]);
|
|
@@ -26341,7 +26581,7 @@ import { useEffect as useEffect31, useState as useState38 } from "react";
|
|
|
26341
26581
|
import { Box as Box60, Text as Text59, useInput as useInput22 } from "ink";
|
|
26342
26582
|
|
|
26343
26583
|
// src/application/ui/tui/components/list-view.tsx
|
|
26344
|
-
import { useEffect as useEffect30, useMemo as
|
|
26584
|
+
import { useEffect as useEffect30, useMemo as useMemo20, useState as useState37 } from "react";
|
|
26345
26585
|
import { Box as Box59, Text as Text58, useInput as useInput21 } from "ink";
|
|
26346
26586
|
import { jsx as jsx74, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
26347
26587
|
var clamp4 = (n, min, max) => Math.max(min, Math.min(max, n));
|
|
@@ -26380,7 +26620,7 @@ function ListView({
|
|
|
26380
26620
|
},
|
|
26381
26621
|
{ isActive: active }
|
|
26382
26622
|
);
|
|
26383
|
-
const window =
|
|
26623
|
+
const window = useMemo20(() => {
|
|
26384
26624
|
const half = Math.floor(visibleRows / 2);
|
|
26385
26625
|
const start = clamp4(cursor - half, 0, Math.max(0, items.length - visibleRows));
|
|
26386
26626
|
const end = Math.min(items.length, start + visibleRows);
|
|
@@ -26529,7 +26769,7 @@ var SessionsView = () => {
|
|
|
26529
26769
|
};
|
|
26530
26770
|
|
|
26531
26771
|
// src/application/ui/tui/views/settings-view.tsx
|
|
26532
|
-
import React86, { useEffect as useEffect32, useMemo as
|
|
26772
|
+
import React86, { useEffect as useEffect32, useMemo as useMemo21, useState as useState39 } from "react";
|
|
26533
26773
|
import { Box as Box64, Text as Text63, useInput as useInput23 } from "ink";
|
|
26534
26774
|
|
|
26535
26775
|
// src/application/flows/settings-show/flow.ts
|
|
@@ -26554,11 +26794,11 @@ var MIXED = {
|
|
|
26554
26794
|
refine: { provider: "openai-codex", model: "gpt-5.5" },
|
|
26555
26795
|
plan: { provider: "github-copilot", model: "claude-sonnet-4.6", effort: "xhigh" },
|
|
26556
26796
|
implement: {
|
|
26557
|
-
generator: { provider: "claude-code", model: "claude-opus-4-
|
|
26558
|
-
evaluator: { provider: "claude-code", model: "claude-opus-4-
|
|
26797
|
+
generator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" },
|
|
26798
|
+
evaluator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" }
|
|
26559
26799
|
},
|
|
26560
26800
|
readiness: { provider: "github-copilot", model: "gpt-5-mini", effort: "medium" },
|
|
26561
|
-
ideate: { provider: "claude-code", model: "claude-opus-4-
|
|
26801
|
+
ideate: { provider: "claude-code", model: "claude-opus-4-8" },
|
|
26562
26802
|
// PR content drafting mirrors refine's "light summary" reasoning profile — a fast Codex
|
|
26563
26803
|
// model is fine, no need to pay for Opus tokens just to summarise a diff.
|
|
26564
26804
|
createPr: { provider: "openai-codex", model: "gpt-5.4-mini" }
|
|
@@ -26566,13 +26806,13 @@ var MIXED = {
|
|
|
26566
26806
|
var CLAUDE_ONLY = {
|
|
26567
26807
|
effort: "high",
|
|
26568
26808
|
refine: { provider: "claude-code", model: "claude-sonnet-4-6" },
|
|
26569
|
-
plan: { provider: "claude-code", model: "claude-opus-4-
|
|
26809
|
+
plan: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" },
|
|
26570
26810
|
implement: {
|
|
26571
|
-
generator: { provider: "claude-code", model: "claude-opus-4-
|
|
26572
|
-
evaluator: { provider: "claude-code", model: "claude-opus-4-
|
|
26811
|
+
generator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" },
|
|
26812
|
+
evaluator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" }
|
|
26573
26813
|
},
|
|
26574
26814
|
readiness: { provider: "claude-code", model: "claude-haiku-4-5", effort: "medium" },
|
|
26575
|
-
ideate: { provider: "claude-code", model: "claude-opus-4-
|
|
26815
|
+
ideate: { provider: "claude-code", model: "claude-opus-4-8" },
|
|
26576
26816
|
createPr: { provider: "claude-code", model: "claude-sonnet-4-6" }
|
|
26577
26817
|
};
|
|
26578
26818
|
var COPILOT_ONLY = {
|
|
@@ -27247,12 +27487,12 @@ var SettingsView = () => {
|
|
|
27247
27487
|
cancelled = true;
|
|
27248
27488
|
};
|
|
27249
27489
|
}, []);
|
|
27250
|
-
const sections =
|
|
27490
|
+
const sections = useMemo21(
|
|
27251
27491
|
() => settings === void 0 ? [] : buildSections(settings),
|
|
27252
27492
|
[settings]
|
|
27253
27493
|
);
|
|
27254
27494
|
const activeSection = sections[sectionIdx];
|
|
27255
|
-
const activeFields =
|
|
27495
|
+
const activeFields = useMemo21(() => activeSection?.fields ?? [], [activeSection]);
|
|
27256
27496
|
useEffect32(() => {
|
|
27257
27497
|
if (cursor >= activeFields.length && activeFields.length > 0) setCursor(activeFields.length - 1);
|
|
27258
27498
|
}, [activeFields, cursor]);
|
|
@@ -28091,20 +28331,20 @@ var renderIssueRefs = (refs) => {
|
|
|
28091
28331
|
var buildCreatePrPrompt = async (deps, input) => buildPrompt(deps, createPrPromptDef, input);
|
|
28092
28332
|
|
|
28093
28333
|
// src/application/flows/create-pr/leaves/generate-pr-content.contract.ts
|
|
28094
|
-
import { z as
|
|
28334
|
+
import { z as z46 } from "zod";
|
|
28095
28335
|
|
|
28096
28336
|
// src/integration/ai/contract/_engine/signals/pr-content/schema.ts
|
|
28097
|
-
import { z as
|
|
28098
|
-
var prContentSignalSchema =
|
|
28099
|
-
type:
|
|
28100
|
-
title:
|
|
28101
|
-
body:
|
|
28337
|
+
import { z as z45 } from "zod";
|
|
28338
|
+
var prContentSignalSchema = z45.object({
|
|
28339
|
+
type: z45.literal("pr-content"),
|
|
28340
|
+
title: z45.string(),
|
|
28341
|
+
body: z45.string(),
|
|
28102
28342
|
timestamp: IsoTimestampSchema
|
|
28103
28343
|
});
|
|
28104
28344
|
|
|
28105
28345
|
// src/application/flows/create-pr/leaves/generate-pr-content.contract.ts
|
|
28106
28346
|
var exactlyOnePrContent = (signals) => signals.filter((s) => s.type === "pr-content").length === 1;
|
|
28107
|
-
var signalsArraySchemaRaw10 =
|
|
28347
|
+
var signalsArraySchemaRaw10 = z46.array(prContentSignalSchema).refine(exactlyOnePrContent, "exactly one pr-content signal per create-pr spawn");
|
|
28108
28348
|
var signalsArraySchema10 = brandSignalArray(signalsArraySchemaRaw10);
|
|
28109
28349
|
var prContentSidecar = {
|
|
28110
28350
|
signalKind: "pr-content",
|
|
@@ -29193,14 +29433,14 @@ var backStep3 = (step) => {
|
|
|
29193
29433
|
};
|
|
29194
29434
|
|
|
29195
29435
|
// src/application/ui/tui/views/add-ticket-internals/review-scrollable-description.tsx
|
|
29196
|
-
import { useEffect as useEffect41, useMemo as
|
|
29436
|
+
import { useEffect as useEffect41, useMemo as useMemo22, useState as useState47 } from "react";
|
|
29197
29437
|
import { Box as Box74, Text as Text73, useInput as useInput29 } from "ink";
|
|
29198
29438
|
import { jsx as jsx91, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
29199
29439
|
var REVIEW_CHROME_ROWS = 14;
|
|
29200
29440
|
var REVIEW_MIN_VIEWPORT = 4;
|
|
29201
29441
|
var ReviewScrollableDescription = ({ text }) => {
|
|
29202
29442
|
const term = useTerminalSize();
|
|
29203
|
-
const lines =
|
|
29443
|
+
const lines = useMemo22(() => text.split("\n"), [text]);
|
|
29204
29444
|
const viewport = Math.max(REVIEW_MIN_VIEWPORT, term.rows - REVIEW_CHROME_ROWS);
|
|
29205
29445
|
const overflows = lines.length > viewport;
|
|
29206
29446
|
const maxOffset = Math.max(0, lines.length - viewport);
|
|
@@ -29440,7 +29680,7 @@ var AddTicketView = () => {
|
|
|
29440
29680
|
};
|
|
29441
29681
|
|
|
29442
29682
|
// src/application/ui/tui/views/pick-project-view.tsx
|
|
29443
|
-
import { useEffect as useEffect43, useMemo as
|
|
29683
|
+
import { useEffect as useEffect43, useMemo as useMemo23, useState as useState49 } from "react";
|
|
29444
29684
|
import { Box as Box77, Text as Text75, useInput as useInput30 } from "ink";
|
|
29445
29685
|
import { jsx as jsx94, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
29446
29686
|
var PickProjectView = () => {
|
|
@@ -29458,8 +29698,8 @@ var PickProjectView = () => {
|
|
|
29458
29698
|
if (!r.ok) throw new Error(r.error.message);
|
|
29459
29699
|
return r.value;
|
|
29460
29700
|
}, []);
|
|
29461
|
-
const projects =
|
|
29462
|
-
const initialIdx =
|
|
29701
|
+
const projects = useMemo23(() => state.kind === "ok" ? state.value : [], [state]);
|
|
29702
|
+
const initialIdx = useMemo23(() => {
|
|
29463
29703
|
if (selection.projectId === void 0) return 0;
|
|
29464
29704
|
const i = projects.findIndex((p) => p.id === selection.projectId);
|
|
29465
29705
|
return i === -1 ? 0 : i;
|
|
@@ -29549,7 +29789,7 @@ var PickProjectView = () => {
|
|
|
29549
29789
|
};
|
|
29550
29790
|
|
|
29551
29791
|
// src/application/ui/tui/views/pick-sprint-view.tsx
|
|
29552
|
-
import { useEffect as useEffect44, useMemo as
|
|
29792
|
+
import { useEffect as useEffect44, useMemo as useMemo25, useState as useState50 } from "react";
|
|
29553
29793
|
import { Box as Box79, Text as Text77, useInput as useInput31 } from "ink";
|
|
29554
29794
|
|
|
29555
29795
|
// src/application/ui/tui/views/pick-sprint-internals/types.ts
|
|
@@ -29653,7 +29893,7 @@ var computeWindow = (totalRows, cursor, visible) => {
|
|
|
29653
29893
|
};
|
|
29654
29894
|
|
|
29655
29895
|
// src/application/ui/tui/views/pick-sprint-internals/row-views.tsx
|
|
29656
|
-
import { useMemo as
|
|
29896
|
+
import { useMemo as useMemo24 } from "react";
|
|
29657
29897
|
import { Box as Box78, Text as Text76 } from "ink";
|
|
29658
29898
|
import { jsx as jsx95, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
29659
29899
|
var RowWindowView = ({
|
|
@@ -29662,7 +29902,7 @@ var RowWindowView = ({
|
|
|
29662
29902
|
visibleRows,
|
|
29663
29903
|
currentSprintId
|
|
29664
29904
|
}) => {
|
|
29665
|
-
const window =
|
|
29905
|
+
const window = useMemo24(() => computeWindow(rows.length, cursor, visibleRows), [rows.length, cursor, visibleRows]);
|
|
29666
29906
|
const slice = rows.slice(window.start, window.end);
|
|
29667
29907
|
return /* @__PURE__ */ jsxs76(Box78, { flexDirection: "column", children: [
|
|
29668
29908
|
window.hiddenAbove > 0 && /* @__PURE__ */ jsx95(Box78, { paddingX: spacing.indent, children: /* @__PURE__ */ jsxs76(Text76, { dimColor: true, children: [
|
|
@@ -29782,17 +30022,17 @@ var PickSprintView = () => {
|
|
|
29782
30022
|
},
|
|
29783
30023
|
[deps.sprintRepo, deps.projectRepo]
|
|
29784
30024
|
);
|
|
29785
|
-
const data =
|
|
30025
|
+
const data = useMemo25(
|
|
29786
30026
|
() => state.kind === "ok" ? state.value : { sprints: [], projectsById: /* @__PURE__ */ new Map() },
|
|
29787
30027
|
[state]
|
|
29788
30028
|
);
|
|
29789
|
-
const groups =
|
|
30029
|
+
const groups = useMemo25(() => buildGroups(data, selection.projectId, scopeAll), [data, selection.projectId, scopeAll]);
|
|
29790
30030
|
const includeCreate = selection.projectId !== void 0;
|
|
29791
|
-
const rows =
|
|
29792
|
-
const sprintCount =
|
|
30031
|
+
const rows = useMemo25(() => flatten(groups, includeCreate), [groups, includeCreate]);
|
|
30032
|
+
const sprintCount = useMemo25(() => rows.reduce((acc, r) => r.kind === "sprint" ? acc + 1 : acc, 0), [rows]);
|
|
29793
30033
|
const bp = useBreakpoint();
|
|
29794
30034
|
const visibleRows = Math.max(MIN_VISIBLE_ROWS, bp.rows - VERTICAL_CHROME_ROWS);
|
|
29795
|
-
const initialIdx =
|
|
30035
|
+
const initialIdx = useMemo25(() => {
|
|
29796
30036
|
if (selection.sprintId !== void 0) {
|
|
29797
30037
|
const i = rows.findIndex((r) => r.kind === "sprint" && r.sprint.id === selection.sprintId);
|
|
29798
30038
|
if (i !== -1) return i;
|
|
@@ -29981,7 +30221,7 @@ var renderView = (entry) => {
|
|
|
29981
30221
|
};
|
|
29982
30222
|
|
|
29983
30223
|
// src/application/ui/tui/runtime/use-global-keys.ts
|
|
29984
|
-
import { useEffect as useEffect45, useMemo as
|
|
30224
|
+
import { useEffect as useEffect45, useMemo as useMemo26, useRef as useRef13 } from "react";
|
|
29985
30225
|
import { useApp, useInput as useInput32 } from "ink";
|
|
29986
30226
|
|
|
29987
30227
|
// src/integration/io/clipboard.ts
|
|
@@ -30086,7 +30326,7 @@ var useGlobalKeys = (opts = {}) => {
|
|
|
30086
30326
|
const ui = useUiState();
|
|
30087
30327
|
const selection = useSelection();
|
|
30088
30328
|
const deps = useDeps();
|
|
30089
|
-
const copyToClipboard =
|
|
30329
|
+
const copyToClipboard = useMemo26(
|
|
30090
30330
|
() => opts.copyToClipboard ?? createCopyToClipboard(),
|
|
30091
30331
|
[opts.copyToClipboard]
|
|
30092
30332
|
);
|
|
@@ -30259,7 +30499,7 @@ var ChainLogDegradedBanner = () => {
|
|
|
30259
30499
|
// src/application/ui/tui/components/progress-overlay.tsx
|
|
30260
30500
|
import { promises as fs29 } from "fs";
|
|
30261
30501
|
import { join as join54 } from "path";
|
|
30262
|
-
import { useEffect as useEffect48, useMemo as
|
|
30502
|
+
import { useEffect as useEffect48, useMemo as useMemo27, useState as useState53 } from "react";
|
|
30263
30503
|
import { Box as Box82, Text as Text80, useInput as useInput33 } from "ink";
|
|
30264
30504
|
import { jsx as jsx99, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
30265
30505
|
var CHROME_ROWS = 10;
|
|
@@ -30276,7 +30516,7 @@ var ProgressOverlay = () => {
|
|
|
30276
30516
|
const [offset, setOffset] = useState53(0);
|
|
30277
30517
|
const [now] = useState53(() => Date.now());
|
|
30278
30518
|
const sprintId = selection.sprintId;
|
|
30279
|
-
const progressPath =
|
|
30519
|
+
const progressPath = useMemo27(() => {
|
|
30280
30520
|
if (sprintId === void 0) return void 0;
|
|
30281
30521
|
return join54(String(storage2.dataRoot), "sprints", String(sprintId), "progress.md");
|
|
30282
30522
|
}, [sprintId, storage2.dataRoot]);
|
|
@@ -30471,20 +30711,23 @@ var resolveInitialState = ({
|
|
|
30471
30711
|
settingsExist,
|
|
30472
30712
|
projects,
|
|
30473
30713
|
lastProjectId,
|
|
30474
|
-
lastSprintId
|
|
30714
|
+
lastSprintId,
|
|
30715
|
+
sprints
|
|
30475
30716
|
}) => {
|
|
30476
30717
|
if (!settingsExist) return { initialView: { id: "welcome" } };
|
|
30477
|
-
|
|
30718
|
+
const [first] = projects;
|
|
30719
|
+
if (first === void 0) return { initialView: { id: "create-project" } };
|
|
30478
30720
|
const restored = lastProjectId !== void 0 ? projects.find((p) => p.id === lastProjectId) : void 0;
|
|
30479
|
-
const
|
|
30480
|
-
|
|
30481
|
-
const
|
|
30721
|
+
const resolvedProject = restored ?? first;
|
|
30722
|
+
const projectSprints = (sprints ?? []).filter((s) => s.projectId === resolvedProject.id).slice().sort((a, b) => a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
|
|
30723
|
+
const persistedSprintValid = restored !== void 0 && lastSprintId !== void 0 && projectSprints.some((s) => s.id === lastSprintId);
|
|
30724
|
+
const seededSprintId = persistedSprintValid ? lastSprintId : projectSprints[0]?.id;
|
|
30482
30725
|
return {
|
|
30483
30726
|
initialView: { id: "home" },
|
|
30484
30727
|
initialSelection: {
|
|
30485
|
-
projectId:
|
|
30486
|
-
projectLabel:
|
|
30487
|
-
...
|
|
30728
|
+
projectId: resolvedProject.id,
|
|
30729
|
+
projectLabel: resolvedProject.displayName,
|
|
30730
|
+
...seededSprintId !== void 0 ? { sprintId: seededSprintId } : {}
|
|
30488
30731
|
}
|
|
30489
30732
|
};
|
|
30490
30733
|
};
|
|
@@ -30783,11 +31026,13 @@ var bootstrap = async () => {
|
|
|
30783
31026
|
void createInkInteractivePrompt(queue);
|
|
30784
31027
|
const settingsExists = await deps.settingsRepo.exists();
|
|
30785
31028
|
const projectsList = await deps.projectRepo.list();
|
|
31029
|
+
const sprintsResult = await deps.sprintRepo.list();
|
|
30786
31030
|
const lastSelectionStore = createLastSelectionStore(paths.value.stateRoot);
|
|
30787
31031
|
const lastSelection = await lastSelectionStore.read();
|
|
30788
31032
|
const { initialView, initialSelection } = resolveInitialState({
|
|
30789
31033
|
settingsExist: settingsExists.ok ? settingsExists.value : false,
|
|
30790
31034
|
projects: projectsList.ok ? projectsList.value : [],
|
|
31035
|
+
sprints: sprintsResult.ok ? sprintsResult.value : [],
|
|
30791
31036
|
...lastSelection !== void 0 ? { lastProjectId: lastSelection.projectId } : {},
|
|
30792
31037
|
...lastSelection?.sprintId !== void 0 ? { lastSprintId: lastSelection.sprintId } : {}
|
|
30793
31038
|
});
|