ralphctl 0.8.3 → 0.8.5
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 +639 -405
- 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
|
},
|
|
@@ -754,13 +782,13 @@ var createJsonSettingsRepository = (deps) => {
|
|
|
754
782
|
import { spawn as nodeSpawn } from "child_process";
|
|
755
783
|
var DEFAULT_GIT_TIMEOUT_MS = 3e4;
|
|
756
784
|
var createGitRunner = (deps = {}) => {
|
|
757
|
-
const
|
|
785
|
+
const spawn2 = deps.spawn ?? defaultSpawn;
|
|
758
786
|
const defaultTimeoutMs = deps.defaultTimeoutMs ?? DEFAULT_GIT_TIMEOUT_MS;
|
|
759
787
|
const run = (cwd, args, opts = {}) => new Promise((resolve) => {
|
|
760
788
|
const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
|
|
761
789
|
let child;
|
|
762
790
|
try {
|
|
763
|
-
child =
|
|
791
|
+
child = spawn2("git", args, {
|
|
764
792
|
stdio: ["pipe", "pipe", "pipe"],
|
|
765
793
|
cwd: String(cwd)
|
|
766
794
|
});
|
|
@@ -837,7 +865,7 @@ import { spawn as nodeSpawn2 } from "child_process";
|
|
|
837
865
|
var DEFAULT_SHELL_TIMEOUT_MS = 5 * 6e4;
|
|
838
866
|
var MAX_OUTPUT_BYTES = 50 * 1024 * 1024;
|
|
839
867
|
var createShellScriptRunner = (deps = {}) => {
|
|
840
|
-
const
|
|
868
|
+
const spawn2 = deps.spawn ?? defaultSpawn2;
|
|
841
869
|
const defaultTimeoutMs = deps.defaultTimeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS;
|
|
842
870
|
const now = deps.now ?? Date.now;
|
|
843
871
|
const run = (cwd, script, opts = {}) => new Promise((resolve) => {
|
|
@@ -845,7 +873,7 @@ var createShellScriptRunner = (deps = {}) => {
|
|
|
845
873
|
const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
|
|
846
874
|
let child;
|
|
847
875
|
try {
|
|
848
|
-
child =
|
|
876
|
+
child = spawn2(script, [], {
|
|
849
877
|
stdio: ["pipe", "pipe", "pipe"],
|
|
850
878
|
cwd: String(cwd),
|
|
851
879
|
shell: true,
|
|
@@ -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;
|
|
2934
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
|
+
});
|
|
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
|
}
|
|
@@ -3781,10 +4005,10 @@ var createInteractiveAiProvider = (deps) => {
|
|
|
3781
4005
|
};
|
|
3782
4006
|
|
|
3783
4007
|
// src/integration/io/run-cli.ts
|
|
3784
|
-
var runCli = (
|
|
4008
|
+
var runCli = (spawn2, command, args, opts) => new Promise((resolve) => {
|
|
3785
4009
|
let child;
|
|
3786
4010
|
try {
|
|
3787
|
-
child =
|
|
4011
|
+
child = spawn2(command, args, {
|
|
3788
4012
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3789
4013
|
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {}
|
|
3790
4014
|
});
|
|
@@ -3922,9 +4146,9 @@ var looksLikeNotFound = (stderr) => {
|
|
|
3922
4146
|
const s = stderr.toLowerCase();
|
|
3923
4147
|
return s.includes("not found") || s.includes("404") || s.includes("could not resolve") || s.includes("does not exist");
|
|
3924
4148
|
};
|
|
3925
|
-
var fetchGitHub = async (
|
|
4149
|
+
var fetchGitHub = async (spawn2, parsed, url) => {
|
|
3926
4150
|
const result = await runCli(
|
|
3927
|
-
|
|
4151
|
+
spawn2,
|
|
3928
4152
|
"gh",
|
|
3929
4153
|
[
|
|
3930
4154
|
"issue",
|
|
@@ -3971,9 +4195,9 @@ var fetchGitHub = async (spawn3, parsed, url) => {
|
|
|
3971
4195
|
comments
|
|
3972
4196
|
});
|
|
3973
4197
|
};
|
|
3974
|
-
var fetchGitLabNotes = async (
|
|
4198
|
+
var fetchGitLabNotes = async (spawn2, parsed) => {
|
|
3975
4199
|
const result = await runCli(
|
|
3976
|
-
|
|
4200
|
+
spawn2,
|
|
3977
4201
|
"glab",
|
|
3978
4202
|
["issue", "note", "list", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--output", "json"],
|
|
3979
4203
|
{ timeoutMs: CLI_TIMEOUT_MS }
|
|
@@ -4002,9 +4226,9 @@ var fetchGitLabNotes = async (spawn3, parsed) => {
|
|
|
4002
4226
|
}));
|
|
4003
4227
|
return { comments };
|
|
4004
4228
|
};
|
|
4005
|
-
var fetchGitLab = async (
|
|
4229
|
+
var fetchGitLab = async (spawn2, parsed, url, logger) => {
|
|
4006
4230
|
const result = await runCli(
|
|
4007
|
-
|
|
4231
|
+
spawn2,
|
|
4008
4232
|
"glab",
|
|
4009
4233
|
["issue", "view", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--output", "json"],
|
|
4010
4234
|
{ timeoutMs: CLI_TIMEOUT_MS }
|
|
@@ -4031,7 +4255,7 @@ var fetchGitLab = async (spawn3, parsed, url, logger) => {
|
|
|
4031
4255
|
})
|
|
4032
4256
|
);
|
|
4033
4257
|
}
|
|
4034
|
-
const notes = await fetchGitLabNotes(
|
|
4258
|
+
const notes = await fetchGitLabNotes(spawn2, parsed);
|
|
4035
4259
|
if (notes.failure !== void 0) {
|
|
4036
4260
|
logger?.warn(`glab issue note list failed for ${url}: ${notes.failure} \u2014 proceeding without comments`);
|
|
4037
4261
|
}
|
|
@@ -4052,9 +4276,9 @@ var createIssueFetcher = (deps) => async (url) => {
|
|
|
4052
4276
|
|
|
4053
4277
|
// src/integration/scm/issue-pusher.ts
|
|
4054
4278
|
var CLI_TIMEOUT_MS2 = 3e4;
|
|
4055
|
-
var updateGitHub = async (
|
|
4279
|
+
var updateGitHub = async (spawn2, url, body, parsed) => {
|
|
4056
4280
|
const r = await runCli(
|
|
4057
|
-
|
|
4281
|
+
spawn2,
|
|
4058
4282
|
"gh",
|
|
4059
4283
|
["issue", "edit", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--body-file", "-"],
|
|
4060
4284
|
{ stdin: body, timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4070,9 +4294,9 @@ var updateGitHub = async (spawn3, url, body, parsed) => {
|
|
|
4070
4294
|
}
|
|
4071
4295
|
return Result.ok(void 0);
|
|
4072
4296
|
};
|
|
4073
|
-
var updateGitLab = async (
|
|
4297
|
+
var updateGitLab = async (spawn2, url, body, parsed) => {
|
|
4074
4298
|
const r = await runCli(
|
|
4075
|
-
|
|
4299
|
+
spawn2,
|
|
4076
4300
|
"glab",
|
|
4077
4301
|
["issue", "update", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--description", body],
|
|
4078
4302
|
{ timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4088,9 +4312,9 @@ var updateGitLab = async (spawn3, url, body, parsed) => {
|
|
|
4088
4312
|
}
|
|
4089
4313
|
return Result.ok(void 0);
|
|
4090
4314
|
};
|
|
4091
|
-
var createGitHub = async (
|
|
4315
|
+
var createGitHub = async (spawn2, origin, title, body) => {
|
|
4092
4316
|
const r = await runCli(
|
|
4093
|
-
|
|
4317
|
+
spawn2,
|
|
4094
4318
|
"gh",
|
|
4095
4319
|
["issue", "create", "--repo", `${origin.owner}/${origin.repo}`, "--title", title, "--body-file", "-"],
|
|
4096
4320
|
{ stdin: body, timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4115,9 +4339,9 @@ var createGitHub = async (spawn3, origin, title, body) => {
|
|
|
4115
4339
|
}
|
|
4116
4340
|
return Result.ok({ url });
|
|
4117
4341
|
};
|
|
4118
|
-
var createGitLab = async (
|
|
4342
|
+
var createGitLab = async (spawn2, origin, title, body) => {
|
|
4119
4343
|
const r = await runCli(
|
|
4120
|
-
|
|
4344
|
+
spawn2,
|
|
4121
4345
|
"glab",
|
|
4122
4346
|
["issue", "create", "--repo", `${origin.owner}/${origin.repo}`, "--title", title, "--description", body],
|
|
4123
4347
|
{ timeoutMs: CLI_TIMEOUT_MS2 }
|
|
@@ -4251,11 +4475,11 @@ var buildGlabArgs = (input) => {
|
|
|
4251
4475
|
if (input.draft) args.push("--draft");
|
|
4252
4476
|
return args;
|
|
4253
4477
|
};
|
|
4254
|
-
var runPlatformCli = async (
|
|
4478
|
+
var runPlatformCli = async (spawn2, platform, input) => {
|
|
4255
4479
|
const command = platform === "github" ? "gh" : "glab";
|
|
4256
4480
|
const args = platform === "github" ? buildGhArgs(input) : buildGlabArgs(input);
|
|
4257
4481
|
const noun = platform === "github" ? "gh pr create" : "glab mr create";
|
|
4258
|
-
const result = await runCli(
|
|
4482
|
+
const result = await runCli(spawn2, command, args, { cwd: String(input.cwd), timeoutMs: CLI_TIMEOUT_MS3 });
|
|
4259
4483
|
if (!result.ok) return Result.error(result.error);
|
|
4260
4484
|
if (result.value.exitCode !== 0) {
|
|
4261
4485
|
const stderr = result.value.stderr.trim();
|
|
@@ -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.5",
|
|
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"
|
|
@@ -5372,7 +5596,7 @@ var noopNotificationDispatcher = {
|
|
|
5372
5596
|
}
|
|
5373
5597
|
};
|
|
5374
5598
|
var wire = (opts) => {
|
|
5375
|
-
const
|
|
5599
|
+
const spawn2 = opts.spawn ?? defaultPipeSpawn;
|
|
5376
5600
|
const env = opts.env ?? process.env;
|
|
5377
5601
|
const debugTrace = isTruthyEnvFlag(env[RALPHCTL_DEBUG_TRACE_ENV]);
|
|
5378
5602
|
const appendFile = createAppendFile();
|
|
@@ -5422,9 +5646,9 @@ var wire = (opts) => {
|
|
|
5422
5646
|
probes: PROBES,
|
|
5423
5647
|
eventBus,
|
|
5424
5648
|
logger,
|
|
5425
|
-
pullRequestCreator: createPullRequestCreator({ gitRunner: createGitRunner(), spawn:
|
|
5426
|
-
issueFetcher: createIssueFetcher({ spawn:
|
|
5427
|
-
issuePusher: createIssuePusher({ spawn:
|
|
5649
|
+
pullRequestCreator: createPullRequestCreator({ gitRunner: createGitRunner(), spawn: spawn2 }),
|
|
5650
|
+
issueFetcher: createIssueFetcher({ spawn: spawn2, logger }),
|
|
5651
|
+
issuePusher: createIssuePusher({ spawn: spawn2 }),
|
|
5428
5652
|
versionChecker: createNpmVersionChecker({
|
|
5429
5653
|
stateRoot: opts.storage.stateRoot,
|
|
5430
5654
|
currentVersion: CLI_METADATA.currentVersion,
|
|
@@ -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 } : {},
|
|
@@ -6840,7 +7069,7 @@ var probeSprintExecutionPairing = async (sprints, sprintExecutionRepo) => {
|
|
|
6840
7069
|
// src/integration/io/command-exists.ts
|
|
6841
7070
|
import { spawn } from "child_process";
|
|
6842
7071
|
var commandExists = (name) => new Promise((resolve) => {
|
|
6843
|
-
const child = spawn(name, ["
|
|
7072
|
+
const child = process.platform === "win32" ? spawn("where", [name], { stdio: "ignore" }) : spawn("command", ["-v", name], { stdio: "ignore", shell: true });
|
|
6844
7073
|
let settled = false;
|
|
6845
7074
|
const settle = (value) => {
|
|
6846
7075
|
if (settled) return;
|
|
@@ -6848,7 +7077,7 @@ var commandExists = (name) => new Promise((resolve) => {
|
|
|
6848
7077
|
resolve(value);
|
|
6849
7078
|
};
|
|
6850
7079
|
child.on("error", () => settle(false));
|
|
6851
|
-
child.on("exit", () => settle(
|
|
7080
|
+
child.on("exit", (code) => settle(code === 0));
|
|
6852
7081
|
});
|
|
6853
7082
|
|
|
6854
7083
|
// src/integration/io/run-command.ts
|
|
@@ -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):");
|
|
@@ -11912,7 +12139,6 @@ var createRefineFlow = (deps, opts) => {
|
|
|
11912
12139
|
};
|
|
11913
12140
|
|
|
11914
12141
|
// src/integration/system/detect-cli.ts
|
|
11915
|
-
import { spawn as spawn2 } from "child_process";
|
|
11916
12142
|
var PROVIDER_BINARY2 = {
|
|
11917
12143
|
"claude-code": "claude",
|
|
11918
12144
|
"github-copilot": "gh",
|
|
@@ -11989,17 +12215,7 @@ Install options (${os}):
|
|
|
11989
12215
|
${bullets}
|
|
11990
12216
|
Docs: ${guidance.docsUrl}`;
|
|
11991
12217
|
};
|
|
11992
|
-
var defaultWhich =
|
|
11993
|
-
const child = spawn2("command", ["-v", binary], { stdio: "pipe", shell: true });
|
|
11994
|
-
let settled = false;
|
|
11995
|
-
const settle = (value) => {
|
|
11996
|
-
if (settled) return;
|
|
11997
|
-
settled = true;
|
|
11998
|
-
resolve(value);
|
|
11999
|
-
};
|
|
12000
|
-
child.on("error", () => settle(false));
|
|
12001
|
-
child.on("exit", (code) => settle(code === 0));
|
|
12002
|
-
});
|
|
12218
|
+
var defaultWhich = commandExists;
|
|
12003
12219
|
var detectInstalledProviders = async (options = {}) => {
|
|
12004
12220
|
const which = options.which ?? defaultWhich;
|
|
12005
12221
|
const providers = Object.keys(PROVIDER_BINARY2);
|
|
@@ -13637,7 +13853,18 @@ var implementPromptDef = {
|
|
|
13637
13853
|
},
|
|
13638
13854
|
// Documents the harness signals the implement response is expected to carry. Validation is
|
|
13639
13855
|
// not enforced at parse time — this list drives test authors and future scoped parsers.
|
|
13640
|
-
|
|
13856
|
+
// Aligned with generator.contract.ts: narrative fan-out (change, decision, learning, note)
|
|
13857
|
+
// plus lifecycle signals (task-verified, task-complete, task-blocked, commit-message).
|
|
13858
|
+
expectedSignals: [
|
|
13859
|
+
"change",
|
|
13860
|
+
"decision",
|
|
13861
|
+
"learning",
|
|
13862
|
+
"note",
|
|
13863
|
+
"task-verified",
|
|
13864
|
+
"task-complete",
|
|
13865
|
+
"task-blocked",
|
|
13866
|
+
"commit-message"
|
|
13867
|
+
]
|
|
13641
13868
|
};
|
|
13642
13869
|
var buildImplementPrompt = async (deps, input) => buildPrompt(deps, implementPromptDef, {
|
|
13643
13870
|
taskName: input.task.name,
|
|
@@ -13656,7 +13883,7 @@ var buildImplementPrompt = async (deps, input) => buildPrompt(deps, implementPro
|
|
|
13656
13883
|
});
|
|
13657
13884
|
|
|
13658
13885
|
// src/application/flows/implement/leaves/generator.contract.ts
|
|
13659
|
-
import { z as
|
|
13886
|
+
import { z as z30 } from "zod";
|
|
13660
13887
|
|
|
13661
13888
|
// src/integration/ai/contract/_engine/signals/change/schema.ts
|
|
13662
13889
|
import { z as z25 } from "zod";
|
|
@@ -13675,44 +13902,33 @@ var commitMessageSignalSchema = z26.object({
|
|
|
13675
13902
|
timestamp: IsoTimestampSchema
|
|
13676
13903
|
});
|
|
13677
13904
|
|
|
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
13905
|
// src/integration/ai/contract/_engine/signals/task-blocked/schema.ts
|
|
13690
|
-
import { z as
|
|
13691
|
-
var taskBlockedSignalSchema =
|
|
13692
|
-
type:
|
|
13693
|
-
reason:
|
|
13906
|
+
import { z as z27 } from "zod";
|
|
13907
|
+
var taskBlockedSignalSchema = z27.object({
|
|
13908
|
+
type: z27.literal("task-blocked"),
|
|
13909
|
+
reason: z27.string(),
|
|
13694
13910
|
timestamp: IsoTimestampSchema
|
|
13695
13911
|
});
|
|
13696
13912
|
|
|
13697
13913
|
// src/integration/ai/contract/_engine/signals/task-complete/schema.ts
|
|
13698
|
-
import { z as
|
|
13699
|
-
var taskCompleteSignalSchema =
|
|
13700
|
-
type:
|
|
13914
|
+
import { z as z28 } from "zod";
|
|
13915
|
+
var taskCompleteSignalSchema = z28.object({
|
|
13916
|
+
type: z28.literal("task-complete"),
|
|
13701
13917
|
timestamp: IsoTimestampSchema
|
|
13702
13918
|
});
|
|
13703
13919
|
|
|
13704
13920
|
// src/integration/ai/contract/_engine/signals/task-verified/schema.ts
|
|
13705
|
-
import { z as
|
|
13706
|
-
var taskVerifiedSignalSchema =
|
|
13707
|
-
type:
|
|
13708
|
-
output:
|
|
13921
|
+
import { z as z29 } from "zod";
|
|
13922
|
+
var taskVerifiedSignalSchema = z29.object({
|
|
13923
|
+
type: z29.literal("task-verified"),
|
|
13924
|
+
output: z29.string(),
|
|
13709
13925
|
timestamp: IsoTimestampSchema
|
|
13710
13926
|
});
|
|
13711
13927
|
|
|
13712
13928
|
// src/application/flows/implement/leaves/generator.contract.ts
|
|
13713
13929
|
var atMostOneCommitMessage = (signals) => signals.filter((s) => s.type === "commit-message").length <= 1;
|
|
13714
|
-
var signalsArraySchemaRaw3 =
|
|
13715
|
-
|
|
13930
|
+
var signalsArraySchemaRaw3 = z30.array(
|
|
13931
|
+
z30.union([
|
|
13716
13932
|
changeSignalSchema,
|
|
13717
13933
|
learningSignalSchema,
|
|
13718
13934
|
noteSignalSchema,
|
|
@@ -13720,8 +13936,7 @@ var signalsArraySchemaRaw3 = z31.array(
|
|
|
13720
13936
|
taskVerifiedSignalSchema,
|
|
13721
13937
|
taskCompleteSignalSchema,
|
|
13722
13938
|
taskBlockedSignalSchema,
|
|
13723
|
-
commitMessageSignalSchema
|
|
13724
|
-
progressEntrySignalSchema
|
|
13939
|
+
commitMessageSignalSchema
|
|
13725
13940
|
])
|
|
13726
13941
|
).refine(atMostOneCommitMessage, "at most one commit-message signal per generator spawn");
|
|
13727
13942
|
var signalsArraySchema3 = brandSignalArray(signalsArraySchemaRaw3);
|
|
@@ -14812,15 +15027,15 @@ var implementSession = (sandboxCwd, repoPath, sprintDir2, prompt, model, signals
|
|
|
14812
15027
|
};
|
|
14813
15028
|
|
|
14814
15029
|
// src/application/flows/implement/leaves/evaluator.contract.ts
|
|
14815
|
-
import { z as
|
|
15030
|
+
import { z as z32 } from "zod";
|
|
14816
15031
|
|
|
14817
15032
|
// src/integration/ai/contract/_engine/signals/evaluation/schema.ts
|
|
14818
|
-
import { z as
|
|
14819
|
-
var dimensionScoreSchema =
|
|
14820
|
-
dimension:
|
|
14821
|
-
passed:
|
|
14822
|
-
finding:
|
|
14823
|
-
executionEvidence:
|
|
15033
|
+
import { z as z31 } from "zod";
|
|
15034
|
+
var dimensionScoreSchema = z31.object({
|
|
15035
|
+
dimension: z31.string(),
|
|
15036
|
+
passed: z31.boolean(),
|
|
15037
|
+
finding: z31.string(),
|
|
15038
|
+
executionEvidence: z31.string().optional()
|
|
14824
15039
|
}).superRefine((d, ctx) => {
|
|
14825
15040
|
if (!d.passed && d.finding.trim().length === 0) {
|
|
14826
15041
|
ctx.addIssue({
|
|
@@ -14830,11 +15045,11 @@ var dimensionScoreSchema = z32.object({
|
|
|
14830
15045
|
});
|
|
14831
15046
|
}
|
|
14832
15047
|
});
|
|
14833
|
-
var evaluationSignalSchema =
|
|
14834
|
-
type:
|
|
14835
|
-
status:
|
|
14836
|
-
dimensions:
|
|
14837
|
-
critique:
|
|
15048
|
+
var evaluationSignalSchema = z31.object({
|
|
15049
|
+
type: z31.literal("evaluation"),
|
|
15050
|
+
status: z31.union([z31.literal("passed"), z31.literal("failed"), z31.literal("malformed")]),
|
|
15051
|
+
dimensions: z31.array(dimensionScoreSchema).readonly(),
|
|
15052
|
+
critique: z31.string().optional(),
|
|
14838
15053
|
timestamp: IsoTimestampSchema
|
|
14839
15054
|
}).superRefine((s, ctx) => {
|
|
14840
15055
|
if (s.status === "passed") {
|
|
@@ -14894,8 +15109,8 @@ var renderEvaluationMarkdown = (signal) => {
|
|
|
14894
15109
|
|
|
14895
15110
|
// src/application/flows/implement/leaves/evaluator.contract.ts
|
|
14896
15111
|
var exactlyOneEvaluation = (signals) => signals.filter((s) => s.type === "evaluation").length === 1;
|
|
14897
|
-
var signalsArraySchemaRaw4 =
|
|
14898
|
-
|
|
15112
|
+
var signalsArraySchemaRaw4 = z32.array(
|
|
15113
|
+
z32.union([
|
|
14899
15114
|
changeSignalSchema,
|
|
14900
15115
|
learningSignalSchema,
|
|
14901
15116
|
noteSignalSchema,
|
|
@@ -15011,7 +15226,7 @@ var evaluatorLeaf = (deps, taskId) => leaf(`evaluator-${String(taskId)}`, {
|
|
|
15011
15226
|
});
|
|
15012
15227
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
15013
15228
|
await writeRoundPrompt(input.workspaceRoot, input.roundNum, "evaluator", String(prompt.value), deps.logger);
|
|
15014
|
-
const
|
|
15229
|
+
const spawn2 = await deps.provider.generate(
|
|
15015
15230
|
implementSession(
|
|
15016
15231
|
input.workspaceRoot,
|
|
15017
15232
|
deps.cwd,
|
|
@@ -15024,7 +15239,7 @@ var evaluatorLeaf = (deps, taskId) => leaf(`evaluator-${String(taskId)}`, {
|
|
|
15024
15239
|
deps.effort
|
|
15025
15240
|
)
|
|
15026
15241
|
);
|
|
15027
|
-
if (!
|
|
15242
|
+
if (!spawn2.ok) return Result.error(spawn2.error);
|
|
15028
15243
|
const validated = await validateSignalsFile(outputDir, evaluatorOutputContract);
|
|
15029
15244
|
if (!validated.ok) return Result.error(validated.error);
|
|
15030
15245
|
const signals = validated.value;
|
|
@@ -15230,7 +15445,7 @@ var generatorLeaf = (deps, taskId) => leaf(`generator-${String(taskId)}`, {
|
|
|
15230
15445
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
15231
15446
|
await writeRoundPrompt(input.workspaceRoot, roundNum, "generator", String(prompt.value), deps.logger);
|
|
15232
15447
|
const effectiveModel = task.escalatedToModel ?? deps.model;
|
|
15233
|
-
const
|
|
15448
|
+
const spawn2 = await deps.provider.generate(
|
|
15234
15449
|
implementSession(
|
|
15235
15450
|
input.workspaceRoot,
|
|
15236
15451
|
deps.cwd,
|
|
@@ -15243,7 +15458,7 @@ var generatorLeaf = (deps, taskId) => leaf(`generator-${String(taskId)}`, {
|
|
|
15243
15458
|
deps.effort
|
|
15244
15459
|
)
|
|
15245
15460
|
);
|
|
15246
|
-
if (!
|
|
15461
|
+
if (!spawn2.ok) return Result.error(spawn2.error);
|
|
15247
15462
|
const validated = await validateSignalsFile(outputDir, generatorOutputContract);
|
|
15248
15463
|
if (!validated.ok) return Result.error(validated.error);
|
|
15249
15464
|
const signals = validated.value;
|
|
@@ -18055,12 +18270,12 @@ var buildApplyFeedbackPrompt = async (deps, input) => buildPrompt(deps, applyFee
|
|
|
18055
18270
|
});
|
|
18056
18271
|
|
|
18057
18272
|
// src/application/flows/review/leaves/review-round.contract.ts
|
|
18058
|
-
import { z as
|
|
18273
|
+
import { z as z33 } from "zod";
|
|
18059
18274
|
var hasExactlyOneTerminal = (signals) => {
|
|
18060
18275
|
const terminals = signals.filter((s) => s.type === "task-complete" || s.type === "task-blocked");
|
|
18061
18276
|
return terminals.length === 1;
|
|
18062
18277
|
};
|
|
18063
|
-
var signalsArraySchemaRaw5 =
|
|
18278
|
+
var signalsArraySchemaRaw5 = z33.array(z33.union([taskCompleteSignalSchema, taskBlockedSignalSchema])).refine(hasExactlyOneTerminal, "exactly one of `task-complete` or `task-blocked` is required per round");
|
|
18064
18279
|
var signalsArraySchema5 = brandSignalArray(signalsArraySchemaRaw5);
|
|
18065
18280
|
var wrapLegacyArray5 = (raw) => {
|
|
18066
18281
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -18198,7 +18413,7 @@ var reviewRoundLeaf = (deps, opts) => leaf("review-round", {
|
|
|
18198
18413
|
}
|
|
18199
18414
|
const promptWrote = await writeTextAtomic(String(paths.value.promptFile), String(prompt));
|
|
18200
18415
|
if (!promptWrote.ok) return Result.error(promptWrote.error);
|
|
18201
|
-
const
|
|
18416
|
+
const spawn2 = await deps.provider.generate({
|
|
18202
18417
|
prompt,
|
|
18203
18418
|
cwd: paths.value.outputDir,
|
|
18204
18419
|
additionalRoots: opts.additionalRoots,
|
|
@@ -18207,7 +18422,7 @@ var reviewRoundLeaf = (deps, opts) => leaf("review-round", {
|
|
|
18207
18422
|
signalsFile: paths.value.signalsFile,
|
|
18208
18423
|
outputDir: paths.value.outputDir
|
|
18209
18424
|
});
|
|
18210
|
-
if (!
|
|
18425
|
+
if (!spawn2.ok) return Result.error(spawn2.error);
|
|
18211
18426
|
const validated = await validateSignalsFile(paths.value.outputDir, reviewRoundOutputContract);
|
|
18212
18427
|
if (!validated.ok) return Result.error(validated.error);
|
|
18213
18428
|
for (const sig of validated.value) {
|
|
@@ -18718,6 +18933,16 @@ var wireTagFor = (tool) => {
|
|
|
18718
18933
|
return "agents-md";
|
|
18719
18934
|
}
|
|
18720
18935
|
};
|
|
18936
|
+
var conventionsPartialName = (tool) => {
|
|
18937
|
+
switch (tool) {
|
|
18938
|
+
case "claude-code":
|
|
18939
|
+
return "conventions-claude-md";
|
|
18940
|
+
case "copilot":
|
|
18941
|
+
return "conventions-copilot-instructions";
|
|
18942
|
+
case "codex":
|
|
18943
|
+
return "conventions-agents-md";
|
|
18944
|
+
}
|
|
18945
|
+
};
|
|
18721
18946
|
var readinessPromptDef = {
|
|
18722
18947
|
templateName: "readiness",
|
|
18723
18948
|
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 +18974,10 @@ var readinessPromptDef = {
|
|
|
18749
18974
|
placeholder: "DETECTED_ARTEFACTS",
|
|
18750
18975
|
description: 'Bullet list of artefact paths discovered by the probe, or "no artefacts detected".'
|
|
18751
18976
|
},
|
|
18977
|
+
targetFileConventions: {
|
|
18978
|
+
placeholder: "TARGET_FILE_CONVENTIONS",
|
|
18979
|
+
description: "Per-provider style guide for the target context file (CLAUDE.md / .github/copilot-instructions.md / AGENTS.md). Loaded from the matching conventions partial."
|
|
18980
|
+
},
|
|
18752
18981
|
outputContractSection: {
|
|
18753
18982
|
placeholder: "OUTPUT_CONTRACT_SECTION",
|
|
18754
18983
|
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 +19028,60 @@ var collectArtefactPaths = (state) => {
|
|
|
18799
19028
|
}
|
|
18800
19029
|
return paths;
|
|
18801
19030
|
};
|
|
18802
|
-
var buildReadinessPrompt = async (deps, input) =>
|
|
18803
|
-
|
|
18804
|
-
|
|
18805
|
-
|
|
18806
|
-
|
|
18807
|
-
|
|
18808
|
-
|
|
18809
|
-
|
|
19031
|
+
var buildReadinessPrompt = async (deps, input) => {
|
|
19032
|
+
const partialName = conventionsPartialName(input.currentTool);
|
|
19033
|
+
const conventionsResult = await deps.load(partialName);
|
|
19034
|
+
if (!conventionsResult.ok) return Result.error(conventionsResult.error);
|
|
19035
|
+
return buildPrompt(deps, readinessPromptDef, {
|
|
19036
|
+
repositoryPath: input.repositoryPath,
|
|
19037
|
+
currentTool: renderCurrentTool(input.currentTool),
|
|
19038
|
+
wireTag: wireTagFor(input.currentTool),
|
|
19039
|
+
existingContextFile: renderExistingContextFile(input.existingContextFile),
|
|
19040
|
+
detectedArtefacts: renderDetectedArtefacts(collectArtefactPaths(input.probedState)),
|
|
19041
|
+
targetFileConventions: conventionsResult.value.trim(),
|
|
19042
|
+
outputContractSection: input.outputContractSection
|
|
19043
|
+
});
|
|
19044
|
+
};
|
|
18810
19045
|
|
|
18811
19046
|
// src/application/flows/readiness/leaves/readiness.contract.ts
|
|
18812
|
-
import { z as
|
|
19047
|
+
import { z as z38 } from "zod";
|
|
18813
19048
|
|
|
18814
19049
|
// src/integration/ai/contract/_engine/signals/agents-md-proposal/schema.ts
|
|
18815
|
-
import { z as
|
|
18816
|
-
var agentsMdProposalSignalSchema =
|
|
18817
|
-
type:
|
|
18818
|
-
tag:
|
|
18819
|
-
content:
|
|
19050
|
+
import { z as z34 } from "zod";
|
|
19051
|
+
var agentsMdProposalSignalSchema = z34.object({
|
|
19052
|
+
type: z34.literal("agents-md-proposal"),
|
|
19053
|
+
tag: z34.union([z34.literal("claude-md"), z34.literal("copilot-instructions"), z34.literal("agents-md")]),
|
|
19054
|
+
content: z34.string(),
|
|
18820
19055
|
timestamp: IsoTimestampSchema
|
|
18821
19056
|
});
|
|
18822
19057
|
|
|
18823
19058
|
// src/integration/ai/contract/_engine/signals/setup-skill-proposal/schema.ts
|
|
18824
|
-
import { z as
|
|
18825
|
-
var setupSkillProposalSignalSchema =
|
|
18826
|
-
type:
|
|
18827
|
-
content:
|
|
19059
|
+
import { z as z35 } from "zod";
|
|
19060
|
+
var setupSkillProposalSignalSchema = z35.object({
|
|
19061
|
+
type: z35.literal("setup-skill-proposal"),
|
|
19062
|
+
content: z35.string(),
|
|
18828
19063
|
timestamp: IsoTimestampSchema
|
|
18829
19064
|
});
|
|
18830
19065
|
|
|
18831
19066
|
// src/integration/ai/contract/_engine/signals/skill-suggestions/schema.ts
|
|
18832
|
-
import { z as
|
|
18833
|
-
var skillSuggestionsSignalSchema =
|
|
18834
|
-
type:
|
|
18835
|
-
names:
|
|
19067
|
+
import { z as z36 } from "zod";
|
|
19068
|
+
var skillSuggestionsSignalSchema = z36.object({
|
|
19069
|
+
type: z36.literal("skill-suggestions"),
|
|
19070
|
+
names: z36.array(z36.string()).readonly(),
|
|
18836
19071
|
timestamp: IsoTimestampSchema
|
|
18837
19072
|
});
|
|
18838
19073
|
|
|
18839
19074
|
// src/integration/ai/contract/_engine/signals/verify-skill-proposal/schema.ts
|
|
18840
|
-
import { z as
|
|
18841
|
-
var verifySkillProposalSignalSchema =
|
|
18842
|
-
type:
|
|
18843
|
-
content:
|
|
19075
|
+
import { z as z37 } from "zod";
|
|
19076
|
+
var verifySkillProposalSignalSchema = z37.object({
|
|
19077
|
+
type: z37.literal("verify-skill-proposal"),
|
|
19078
|
+
content: z37.string(),
|
|
18844
19079
|
timestamp: IsoTimestampSchema
|
|
18845
19080
|
});
|
|
18846
19081
|
|
|
18847
19082
|
// src/application/flows/readiness/leaves/readiness.contract.ts
|
|
18848
|
-
var signalsArraySchemaRaw6 =
|
|
18849
|
-
|
|
19083
|
+
var signalsArraySchemaRaw6 = z38.array(
|
|
19084
|
+
z38.union([
|
|
18850
19085
|
learningSignalSchema,
|
|
18851
19086
|
noteSignalSchema,
|
|
18852
19087
|
agentsMdProposalSignalSchema,
|
|
@@ -19411,9 +19646,9 @@ var buildDetectSkillsPrompt = async (loader, input) => buildPrompt(loader, detec
|
|
|
19411
19646
|
});
|
|
19412
19647
|
|
|
19413
19648
|
// src/application/flows/detect-skills/leaves/propose.contract.ts
|
|
19414
|
-
import { z as
|
|
19649
|
+
import { z as z39 } from "zod";
|
|
19415
19650
|
var atMostOneOf = (kind) => (signals) => signals.filter((s) => s.type === kind).length <= 1;
|
|
19416
|
-
var signalsArraySchemaRaw7 =
|
|
19651
|
+
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
19652
|
var signalsArraySchema7 = brandSignalArray(signalsArraySchemaRaw7);
|
|
19418
19653
|
var wrapLegacyArray7 = (raw) => {
|
|
19419
19654
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -19501,7 +19736,7 @@ var proposeUseCase = async (deps, input) => {
|
|
|
19501
19736
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
19502
19737
|
const promptWrote = await writeTextAtomic(String(paths.value.promptFile), String(prompt.value));
|
|
19503
19738
|
if (!promptWrote.ok) return Result.error(promptWrote.error);
|
|
19504
|
-
const
|
|
19739
|
+
const spawn2 = await deps.provider.generate(
|
|
19505
19740
|
detectSkillsSession(
|
|
19506
19741
|
input.repository,
|
|
19507
19742
|
prompt.value,
|
|
@@ -19512,13 +19747,13 @@ var proposeUseCase = async (deps, input) => {
|
|
|
19512
19747
|
deps.effort
|
|
19513
19748
|
)
|
|
19514
19749
|
);
|
|
19515
|
-
if (!
|
|
19750
|
+
if (!spawn2.ok) {
|
|
19516
19751
|
log.error(`provider failed for repo ${input.repository.name}`, {
|
|
19517
19752
|
repositoryId: String(input.repository.id),
|
|
19518
|
-
error:
|
|
19753
|
+
error: spawn2.error.message,
|
|
19519
19754
|
runDir: String(paths.value.runDir)
|
|
19520
19755
|
});
|
|
19521
|
-
return Result.error(
|
|
19756
|
+
return Result.error(spawn2.error);
|
|
19522
19757
|
}
|
|
19523
19758
|
const validated = await validateSignalsFile(paths.value.runDir, detectSkillsOutputContract);
|
|
19524
19759
|
if (!validated.ok) {
|
|
@@ -20168,27 +20403,27 @@ var buildDetectScriptsPrompt = async (loader, input) => buildPrompt(loader, dete
|
|
|
20168
20403
|
});
|
|
20169
20404
|
|
|
20170
20405
|
// src/application/flows/detect-scripts/leaves/propose.contract.ts
|
|
20171
|
-
import { z as
|
|
20406
|
+
import { z as z42 } from "zod";
|
|
20172
20407
|
|
|
20173
20408
|
// src/integration/ai/contract/_engine/signals/setup-script/schema.ts
|
|
20174
|
-
import { z as
|
|
20175
|
-
var setupScriptSignalSchema =
|
|
20176
|
-
type:
|
|
20177
|
-
command:
|
|
20409
|
+
import { z as z40 } from "zod";
|
|
20410
|
+
var setupScriptSignalSchema = z40.object({
|
|
20411
|
+
type: z40.literal("setup-script"),
|
|
20412
|
+
command: z40.string(),
|
|
20178
20413
|
timestamp: IsoTimestampSchema
|
|
20179
20414
|
});
|
|
20180
20415
|
|
|
20181
20416
|
// src/integration/ai/contract/_engine/signals/verify-script/schema.ts
|
|
20182
|
-
import { z as
|
|
20183
|
-
var verifyScriptSignalSchema =
|
|
20184
|
-
type:
|
|
20185
|
-
command:
|
|
20417
|
+
import { z as z41 } from "zod";
|
|
20418
|
+
var verifyScriptSignalSchema = z41.object({
|
|
20419
|
+
type: z41.literal("verify-script"),
|
|
20420
|
+
command: z41.string(),
|
|
20186
20421
|
timestamp: IsoTimestampSchema
|
|
20187
20422
|
});
|
|
20188
20423
|
|
|
20189
20424
|
// src/application/flows/detect-scripts/leaves/propose.contract.ts
|
|
20190
20425
|
var atMostOneOf2 = (kind) => (signals) => signals.filter((s) => s.type === kind).length <= 1;
|
|
20191
|
-
var signalsArraySchemaRaw8 =
|
|
20426
|
+
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
20427
|
var signalsArraySchema8 = brandSignalArray(signalsArraySchemaRaw8);
|
|
20193
20428
|
var wrapLegacyArray8 = (raw) => {
|
|
20194
20429
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -20259,7 +20494,7 @@ var proposeUseCase2 = async (deps, input) => {
|
|
|
20259
20494
|
if (!prompt.ok) return Result.error(prompt.error);
|
|
20260
20495
|
const promptWrote = await writeTextAtomic(String(paths.value.promptFile), String(prompt.value));
|
|
20261
20496
|
if (!promptWrote.ok) return Result.error(promptWrote.error);
|
|
20262
|
-
const
|
|
20497
|
+
const spawn2 = await deps.provider.generate(
|
|
20263
20498
|
detectScriptsSession(
|
|
20264
20499
|
input.repository,
|
|
20265
20500
|
prompt.value,
|
|
@@ -20270,13 +20505,13 @@ var proposeUseCase2 = async (deps, input) => {
|
|
|
20270
20505
|
deps.effort
|
|
20271
20506
|
)
|
|
20272
20507
|
);
|
|
20273
|
-
if (!
|
|
20508
|
+
if (!spawn2.ok) {
|
|
20274
20509
|
log.error(`provider failed for repo ${input.repository.name}`, {
|
|
20275
20510
|
repositoryId: String(input.repository.id),
|
|
20276
|
-
error:
|
|
20511
|
+
error: spawn2.error.message,
|
|
20277
20512
|
runDir: String(paths.value.runDir)
|
|
20278
20513
|
});
|
|
20279
|
-
return Result.error(
|
|
20514
|
+
return Result.error(spawn2.error);
|
|
20280
20515
|
}
|
|
20281
20516
|
const validated = await validateSignalsFile(paths.value.runDir, detectScriptsOutputContract);
|
|
20282
20517
|
if (!validated.ok) {
|
|
@@ -20664,7 +20899,7 @@ var ideatePromptDef = {
|
|
|
20664
20899
|
partials: {
|
|
20665
20900
|
HARNESS_CONTEXT: "harness-context"
|
|
20666
20901
|
},
|
|
20667
|
-
expectedSignals: ["ideated-tickets"]
|
|
20902
|
+
expectedSignals: ["ideated-tickets", "note", "learning", "decision"]
|
|
20668
20903
|
};
|
|
20669
20904
|
var renderRepositories2 = (project) => {
|
|
20670
20905
|
if (project.repositories.length === 0) return "_no repositories configured_";
|
|
@@ -20682,19 +20917,19 @@ var buildIdeatePrompt = async (deps, input) => buildPrompt(deps, ideatePromptDef
|
|
|
20682
20917
|
var project_name = (project) => project.displayName;
|
|
20683
20918
|
|
|
20684
20919
|
// src/application/flows/ideate/leaves/ideate.contract.ts
|
|
20685
|
-
import { z as
|
|
20920
|
+
import { z as z44 } from "zod";
|
|
20686
20921
|
|
|
20687
20922
|
// src/integration/ai/contract/_engine/signals/ideated-tickets/schema.ts
|
|
20688
|
-
import { z as
|
|
20689
|
-
var ideatedTicketsSignalSchema =
|
|
20690
|
-
type:
|
|
20691
|
-
outputJson:
|
|
20923
|
+
import { z as z43 } from "zod";
|
|
20924
|
+
var ideatedTicketsSignalSchema = z43.object({
|
|
20925
|
+
type: z43.literal("ideated-tickets"),
|
|
20926
|
+
outputJson: z43.string(),
|
|
20692
20927
|
timestamp: IsoTimestampSchema
|
|
20693
20928
|
});
|
|
20694
20929
|
|
|
20695
20930
|
// src/application/flows/ideate/leaves/ideate.contract.ts
|
|
20696
20931
|
var exactlyOneIdeatedTickets = (signals) => signals.filter((s) => s.type === "ideated-tickets").length === 1;
|
|
20697
|
-
var signalsArraySchemaRaw9 =
|
|
20932
|
+
var signalsArraySchemaRaw9 = z44.array(z44.union([learningSignalSchema, noteSignalSchema, decisionSignalSchema, ideatedTicketsSignalSchema])).refine(exactlyOneIdeatedTickets, "exactly one ideated-tickets signal per ideate spawn");
|
|
20698
20933
|
var signalsArraySchema9 = brandSignalArray(signalsArraySchemaRaw9);
|
|
20699
20934
|
var wrapLegacyArray9 = (raw) => {
|
|
20700
20935
|
if (Array.isArray(raw)) return { schemaVersion: 1, signals: raw };
|
|
@@ -22767,7 +23002,7 @@ var ProjectsView = () => {
|
|
|
22767
23002
|
};
|
|
22768
23003
|
|
|
22769
23004
|
// src/application/ui/tui/views/project-detail-view.tsx
|
|
22770
|
-
import React49, { useEffect as useEffect19, useState as useState28 } from "react";
|
|
23005
|
+
import React49, { useEffect as useEffect19, useMemo as useMemo13, useState as useState28 } from "react";
|
|
22771
23006
|
import { Box as Box35, Text as Text37, useInput as useInput16 } from "ink";
|
|
22772
23007
|
|
|
22773
23008
|
// src/application/ui/tui/components/field-list.tsx
|
|
@@ -22806,7 +23041,6 @@ var ProjectDetailView = () => {
|
|
|
22806
23041
|
useViewHints([
|
|
22807
23042
|
{ keys: "r", label: "sprints" },
|
|
22808
23043
|
{ keys: "a", label: "add repo" },
|
|
22809
|
-
{ keys: "e", label: "edit project / repo field" },
|
|
22810
23044
|
{ keys: "d", label: "remove repo" },
|
|
22811
23045
|
{ keys: "c", label: "detect scripts" },
|
|
22812
23046
|
{ keys: "S", label: "detect skills" }
|
|
@@ -22830,7 +23064,21 @@ var ProjectDetailView = () => {
|
|
|
22830
23064
|
const [confirmRemove, setConfirmRemove] = useState28(void 0);
|
|
22831
23065
|
const [feedback, setFeedback] = useState28(void 0);
|
|
22832
23066
|
const project = state.kind === "ok" ? state.value : void 0;
|
|
22833
|
-
const
|
|
23067
|
+
const fields = useMemo13(() => {
|
|
23068
|
+
if (project === void 0) return [];
|
|
23069
|
+
return [
|
|
23070
|
+
{ kind: "project", field: "displayName" },
|
|
23071
|
+
...project.repositories.flatMap((r) => [
|
|
23072
|
+
{ kind: "repo", field: "name", repo: r },
|
|
23073
|
+
{ kind: "repo", field: "setupScript", repo: r },
|
|
23074
|
+
{ kind: "repo", field: "verifyScript", repo: r }
|
|
23075
|
+
])
|
|
23076
|
+
];
|
|
23077
|
+
}, [project]);
|
|
23078
|
+
const focused = fields[Math.min(cursorIdx, Math.max(0, fields.length - 1))];
|
|
23079
|
+
useEffect19(() => {
|
|
23080
|
+
if (state.kind === "ok") setCursorIdx(0);
|
|
23081
|
+
}, [state.kind, projectId]);
|
|
22834
23082
|
const launchPerRepoFlow = async (flowId, target) => {
|
|
22835
23083
|
if (project === void 0) return;
|
|
22836
23084
|
setFeedback(void 0);
|
|
@@ -22904,30 +23152,11 @@ var ProjectDetailView = () => {
|
|
|
22904
23152
|
};
|
|
22905
23153
|
};
|
|
22906
23154
|
const handleEdit = () => {
|
|
22907
|
-
if (project === void 0) return;
|
|
23155
|
+
if (project === void 0 || focused === void 0) return;
|
|
22908
23156
|
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
|
-
});
|
|
23157
|
+
const target = focused.kind === "project" ? { kind: "project" } : { kind: "repo", field: focused.field, repo: focused.repo };
|
|
23158
|
+
const cfg = renderEditPrompt(target);
|
|
23159
|
+
if (cfg !== void 0) void edit.openEditPrompt(cfg);
|
|
22931
23160
|
};
|
|
22932
23161
|
useInput16((input, key) => {
|
|
22933
23162
|
if (ui.helpOpen || ui.promptActive || confirmRemove !== void 0 || project === void 0) return;
|
|
@@ -22935,31 +23164,28 @@ var ProjectDetailView = () => {
|
|
|
22935
23164
|
router.push({ id: "add-repository", props: { projectId: project.id } });
|
|
22936
23165
|
return;
|
|
22937
23166
|
}
|
|
22938
|
-
if (input === "e") {
|
|
23167
|
+
if (input === "e" || key.return) {
|
|
22939
23168
|
handleEdit();
|
|
22940
23169
|
return;
|
|
22941
23170
|
}
|
|
22942
|
-
if (
|
|
22943
|
-
setCursorIdx((c) => Math.min(
|
|
23171
|
+
if (key.downArrow || input === "j") {
|
|
23172
|
+
setCursorIdx((c) => Math.min(Math.max(0, fields.length - 1), c + 1));
|
|
22944
23173
|
return;
|
|
22945
23174
|
}
|
|
22946
|
-
if (
|
|
23175
|
+
if (key.upArrow || input === "k") {
|
|
22947
23176
|
setCursorIdx((c) => Math.max(0, c - 1));
|
|
22948
23177
|
return;
|
|
22949
23178
|
}
|
|
22950
|
-
if (input === "d" &&
|
|
22951
|
-
|
|
22952
|
-
if (target !== void 0) setConfirmRemove(target);
|
|
23179
|
+
if (input === "d" && focused?.kind === "repo") {
|
|
23180
|
+
setConfirmRemove(focused.repo);
|
|
22953
23181
|
return;
|
|
22954
23182
|
}
|
|
22955
|
-
if (input === "c" &&
|
|
22956
|
-
|
|
22957
|
-
if (target !== void 0) void launchPerRepoFlow("detect-scripts", target);
|
|
23183
|
+
if (input === "c" && focused?.kind === "repo") {
|
|
23184
|
+
void launchPerRepoFlow("detect-scripts", focused.repo);
|
|
22958
23185
|
return;
|
|
22959
23186
|
}
|
|
22960
|
-
if (input === "S" &&
|
|
22961
|
-
|
|
22962
|
-
if (target !== void 0) void launchPerRepoFlow("detect-skills", target);
|
|
23187
|
+
if (input === "S" && focused?.kind === "repo") {
|
|
23188
|
+
void launchPerRepoFlow("detect-skills", focused.repo);
|
|
22963
23189
|
}
|
|
22964
23190
|
});
|
|
22965
23191
|
const claimPrompt = ui.claimPrompt;
|
|
@@ -22991,14 +23217,7 @@ var ProjectDetailView = () => {
|
|
|
22991
23217
|
onCancel: () => setConfirmRemove(void 0)
|
|
22992
23218
|
}
|
|
22993
23219
|
) })
|
|
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
|
-
) });
|
|
23220
|
+
] }) : /* @__PURE__ */ jsx47(Body, { project: state.value, focused, feedback: feedback ?? edit.feedback }) });
|
|
23002
23221
|
};
|
|
23003
23222
|
var removeRepoFromProject = async (project, repoId, projectRepo) => {
|
|
23004
23223
|
const updated = removeRepository(project, repoId);
|
|
@@ -23007,85 +23226,91 @@ var removeRepoFromProject = async (project, repoId, projectRepo) => {
|
|
|
23007
23226
|
if (!saved.ok) return { ok: false, error: saved.error.message };
|
|
23008
23227
|
return { ok: true };
|
|
23009
23228
|
};
|
|
23010
|
-
var
|
|
23011
|
-
|
|
23012
|
-
|
|
23229
|
+
var focusable = (focused, node) => /* @__PURE__ */ jsxs36(Text37, { ...focused ? { color: inkColors.primary } : {}, bold: focused, children: [
|
|
23230
|
+
focused ? `${glyphs.actionCursor} ` : " ",
|
|
23231
|
+
node
|
|
23232
|
+
] });
|
|
23233
|
+
var noneText = /* @__PURE__ */ jsx47(Text37, { dimColor: true, italic: true, children: "(none)" });
|
|
23234
|
+
var RepoCard = ({ repo, focused }) => {
|
|
23235
|
+
const repoFocused = focused?.kind === "repo" && focused.repo.id === repo.id;
|
|
23236
|
+
const nameFocused = repoFocused && focused.field === "name";
|
|
23237
|
+
const setupFocused = repoFocused && focused.field === "setupScript";
|
|
23238
|
+
const verifyFocused = repoFocused && focused.field === "verifyScript";
|
|
23239
|
+
return /* @__PURE__ */ jsxs36(
|
|
23240
|
+
Box35,
|
|
23013
23241
|
{
|
|
23014
|
-
|
|
23015
|
-
|
|
23016
|
-
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23242
|
+
flexDirection: "column",
|
|
23243
|
+
borderStyle: "round",
|
|
23244
|
+
borderColor: inkColors.rule,
|
|
23245
|
+
paddingX: spacing.cardPadX,
|
|
23246
|
+
marginTop: 1,
|
|
23247
|
+
children: [
|
|
23248
|
+
/* @__PURE__ */ jsxs36(Text37, { bold: true, ...nameFocused ? { color: inkColors.primary } : {}, children: [
|
|
23249
|
+
nameFocused ? `${glyphs.actionCursor} ` : " ",
|
|
23250
|
+
repo.name,
|
|
23251
|
+
" ",
|
|
23252
|
+
/* @__PURE__ */ jsxs36(Text37, { dimColor: true, children: [
|
|
23253
|
+
"(",
|
|
23254
|
+
repo.slug,
|
|
23255
|
+
")"
|
|
23256
|
+
] })
|
|
23257
|
+
] }),
|
|
23258
|
+
/* @__PURE__ */ jsx47(
|
|
23259
|
+
FieldList,
|
|
23260
|
+
{
|
|
23261
|
+
fields: [
|
|
23262
|
+
{ label: "Path", value: /* @__PURE__ */ jsx47(Text37, { dimColor: true, children: repo.path }) },
|
|
23263
|
+
{ label: "Setup", value: focusable(setupFocused, repo.setupScript ?? noneText) },
|
|
23264
|
+
{ label: "Verify", value: focusable(verifyFocused, repo.verifyScript ?? noneText) }
|
|
23265
|
+
]
|
|
23266
|
+
}
|
|
23267
|
+
)
|
|
23020
23268
|
]
|
|
23021
23269
|
}
|
|
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
|
-
] });
|
|
23270
|
+
);
|
|
23271
|
+
};
|
|
23272
|
+
var Body = ({ project, focused, feedback }) => {
|
|
23273
|
+
const projectNameFocused = focused?.kind === "project";
|
|
23274
|
+
return /* @__PURE__ */ jsxs36(Box35, { flexDirection: "column", children: [
|
|
23275
|
+
/* @__PURE__ */ jsx47(Card, { title: "Project", tone: "primary", children: /* @__PURE__ */ jsx47(
|
|
23276
|
+
FieldList,
|
|
23277
|
+
{
|
|
23278
|
+
fields: [
|
|
23279
|
+
{
|
|
23280
|
+
label: "Name",
|
|
23281
|
+
value: focusable(projectNameFocused, /* @__PURE__ */ jsx47(Text37, { bold: true, children: project.displayName }))
|
|
23282
|
+
},
|
|
23283
|
+
{ label: "Slug", value: project.slug },
|
|
23284
|
+
{ label: "Id", value: /* @__PURE__ */ jsx47(Text37, { dimColor: true, children: project.id }) },
|
|
23285
|
+
...project.description !== void 0 ? [{ label: "Description", value: project.description }] : [],
|
|
23286
|
+
{ label: "Repositories", value: String(project.repositories.length) }
|
|
23287
|
+
]
|
|
23288
|
+
}
|
|
23289
|
+
) }),
|
|
23290
|
+
/* @__PURE__ */ jsxs36(Box35, { marginTop: spacing.section, flexDirection: "column", children: [
|
|
23291
|
+
/* @__PURE__ */ jsxs36(Text37, { bold: true, children: [
|
|
23292
|
+
glyphs.badge,
|
|
23293
|
+
" Repositories"
|
|
23294
|
+
] }),
|
|
23295
|
+
project.repositories.map((repo) => /* @__PURE__ */ jsx47(RepoCard, { repo, focused }, repo.id)),
|
|
23296
|
+
/* @__PURE__ */ jsx47(Box35, { paddingX: spacing.indent, marginTop: spacing.section, children: /* @__PURE__ */ jsxs36(Text37, { dimColor: true, children: [
|
|
23297
|
+
"a add ",
|
|
23298
|
+
glyphs.bullet,
|
|
23299
|
+
" \u2191/\u2193 navigate ",
|
|
23300
|
+
glyphs.bullet,
|
|
23301
|
+
" e/\u21B5 edit field ",
|
|
23302
|
+
glyphs.bullet,
|
|
23303
|
+
" c detect scripts",
|
|
23304
|
+
" ",
|
|
23305
|
+
glyphs.bullet,
|
|
23306
|
+
" S detect skills ",
|
|
23307
|
+
glyphs.bullet,
|
|
23308
|
+
" d remove (keeps \u2265 1)"
|
|
23309
|
+
] }) }),
|
|
23310
|
+
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 }) })
|
|
23311
|
+
] })
|
|
23312
|
+
] });
|
|
23313
|
+
};
|
|
23089
23314
|
|
|
23090
23315
|
// src/application/ui/tui/views/sprints-view.tsx
|
|
23091
23316
|
import { useEffect as useEffect20, useState as useState29 } from "react";
|
|
@@ -23138,8 +23363,8 @@ var SprintsView = () => {
|
|
|
23138
23363
|
const { state, reload } = useAsyncLoad(async () => {
|
|
23139
23364
|
const r = await deps.sprintRepo.list();
|
|
23140
23365
|
if (!r.ok) throw new Error(r.error.message);
|
|
23141
|
-
const
|
|
23142
|
-
return
|
|
23366
|
+
const scoped = selection.projectId !== void 0 ? r.value.filter((s) => s.projectId === selection.projectId) : r.value;
|
|
23367
|
+
return [...scoped].sort((a, b) => a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
|
|
23143
23368
|
}, [selection.projectId]);
|
|
23144
23369
|
const items = state.kind === "ok" ? state.value : [];
|
|
23145
23370
|
const [cursorId, setCursorId] = useState29(void 0);
|
|
@@ -23392,7 +23617,7 @@ var SprintsView = () => {
|
|
|
23392
23617
|
};
|
|
23393
23618
|
|
|
23394
23619
|
// src/application/ui/tui/views/sprint-detail-view.tsx
|
|
23395
|
-
import { useEffect as useEffect22, useMemo as
|
|
23620
|
+
import { useEffect as useEffect22, useMemo as useMemo14, useState as useState31 } from "react";
|
|
23396
23621
|
import { Box as Box44, Text as Text46 } from "ink";
|
|
23397
23622
|
|
|
23398
23623
|
// src/application/flows/ticket-remove/flow.ts
|
|
@@ -24308,8 +24533,8 @@ var SprintDetailView = () => {
|
|
|
24308
24533
|
const selection = useSelection();
|
|
24309
24534
|
const { state, project, reload } = useSprintBundle({ sprintId, deps });
|
|
24310
24535
|
const sprint = state.kind === "ok" ? state.value.sprint : void 0;
|
|
24311
|
-
const tasks =
|
|
24312
|
-
const focusList =
|
|
24536
|
+
const tasks = useMemo14(() => state.kind === "ok" ? state.value.tasks : [], [state]);
|
|
24537
|
+
const focusList = useMemo14(() => sprint !== void 0 ? buildFocusList(sprint, tasks) : [], [sprint, tasks]);
|
|
24313
24538
|
const [cursorIdx, setCursorIdx] = useState31(0);
|
|
24314
24539
|
const [openIds, setOpenIds] = useState31(() => /* @__PURE__ */ new Set());
|
|
24315
24540
|
const [confirmRemove, setConfirmRemove] = useState31(void 0);
|
|
@@ -24527,13 +24752,12 @@ var useSinkStream = (bus, opts = {}) => {
|
|
|
24527
24752
|
const [items, setItems] = useState33(() => replay ? bus.entries.slice(-limit) : []);
|
|
24528
24753
|
useEffect24(() => {
|
|
24529
24754
|
if (replay) setItems(bus.entries.slice(-limit));
|
|
24530
|
-
|
|
24755
|
+
return bus.subscribe((value) => {
|
|
24531
24756
|
setItems((prev) => {
|
|
24532
24757
|
const next = [...prev, value];
|
|
24533
24758
|
return next.length > limit ? next.slice(next.length - limit) : next;
|
|
24534
24759
|
});
|
|
24535
24760
|
});
|
|
24536
|
-
return unsub;
|
|
24537
24761
|
}, [bus, limit, replay]);
|
|
24538
24762
|
return items;
|
|
24539
24763
|
};
|
|
@@ -24546,14 +24770,13 @@ var useEventBusBuffer = (bus, opts) => {
|
|
|
24546
24770
|
const filterRef = useRef11(opts.filter);
|
|
24547
24771
|
filterRef.current = opts.filter;
|
|
24548
24772
|
useEffect25(() => {
|
|
24549
|
-
|
|
24773
|
+
return bus.subscribe((event) => {
|
|
24550
24774
|
if (!filterRef.current(event)) return;
|
|
24551
24775
|
setItems((prev) => {
|
|
24552
24776
|
const next = [...prev, event];
|
|
24553
24777
|
return next.length > limit ? next.slice(next.length - limit) : next;
|
|
24554
24778
|
});
|
|
24555
24779
|
});
|
|
24556
|
-
return unsub;
|
|
24557
24780
|
}, [bus, limit]);
|
|
24558
24781
|
return items;
|
|
24559
24782
|
};
|
|
@@ -24888,7 +25111,7 @@ import "react";
|
|
|
24888
25111
|
import { Box as Box53 } from "ink";
|
|
24889
25112
|
|
|
24890
25113
|
// src/application/ui/tui/components/baseline-health-card.tsx
|
|
24891
|
-
import { useMemo as
|
|
25114
|
+
import { useMemo as useMemo15 } from "react";
|
|
24892
25115
|
import { Box as Box49, Text as Text51 } from "ink";
|
|
24893
25116
|
import { jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
24894
25117
|
var tierColor3 = (tier) => {
|
|
@@ -25026,14 +25249,14 @@ var CompactCleanRow = ({ rows }) => {
|
|
|
25026
25249
|
};
|
|
25027
25250
|
var BaselineHealthCard = ({ execution, tasks, now, width }) => {
|
|
25028
25251
|
const tNow = now ?? Date.now();
|
|
25029
|
-
const taskList =
|
|
25252
|
+
const taskList = useMemo15(() => tasks ?? [], [tasks]);
|
|
25030
25253
|
const cardWidth = width ?? CONTEXT_WIDTH;
|
|
25031
|
-
const setupData =
|
|
25032
|
-
const preRun =
|
|
25033
|
-
const postRun =
|
|
25254
|
+
const setupData = useMemo15(() => setupRowData(execution, tNow), [execution, tNow]);
|
|
25255
|
+
const preRun = useMemo15(() => latestVerifyRun(taskList, "pre"), [taskList]);
|
|
25256
|
+
const postRun = useMemo15(() => latestVerifyRun(taskList, "post"), [taskList]);
|
|
25034
25257
|
const preData = verifyRowData(preRun, tNow, "Pre verify");
|
|
25035
25258
|
const postData = verifyRowData(postRun, tNow, "Post verify");
|
|
25036
|
-
const counts =
|
|
25259
|
+
const counts = useMemo15(() => countAttributions(taskList), [taskList]);
|
|
25037
25260
|
const attribData = attributionRowData(counts);
|
|
25038
25261
|
const rows = [setupData, preData, postData, attribData];
|
|
25039
25262
|
const health = synthesiseBaselineHealth({
|
|
@@ -25155,7 +25378,7 @@ var Section2 = ({
|
|
|
25155
25378
|
import "react";
|
|
25156
25379
|
|
|
25157
25380
|
// src/application/ui/tui/components/step-trace.tsx
|
|
25158
|
-
import { useMemo as
|
|
25381
|
+
import { useMemo as useMemo16 } from "react";
|
|
25159
25382
|
import { Box as Box52, Text as Text54 } from "ink";
|
|
25160
25383
|
import { Fragment as Fragment5, jsx as jsx64, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
25161
25384
|
var glyphFor2 = (status) => {
|
|
@@ -25237,12 +25460,12 @@ var StepTrace = ({
|
|
|
25237
25460
|
railWidth
|
|
25238
25461
|
}) => {
|
|
25239
25462
|
const traceLastEntry = trace[trace.length - 1];
|
|
25240
|
-
const merged =
|
|
25463
|
+
const merged = useMemo16(
|
|
25241
25464
|
() => plan !== void 0 ? mergePlanWithTrace(plan, trace, running, labelByName) : traceToRows(trace),
|
|
25242
25465
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- in-place ring-buffer mutation; see comment above
|
|
25243
25466
|
[plan, labelByName, trace, trace.length, traceLastEntry, running]
|
|
25244
25467
|
);
|
|
25245
|
-
const filtered =
|
|
25468
|
+
const filtered = useMemo16(
|
|
25246
25469
|
() => filter !== void 0 ? merged.filter((r) => filter(r.name)) : merged,
|
|
25247
25470
|
[merged, filter]
|
|
25248
25471
|
);
|
|
@@ -25791,7 +26014,7 @@ var ExecuteBody = ({
|
|
|
25791
26014
|
] });
|
|
25792
26015
|
|
|
25793
26016
|
// src/application/ui/tui/views/execute-view-internals/tasks-panel-host.tsx
|
|
25794
|
-
import { useMemo as
|
|
26017
|
+
import { useMemo as useMemo17 } from "react";
|
|
25795
26018
|
import { jsx as jsx72 } from "react/jsx-runtime";
|
|
25796
26019
|
var TasksPanelHost = ({
|
|
25797
26020
|
bucketed,
|
|
@@ -25802,7 +26025,7 @@ var TasksPanelHost = ({
|
|
|
25802
26025
|
now,
|
|
25803
26026
|
taskState
|
|
25804
26027
|
}) => {
|
|
25805
|
-
const taskCriteriaById =
|
|
26028
|
+
const taskCriteriaById = useMemo17(() => {
|
|
25806
26029
|
if (taskState === void 0) return void 0;
|
|
25807
26030
|
const m = /* @__PURE__ */ new Map();
|
|
25808
26031
|
for (const t of taskState) {
|
|
@@ -25951,25 +26174,31 @@ var useBaselineHealthData = ({
|
|
|
25951
26174
|
};
|
|
25952
26175
|
|
|
25953
26176
|
// src/application/ui/tui/views/execute-view-internals/use-bucketed-tasks.ts
|
|
25954
|
-
import { useMemo as
|
|
26177
|
+
import { useMemo as useMemo18 } from "react";
|
|
25955
26178
|
|
|
25956
26179
|
// src/application/ui/tui/runtime/use-task-round-tracker.ts
|
|
25957
26180
|
import { useEffect as useEffect28, useState as useState35 } from "react";
|
|
26181
|
+
var TASK_ROUND_CAP = 500;
|
|
25958
26182
|
var isTaskRoundStarted = (e) => e.type === "task-round-started";
|
|
25959
26183
|
var useTaskRoundTracker = (bus) => {
|
|
25960
26184
|
const [rounds, setRounds] = useState35(() => /* @__PURE__ */ new Map());
|
|
25961
26185
|
useEffect28(() => {
|
|
25962
|
-
|
|
26186
|
+
return bus.subscribe((event) => {
|
|
25963
26187
|
if (!isTaskRoundStarted(event)) return;
|
|
25964
26188
|
setRounds((prev) => {
|
|
25965
26189
|
const existing = prev.get(event.taskId);
|
|
25966
26190
|
if (existing !== void 0 && existing.roundN >= event.roundN) return prev;
|
|
25967
26191
|
const next = new Map(prev);
|
|
26192
|
+
next.delete(event.taskId);
|
|
25968
26193
|
next.set(event.taskId, { roundN: event.roundN, totalCap: event.totalCap });
|
|
26194
|
+
while (next.size > TASK_ROUND_CAP) {
|
|
26195
|
+
const oldest = next.keys().next().value;
|
|
26196
|
+
if (oldest === void 0) break;
|
|
26197
|
+
next.delete(oldest);
|
|
26198
|
+
}
|
|
25969
26199
|
return next;
|
|
25970
26200
|
});
|
|
25971
26201
|
});
|
|
25972
|
-
return unsub;
|
|
25973
26202
|
}, [bus]);
|
|
25974
26203
|
return rounds;
|
|
25975
26204
|
};
|
|
@@ -25981,7 +26210,7 @@ var useBucketedTasks = ({
|
|
|
25981
26210
|
signals,
|
|
25982
26211
|
eventBus
|
|
25983
26212
|
}) => {
|
|
25984
|
-
const rawBucketed =
|
|
26213
|
+
const rawBucketed = useMemo18(
|
|
25985
26214
|
() => descriptor ? bucketTaskSignals(descriptor.trace, chainEvents, signals, {
|
|
25986
26215
|
...descriptor.maxTurns !== void 0 ? { maxTurns: descriptor.maxTurns } : {},
|
|
25987
26216
|
...descriptor.terminalSubstepName !== void 0 ? { terminalSubstepName: descriptor.terminalSubstepName } : {},
|
|
@@ -25994,7 +26223,7 @@ var useBucketedTasks = ({
|
|
|
25994
26223
|
[descriptor, chainEvents, signals]
|
|
25995
26224
|
);
|
|
25996
26225
|
const taskRounds = useTaskRoundTracker(eventBus);
|
|
25997
|
-
const bucketed =
|
|
26226
|
+
const bucketed = useMemo18(() => {
|
|
25998
26227
|
if (rawBucketed === void 0) return void 0;
|
|
25999
26228
|
const tasks = rawBucketed.tasks.map((t) => {
|
|
26000
26229
|
const tracked = taskRounds.get(t.id);
|
|
@@ -26102,14 +26331,14 @@ var useCancelHandlers = ({
|
|
|
26102
26331
|
};
|
|
26103
26332
|
|
|
26104
26333
|
// src/application/ui/tui/views/execute-view-internals/use-cancel-scope-stats.ts
|
|
26105
|
-
import { useMemo as
|
|
26334
|
+
import { useMemo as useMemo19 } from "react";
|
|
26106
26335
|
var useCancelScopeStats = ({
|
|
26107
26336
|
chainEvents,
|
|
26108
26337
|
currentTask,
|
|
26109
26338
|
bucketed,
|
|
26110
26339
|
now
|
|
26111
26340
|
}) => {
|
|
26112
|
-
const attemptElapsedMs2 =
|
|
26341
|
+
const attemptElapsedMs2 = useMemo19(() => {
|
|
26113
26342
|
if (currentTask === void 0) return void 0;
|
|
26114
26343
|
let latestStartMs;
|
|
26115
26344
|
for (const ev of chainEvents) {
|
|
@@ -26120,7 +26349,7 @@ var useCancelScopeStats = ({
|
|
|
26120
26349
|
}
|
|
26121
26350
|
return latestStartMs !== void 0 ? Math.max(0, now - latestStartMs) : void 0;
|
|
26122
26351
|
}, [chainEvents, currentTask, now]);
|
|
26123
|
-
const remainingTaskCount =
|
|
26352
|
+
const remainingTaskCount = useMemo19(() => {
|
|
26124
26353
|
if (bucketed === void 0) return 0;
|
|
26125
26354
|
return bucketed.tasks.reduce((n, t) => t.status === "completed" ? n : n + 1, 0);
|
|
26126
26355
|
}, [bucketed]);
|
|
@@ -26341,7 +26570,7 @@ import { useEffect as useEffect31, useState as useState38 } from "react";
|
|
|
26341
26570
|
import { Box as Box60, Text as Text59, useInput as useInput22 } from "ink";
|
|
26342
26571
|
|
|
26343
26572
|
// src/application/ui/tui/components/list-view.tsx
|
|
26344
|
-
import { useEffect as useEffect30, useMemo as
|
|
26573
|
+
import { useEffect as useEffect30, useMemo as useMemo20, useState as useState37 } from "react";
|
|
26345
26574
|
import { Box as Box59, Text as Text58, useInput as useInput21 } from "ink";
|
|
26346
26575
|
import { jsx as jsx74, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
26347
26576
|
var clamp4 = (n, min, max) => Math.max(min, Math.min(max, n));
|
|
@@ -26380,7 +26609,7 @@ function ListView({
|
|
|
26380
26609
|
},
|
|
26381
26610
|
{ isActive: active }
|
|
26382
26611
|
);
|
|
26383
|
-
const window =
|
|
26612
|
+
const window = useMemo20(() => {
|
|
26384
26613
|
const half = Math.floor(visibleRows / 2);
|
|
26385
26614
|
const start = clamp4(cursor - half, 0, Math.max(0, items.length - visibleRows));
|
|
26386
26615
|
const end = Math.min(items.length, start + visibleRows);
|
|
@@ -26529,7 +26758,7 @@ var SessionsView = () => {
|
|
|
26529
26758
|
};
|
|
26530
26759
|
|
|
26531
26760
|
// src/application/ui/tui/views/settings-view.tsx
|
|
26532
|
-
import React86, { useEffect as useEffect32, useMemo as
|
|
26761
|
+
import React86, { useEffect as useEffect32, useMemo as useMemo21, useState as useState39 } from "react";
|
|
26533
26762
|
import { Box as Box64, Text as Text63, useInput as useInput23 } from "ink";
|
|
26534
26763
|
|
|
26535
26764
|
// src/application/flows/settings-show/flow.ts
|
|
@@ -26554,11 +26783,11 @@ var MIXED = {
|
|
|
26554
26783
|
refine: { provider: "openai-codex", model: "gpt-5.5" },
|
|
26555
26784
|
plan: { provider: "github-copilot", model: "claude-sonnet-4.6", effort: "xhigh" },
|
|
26556
26785
|
implement: {
|
|
26557
|
-
generator: { provider: "claude-code", model: "claude-opus-4-
|
|
26558
|
-
evaluator: { provider: "claude-code", model: "claude-opus-4-
|
|
26786
|
+
generator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" },
|
|
26787
|
+
evaluator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" }
|
|
26559
26788
|
},
|
|
26560
26789
|
readiness: { provider: "github-copilot", model: "gpt-5-mini", effort: "medium" },
|
|
26561
|
-
ideate: { provider: "claude-code", model: "claude-opus-4-
|
|
26790
|
+
ideate: { provider: "claude-code", model: "claude-opus-4-8" },
|
|
26562
26791
|
// PR content drafting mirrors refine's "light summary" reasoning profile — a fast Codex
|
|
26563
26792
|
// model is fine, no need to pay for Opus tokens just to summarise a diff.
|
|
26564
26793
|
createPr: { provider: "openai-codex", model: "gpt-5.4-mini" }
|
|
@@ -26566,13 +26795,13 @@ var MIXED = {
|
|
|
26566
26795
|
var CLAUDE_ONLY = {
|
|
26567
26796
|
effort: "high",
|
|
26568
26797
|
refine: { provider: "claude-code", model: "claude-sonnet-4-6" },
|
|
26569
|
-
plan: { provider: "claude-code", model: "claude-opus-4-
|
|
26798
|
+
plan: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" },
|
|
26570
26799
|
implement: {
|
|
26571
|
-
generator: { provider: "claude-code", model: "claude-opus-4-
|
|
26572
|
-
evaluator: { provider: "claude-code", model: "claude-opus-4-
|
|
26800
|
+
generator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" },
|
|
26801
|
+
evaluator: { provider: "claude-code", model: "claude-opus-4-8", effort: "xhigh" }
|
|
26573
26802
|
},
|
|
26574
26803
|
readiness: { provider: "claude-code", model: "claude-haiku-4-5", effort: "medium" },
|
|
26575
|
-
ideate: { provider: "claude-code", model: "claude-opus-4-
|
|
26804
|
+
ideate: { provider: "claude-code", model: "claude-opus-4-8" },
|
|
26576
26805
|
createPr: { provider: "claude-code", model: "claude-sonnet-4-6" }
|
|
26577
26806
|
};
|
|
26578
26807
|
var COPILOT_ONLY = {
|
|
@@ -27247,12 +27476,12 @@ var SettingsView = () => {
|
|
|
27247
27476
|
cancelled = true;
|
|
27248
27477
|
};
|
|
27249
27478
|
}, []);
|
|
27250
|
-
const sections =
|
|
27479
|
+
const sections = useMemo21(
|
|
27251
27480
|
() => settings === void 0 ? [] : buildSections(settings),
|
|
27252
27481
|
[settings]
|
|
27253
27482
|
);
|
|
27254
27483
|
const activeSection = sections[sectionIdx];
|
|
27255
|
-
const activeFields =
|
|
27484
|
+
const activeFields = useMemo21(() => activeSection?.fields ?? [], [activeSection]);
|
|
27256
27485
|
useEffect32(() => {
|
|
27257
27486
|
if (cursor >= activeFields.length && activeFields.length > 0) setCursor(activeFields.length - 1);
|
|
27258
27487
|
}, [activeFields, cursor]);
|
|
@@ -28091,20 +28320,20 @@ var renderIssueRefs = (refs) => {
|
|
|
28091
28320
|
var buildCreatePrPrompt = async (deps, input) => buildPrompt(deps, createPrPromptDef, input);
|
|
28092
28321
|
|
|
28093
28322
|
// src/application/flows/create-pr/leaves/generate-pr-content.contract.ts
|
|
28094
|
-
import { z as
|
|
28323
|
+
import { z as z46 } from "zod";
|
|
28095
28324
|
|
|
28096
28325
|
// src/integration/ai/contract/_engine/signals/pr-content/schema.ts
|
|
28097
|
-
import { z as
|
|
28098
|
-
var prContentSignalSchema =
|
|
28099
|
-
type:
|
|
28100
|
-
title:
|
|
28101
|
-
body:
|
|
28326
|
+
import { z as z45 } from "zod";
|
|
28327
|
+
var prContentSignalSchema = z45.object({
|
|
28328
|
+
type: z45.literal("pr-content"),
|
|
28329
|
+
title: z45.string(),
|
|
28330
|
+
body: z45.string(),
|
|
28102
28331
|
timestamp: IsoTimestampSchema
|
|
28103
28332
|
});
|
|
28104
28333
|
|
|
28105
28334
|
// src/application/flows/create-pr/leaves/generate-pr-content.contract.ts
|
|
28106
28335
|
var exactlyOnePrContent = (signals) => signals.filter((s) => s.type === "pr-content").length === 1;
|
|
28107
|
-
var signalsArraySchemaRaw10 =
|
|
28336
|
+
var signalsArraySchemaRaw10 = z46.array(prContentSignalSchema).refine(exactlyOnePrContent, "exactly one pr-content signal per create-pr spawn");
|
|
28108
28337
|
var signalsArraySchema10 = brandSignalArray(signalsArraySchemaRaw10);
|
|
28109
28338
|
var prContentSidecar = {
|
|
28110
28339
|
signalKind: "pr-content",
|
|
@@ -28189,9 +28418,9 @@ var generatePrContentLeaf = (deps) => leaf("generate-pr-content", {
|
|
|
28189
28418
|
outputDir: input.unitRoot
|
|
28190
28419
|
};
|
|
28191
28420
|
try {
|
|
28192
|
-
const
|
|
28193
|
-
if (!
|
|
28194
|
-
deps.logger.named("create-pr.ai").warn(`create-pr: AI authoring failed, falling back to template (${
|
|
28421
|
+
const spawn2 = await deps.provider.generate(session);
|
|
28422
|
+
if (!spawn2.ok) {
|
|
28423
|
+
deps.logger.named("create-pr.ai").warn(`create-pr: AI authoring failed, falling back to template (${spawn2.error.message})`);
|
|
28195
28424
|
return Result.ok({});
|
|
28196
28425
|
}
|
|
28197
28426
|
const validated = await validateSignalsFile(input.unitRoot, generatePrContentOutputContract);
|
|
@@ -29193,14 +29422,14 @@ var backStep3 = (step) => {
|
|
|
29193
29422
|
};
|
|
29194
29423
|
|
|
29195
29424
|
// src/application/ui/tui/views/add-ticket-internals/review-scrollable-description.tsx
|
|
29196
|
-
import { useEffect as useEffect41, useMemo as
|
|
29425
|
+
import { useEffect as useEffect41, useMemo as useMemo22, useState as useState47 } from "react";
|
|
29197
29426
|
import { Box as Box74, Text as Text73, useInput as useInput29 } from "ink";
|
|
29198
29427
|
import { jsx as jsx91, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
29199
29428
|
var REVIEW_CHROME_ROWS = 14;
|
|
29200
29429
|
var REVIEW_MIN_VIEWPORT = 4;
|
|
29201
29430
|
var ReviewScrollableDescription = ({ text }) => {
|
|
29202
29431
|
const term = useTerminalSize();
|
|
29203
|
-
const lines =
|
|
29432
|
+
const lines = useMemo22(() => text.split("\n"), [text]);
|
|
29204
29433
|
const viewport = Math.max(REVIEW_MIN_VIEWPORT, term.rows - REVIEW_CHROME_ROWS);
|
|
29205
29434
|
const overflows = lines.length > viewport;
|
|
29206
29435
|
const maxOffset = Math.max(0, lines.length - viewport);
|
|
@@ -29440,7 +29669,7 @@ var AddTicketView = () => {
|
|
|
29440
29669
|
};
|
|
29441
29670
|
|
|
29442
29671
|
// src/application/ui/tui/views/pick-project-view.tsx
|
|
29443
|
-
import { useEffect as useEffect43, useMemo as
|
|
29672
|
+
import { useEffect as useEffect43, useMemo as useMemo23, useState as useState49 } from "react";
|
|
29444
29673
|
import { Box as Box77, Text as Text75, useInput as useInput30 } from "ink";
|
|
29445
29674
|
import { jsx as jsx94, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
29446
29675
|
var PickProjectView = () => {
|
|
@@ -29458,8 +29687,8 @@ var PickProjectView = () => {
|
|
|
29458
29687
|
if (!r.ok) throw new Error(r.error.message);
|
|
29459
29688
|
return r.value;
|
|
29460
29689
|
}, []);
|
|
29461
|
-
const projects =
|
|
29462
|
-
const initialIdx =
|
|
29690
|
+
const projects = useMemo23(() => state.kind === "ok" ? state.value : [], [state]);
|
|
29691
|
+
const initialIdx = useMemo23(() => {
|
|
29463
29692
|
if (selection.projectId === void 0) return 0;
|
|
29464
29693
|
const i = projects.findIndex((p) => p.id === selection.projectId);
|
|
29465
29694
|
return i === -1 ? 0 : i;
|
|
@@ -29549,7 +29778,7 @@ var PickProjectView = () => {
|
|
|
29549
29778
|
};
|
|
29550
29779
|
|
|
29551
29780
|
// src/application/ui/tui/views/pick-sprint-view.tsx
|
|
29552
|
-
import { useEffect as useEffect44, useMemo as
|
|
29781
|
+
import { useEffect as useEffect44, useMemo as useMemo25, useState as useState50 } from "react";
|
|
29553
29782
|
import { Box as Box79, Text as Text77, useInput as useInput31 } from "ink";
|
|
29554
29783
|
|
|
29555
29784
|
// src/application/ui/tui/views/pick-sprint-internals/types.ts
|
|
@@ -29653,7 +29882,7 @@ var computeWindow = (totalRows, cursor, visible) => {
|
|
|
29653
29882
|
};
|
|
29654
29883
|
|
|
29655
29884
|
// src/application/ui/tui/views/pick-sprint-internals/row-views.tsx
|
|
29656
|
-
import { useMemo as
|
|
29885
|
+
import { useMemo as useMemo24 } from "react";
|
|
29657
29886
|
import { Box as Box78, Text as Text76 } from "ink";
|
|
29658
29887
|
import { jsx as jsx95, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
29659
29888
|
var RowWindowView = ({
|
|
@@ -29662,7 +29891,7 @@ var RowWindowView = ({
|
|
|
29662
29891
|
visibleRows,
|
|
29663
29892
|
currentSprintId
|
|
29664
29893
|
}) => {
|
|
29665
|
-
const window =
|
|
29894
|
+
const window = useMemo24(() => computeWindow(rows.length, cursor, visibleRows), [rows.length, cursor, visibleRows]);
|
|
29666
29895
|
const slice = rows.slice(window.start, window.end);
|
|
29667
29896
|
return /* @__PURE__ */ jsxs76(Box78, { flexDirection: "column", children: [
|
|
29668
29897
|
window.hiddenAbove > 0 && /* @__PURE__ */ jsx95(Box78, { paddingX: spacing.indent, children: /* @__PURE__ */ jsxs76(Text76, { dimColor: true, children: [
|
|
@@ -29782,17 +30011,17 @@ var PickSprintView = () => {
|
|
|
29782
30011
|
},
|
|
29783
30012
|
[deps.sprintRepo, deps.projectRepo]
|
|
29784
30013
|
);
|
|
29785
|
-
const data =
|
|
30014
|
+
const data = useMemo25(
|
|
29786
30015
|
() => state.kind === "ok" ? state.value : { sprints: [], projectsById: /* @__PURE__ */ new Map() },
|
|
29787
30016
|
[state]
|
|
29788
30017
|
);
|
|
29789
|
-
const groups =
|
|
30018
|
+
const groups = useMemo25(() => buildGroups(data, selection.projectId, scopeAll), [data, selection.projectId, scopeAll]);
|
|
29790
30019
|
const includeCreate = selection.projectId !== void 0;
|
|
29791
|
-
const rows =
|
|
29792
|
-
const sprintCount =
|
|
30020
|
+
const rows = useMemo25(() => flatten(groups, includeCreate), [groups, includeCreate]);
|
|
30021
|
+
const sprintCount = useMemo25(() => rows.reduce((acc, r) => r.kind === "sprint" ? acc + 1 : acc, 0), [rows]);
|
|
29793
30022
|
const bp = useBreakpoint();
|
|
29794
30023
|
const visibleRows = Math.max(MIN_VISIBLE_ROWS, bp.rows - VERTICAL_CHROME_ROWS);
|
|
29795
|
-
const initialIdx =
|
|
30024
|
+
const initialIdx = useMemo25(() => {
|
|
29796
30025
|
if (selection.sprintId !== void 0) {
|
|
29797
30026
|
const i = rows.findIndex((r) => r.kind === "sprint" && r.sprint.id === selection.sprintId);
|
|
29798
30027
|
if (i !== -1) return i;
|
|
@@ -29981,7 +30210,7 @@ var renderView = (entry) => {
|
|
|
29981
30210
|
};
|
|
29982
30211
|
|
|
29983
30212
|
// src/application/ui/tui/runtime/use-global-keys.ts
|
|
29984
|
-
import { useEffect as useEffect45, useMemo as
|
|
30213
|
+
import { useEffect as useEffect45, useMemo as useMemo26, useRef as useRef13 } from "react";
|
|
29985
30214
|
import { useApp, useInput as useInput32 } from "ink";
|
|
29986
30215
|
|
|
29987
30216
|
// src/integration/io/clipboard.ts
|
|
@@ -30003,10 +30232,10 @@ var resolveHelpers = ({ platform, env }) => {
|
|
|
30003
30232
|
}
|
|
30004
30233
|
return [];
|
|
30005
30234
|
};
|
|
30006
|
-
var runHelper = (
|
|
30235
|
+
var runHelper = (spawn2, helper, text) => new Promise((resolve) => {
|
|
30007
30236
|
let child;
|
|
30008
30237
|
try {
|
|
30009
|
-
child =
|
|
30238
|
+
child = spawn2(helper.cmd, helper.args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
30010
30239
|
} catch (cause) {
|
|
30011
30240
|
resolve(
|
|
30012
30241
|
Result.error({
|
|
@@ -30050,7 +30279,7 @@ var runHelper = (spawn3, helper, text) => new Promise((resolve) => {
|
|
|
30050
30279
|
}
|
|
30051
30280
|
});
|
|
30052
30281
|
var createCopyToClipboard = (opts = {}) => {
|
|
30053
|
-
const
|
|
30282
|
+
const spawn2 = opts.spawn ?? nodeSpawn10;
|
|
30054
30283
|
const platform = opts.platform ?? process.platform;
|
|
30055
30284
|
const env = opts.env ?? process.env;
|
|
30056
30285
|
const helpers = resolveHelpers({ platform, env });
|
|
@@ -30063,7 +30292,7 @@ var createCopyToClipboard = (opts = {}) => {
|
|
|
30063
30292
|
}
|
|
30064
30293
|
let lastError;
|
|
30065
30294
|
for (const helper of helpers) {
|
|
30066
|
-
const result = await runHelper(
|
|
30295
|
+
const result = await runHelper(spawn2, helper, text);
|
|
30067
30296
|
if (result.ok) return result;
|
|
30068
30297
|
lastError = result.error;
|
|
30069
30298
|
if (result.error.code !== "no-helper") return result;
|
|
@@ -30086,7 +30315,7 @@ var useGlobalKeys = (opts = {}) => {
|
|
|
30086
30315
|
const ui = useUiState();
|
|
30087
30316
|
const selection = useSelection();
|
|
30088
30317
|
const deps = useDeps();
|
|
30089
|
-
const copyToClipboard =
|
|
30318
|
+
const copyToClipboard = useMemo26(
|
|
30090
30319
|
() => opts.copyToClipboard ?? createCopyToClipboard(),
|
|
30091
30320
|
[opts.copyToClipboard]
|
|
30092
30321
|
);
|
|
@@ -30259,7 +30488,7 @@ var ChainLogDegradedBanner = () => {
|
|
|
30259
30488
|
// src/application/ui/tui/components/progress-overlay.tsx
|
|
30260
30489
|
import { promises as fs29 } from "fs";
|
|
30261
30490
|
import { join as join54 } from "path";
|
|
30262
|
-
import { useEffect as useEffect48, useMemo as
|
|
30491
|
+
import { useEffect as useEffect48, useMemo as useMemo27, useState as useState53 } from "react";
|
|
30263
30492
|
import { Box as Box82, Text as Text80, useInput as useInput33 } from "ink";
|
|
30264
30493
|
import { jsx as jsx99, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
30265
30494
|
var CHROME_ROWS = 10;
|
|
@@ -30276,7 +30505,7 @@ var ProgressOverlay = () => {
|
|
|
30276
30505
|
const [offset, setOffset] = useState53(0);
|
|
30277
30506
|
const [now] = useState53(() => Date.now());
|
|
30278
30507
|
const sprintId = selection.sprintId;
|
|
30279
|
-
const progressPath =
|
|
30508
|
+
const progressPath = useMemo27(() => {
|
|
30280
30509
|
if (sprintId === void 0) return void 0;
|
|
30281
30510
|
return join54(String(storage2.dataRoot), "sprints", String(sprintId), "progress.md");
|
|
30282
30511
|
}, [sprintId, storage2.dataRoot]);
|
|
@@ -30471,20 +30700,23 @@ var resolveInitialState = ({
|
|
|
30471
30700
|
settingsExist,
|
|
30472
30701
|
projects,
|
|
30473
30702
|
lastProjectId,
|
|
30474
|
-
lastSprintId
|
|
30703
|
+
lastSprintId,
|
|
30704
|
+
sprints
|
|
30475
30705
|
}) => {
|
|
30476
30706
|
if (!settingsExist) return { initialView: { id: "welcome" } };
|
|
30477
|
-
|
|
30707
|
+
const [first] = projects;
|
|
30708
|
+
if (first === void 0) return { initialView: { id: "create-project" } };
|
|
30478
30709
|
const restored = lastProjectId !== void 0 ? projects.find((p) => p.id === lastProjectId) : void 0;
|
|
30479
|
-
const
|
|
30480
|
-
|
|
30481
|
-
const
|
|
30710
|
+
const resolvedProject = restored ?? first;
|
|
30711
|
+
const projectSprints = (sprints ?? []).filter((s) => s.projectId === resolvedProject.id).slice().sort((a, b) => a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
|
|
30712
|
+
const persistedSprintValid = restored !== void 0 && lastSprintId !== void 0 && projectSprints.some((s) => s.id === lastSprintId);
|
|
30713
|
+
const seededSprintId = persistedSprintValid ? lastSprintId : projectSprints[0]?.id;
|
|
30482
30714
|
return {
|
|
30483
30715
|
initialView: { id: "home" },
|
|
30484
30716
|
initialSelection: {
|
|
30485
|
-
projectId:
|
|
30486
|
-
projectLabel:
|
|
30487
|
-
...
|
|
30717
|
+
projectId: resolvedProject.id,
|
|
30718
|
+
projectLabel: resolvedProject.displayName,
|
|
30719
|
+
...seededSprintId !== void 0 ? { sprintId: seededSprintId } : {}
|
|
30488
30720
|
}
|
|
30489
30721
|
};
|
|
30490
30722
|
};
|
|
@@ -30783,11 +31015,13 @@ var bootstrap = async () => {
|
|
|
30783
31015
|
void createInkInteractivePrompt(queue);
|
|
30784
31016
|
const settingsExists = await deps.settingsRepo.exists();
|
|
30785
31017
|
const projectsList = await deps.projectRepo.list();
|
|
31018
|
+
const sprintsResult = await deps.sprintRepo.list();
|
|
30786
31019
|
const lastSelectionStore = createLastSelectionStore(paths.value.stateRoot);
|
|
30787
31020
|
const lastSelection = await lastSelectionStore.read();
|
|
30788
31021
|
const { initialView, initialSelection } = resolveInitialState({
|
|
30789
31022
|
settingsExist: settingsExists.ok ? settingsExists.value : false,
|
|
30790
31023
|
projects: projectsList.ok ? projectsList.value : [],
|
|
31024
|
+
sprints: sprintsResult.ok ? sprintsResult.value : [],
|
|
30791
31025
|
...lastSelection !== void 0 ? { lastProjectId: lastSelection.projectId } : {},
|
|
30792
31026
|
...lastSelection?.sprintId !== void 0 ? { lastSprintId: lastSelection.sprintId } : {}
|
|
30793
31027
|
});
|