strikethroo 3.18.0 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-web/assets/{arc-BlSNa2QY.js → arc-XmjVSUrZ.js} +1 -1
- package/dist-web/assets/{architectureDiagram-3BPJPVTR-CPcCF2a4.js → architectureDiagram-3BPJPVTR-BkIMNPZQ.js} +1 -1
- package/dist-web/assets/{blockDiagram-GPEHLZMM-ECDR0edZ.js → blockDiagram-GPEHLZMM-CIUhAyCy.js} +1 -1
- package/dist-web/assets/{c4Diagram-AAUBKEIU-oM3VnEAQ.js → c4Diagram-AAUBKEIU-DHmyXhPl.js} +1 -1
- package/dist-web/assets/channel-BluR9kJ8.js +1 -0
- package/dist-web/assets/{chunk-2J33WTMH-DHk5SJLz.js → chunk-2J33WTMH-CsadzJpE.js} +1 -1
- package/dist-web/assets/{chunk-4BX2VUAB-CjBwgkMu.js → chunk-4BX2VUAB-rdZMTiJd.js} +1 -1
- package/dist-web/assets/{chunk-55IACEB6-D95zqyiV.js → chunk-55IACEB6-BFgbJmlS.js} +1 -1
- package/dist-web/assets/{chunk-727SXJPM-DCCPRUfv.js → chunk-727SXJPM-CaGOdOo-.js} +1 -1
- package/dist-web/assets/{chunk-AQP2D5EJ-qur7KQyD.js → chunk-AQP2D5EJ-Dj1Z_buE.js} +1 -1
- package/dist-web/assets/{chunk-FMBD7UC4-D46Su7Fv.js → chunk-FMBD7UC4-ByPFO0XR.js} +1 -1
- package/dist-web/assets/{chunk-ND2GUHAM-BioGsqxt.js → chunk-ND2GUHAM-CRT0WqT3.js} +1 -1
- package/dist-web/assets/{chunk-QZHKN3VN-C8LdDiqn.js → chunk-QZHKN3VN-DeBs7Z-A.js} +1 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK-dvsWFqDg.js +1 -0
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-dvsWFqDg.js +1 -0
- package/dist-web/assets/{cose-bilkent-S5V4N54A-ccY03BRh.js → cose-bilkent-S5V4N54A-8sFxzH_F.js} +1 -1
- package/dist-web/assets/{dagre-BM42HDAG-BYLmCViB.js → dagre-BM42HDAG-CXKxHlld.js} +1 -1
- package/dist-web/assets/{diagram-2AECGRRQ-DTvenvXR.js → diagram-2AECGRRQ-DtcDQjmq.js} +1 -1
- package/dist-web/assets/{diagram-5GNKFQAL-CCzsYDmr.js → diagram-5GNKFQAL-C5z5tfjo.js} +1 -1
- package/dist-web/assets/{diagram-KO2AKTUF-QSff7J_V.js → diagram-KO2AKTUF-DzGoK3-W.js} +1 -1
- package/dist-web/assets/{diagram-LMA3HP47-CVqlEmu2.js → diagram-LMA3HP47-CClXYqlA.js} +1 -1
- package/dist-web/assets/{diagram-OG6HWLK6-dBVz-I46.js → diagram-OG6HWLK6-CCOd6tb5.js} +1 -1
- package/dist-web/assets/{erDiagram-TEJ5UH35-B_y4ftNu.js → erDiagram-TEJ5UH35-DyUNZPGi.js} +1 -1
- package/dist-web/assets/{flowDiagram-I6XJVG4X-M410hT_n.js → flowDiagram-I6XJVG4X-DWE9txcF.js} +1 -1
- package/dist-web/assets/{ganttDiagram-6RSMTGT7-qiri2OJa.js → ganttDiagram-6RSMTGT7-B-OtEqRy.js} +1 -1
- package/dist-web/assets/{gitGraphDiagram-PVQCEYII-FqGGBobG.js → gitGraphDiagram-PVQCEYII-F9vafo91.js} +1 -1
- package/dist-web/assets/{index-BaFSLlgl.js → index-CwMlRsHB.js} +1 -1
- package/dist-web/assets/{index-DrUIu0u6.js → index-D_5U356C.js} +4 -4
- package/dist-web/assets/{index-1SV04K_c.js → index-DahCY-9n.js} +1 -1
- package/dist-web/assets/{infoDiagram-5YYISTIA-CczHqRr1.js → infoDiagram-5YYISTIA-BqiJJ4mQ.js} +1 -1
- package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-ty1DRy6n.js → ishikawaDiagram-YF4QCWOH-BJhigZjk.js} +1 -1
- package/dist-web/assets/{journeyDiagram-JHISSGLW-D_JYvt6i.js → journeyDiagram-JHISSGLW-DbnfMDvR.js} +1 -1
- package/dist-web/assets/{kanban-definition-UN3LZRKU-CT67nUTK.js → kanban-definition-UN3LZRKU-CWbRbJ6f.js} +1 -1
- package/dist-web/assets/{linear-B1HaE_t1.js → linear-D3Xq7OUM.js} +1 -1
- package/dist-web/assets/{mermaid.core-Dumx_iKV.js → mermaid.core-CT0YFN3s.js} +4 -4
- package/dist-web/assets/{mindmap-definition-RKZ34NQL-CVulJo63.js → mindmap-definition-RKZ34NQL-D6AZLTGR.js} +1 -1
- package/dist-web/assets/{pieDiagram-4H26LBE5-C1yD5ntZ.js → pieDiagram-4H26LBE5-NGxhfGd1.js} +1 -1
- package/dist-web/assets/{quadrantDiagram-W4KKPZXB-B7PoiM8c.js → quadrantDiagram-W4KKPZXB-jNVzj-DZ.js} +1 -1
- package/dist-web/assets/{requirementDiagram-4Y6WPE33-COvHb3Mv.js → requirementDiagram-4Y6WPE33-cxYkgHCv.js} +1 -1
- package/dist-web/assets/{sankeyDiagram-5OEKKPKP-CAnwm5-J.js → sankeyDiagram-5OEKKPKP-CO7LMTUX.js} +1 -1
- package/dist-web/assets/{sequenceDiagram-3UESZ5HK-C2KFLIUq.js → sequenceDiagram-3UESZ5HK-C8d8VIsZ.js} +1 -1
- package/dist-web/assets/{stateDiagram-AJRCARHV-CqmhS5P6.js → stateDiagram-AJRCARHV-DVxepHih.js} +1 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-OpTLx_eY.js +1 -0
- package/dist-web/assets/{timeline-definition-PNZ67QCA-DvPre9M_.js → timeline-definition-PNZ67QCA-Bef04SiL.js} +1 -1
- package/dist-web/assets/{vennDiagram-CIIHVFJN-Top6i7KH.js → vennDiagram-CIIHVFJN-DlZHmyp0.js} +1 -1
- package/dist-web/assets/{wardley-L42UT6IY-_jVLsWqf.js → wardley-L42UT6IY-ChkIPtT_.js} +1 -1
- package/dist-web/assets/{wardleyDiagram-YWT4CUSO-BV4e5mP6.js → wardleyDiagram-YWT4CUSO-D67J0WGX.js} +1 -1
- package/dist-web/assets/{xychartDiagram-2RQKCTM6-Bn1hw4Jk.js → xychartDiagram-2RQKCTM6-BoNIIDDe.js} +1 -1
- package/dist-web/index.html +1 -1
- package/package.json +1 -1
- package/templates/harness/skills/st-code-review/scripts/code-review.cjs +2710 -264
- package/templates/harness/skills/st-execute-blueprint/scripts/dispatch-task-execution.cjs +420 -213
- package/templates/harness/skills/st-execute-task/scripts/dispatch-task-execution.cjs +420 -213
- package/templates/harness/skills/st-full-workflow/scripts/dispatch-task-execution.cjs +420 -213
- package/templates/strikethroo/config/config.yaml +95 -6
- package/templates/strikethroo/gitignore +13 -10
- package/dist-web/assets/channel-CmU4mBgT.js +0 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK-D_FMKQsB.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-D_FMKQsB.js +0 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-C3Kw8ZDR.js +0 -1
|
@@ -3342,8 +3342,8 @@ var require_excerpt = __commonJS({
|
|
|
3342
3342
|
if (sep2 == null && (opts.excerpt === false || opts.excerpt == null)) {
|
|
3343
3343
|
return file;
|
|
3344
3344
|
}
|
|
3345
|
-
const
|
|
3346
|
-
const idx = file.content.indexOf(
|
|
3345
|
+
const delimiter3 = typeof opts.excerpt === "string" ? opts.excerpt : sep2 || opts.delimiters[0];
|
|
3346
|
+
const idx = file.content.indexOf(delimiter3);
|
|
3347
3347
|
if (idx !== -1) {
|
|
3348
3348
|
file.excerpt = file.content.slice(0, idx);
|
|
3349
3349
|
}
|
|
@@ -3407,7 +3407,7 @@ var require_parse = __commonJS({
|
|
|
3407
3407
|
var require_gray_matter = __commonJS({
|
|
3408
3408
|
"node_modules/gray-matter/index.js"(exports2, module2) {
|
|
3409
3409
|
"use strict";
|
|
3410
|
-
var
|
|
3410
|
+
var fs6 = require("fs");
|
|
3411
3411
|
var sections = require_section_matter();
|
|
3412
3412
|
var defaults = require_defaults();
|
|
3413
3413
|
var stringify = require_stringify();
|
|
@@ -3491,7 +3491,7 @@ var require_gray_matter = __commonJS({
|
|
|
3491
3491
|
return stringify(file, data, options2);
|
|
3492
3492
|
};
|
|
3493
3493
|
matter2.read = function(filepath, options2) {
|
|
3494
|
-
const str2 =
|
|
3494
|
+
const str2 = fs6.readFileSync(filepath, "utf8");
|
|
3495
3495
|
const file = matter2(str2, options2);
|
|
3496
3496
|
file.path = filepath;
|
|
3497
3497
|
return file;
|
|
@@ -3525,8 +3525,8 @@ __export(dispatch_task_execution_exports, {
|
|
|
3525
3525
|
resolveDispatchRoute: () => resolveDispatchRoute
|
|
3526
3526
|
});
|
|
3527
3527
|
module.exports = __toCommonJS(dispatch_task_execution_exports);
|
|
3528
|
-
var
|
|
3529
|
-
var
|
|
3528
|
+
var fs5 = __toESM(require("fs"));
|
|
3529
|
+
var path6 = __toESM(require("path"));
|
|
3530
3530
|
var import_gray_matter = __toESM(require_gray_matter());
|
|
3531
3531
|
|
|
3532
3532
|
// src/types.ts
|
|
@@ -3664,6 +3664,7 @@ var EXTERNAL_HARNESS_ADAPTERS = {
|
|
|
3664
3664
|
"claude",
|
|
3665
3665
|
[
|
|
3666
3666
|
"-p",
|
|
3667
|
+
...request.cliArgs,
|
|
3667
3668
|
...modelArgv(request.model),
|
|
3668
3669
|
...request.reasoningEffort === void 0 ? [] : ["--effort", request.reasoningEffort]
|
|
3669
3670
|
],
|
|
@@ -3677,6 +3678,7 @@ var EXTERNAL_HARNESS_ADAPTERS = {
|
|
|
3677
3678
|
"codex",
|
|
3678
3679
|
[
|
|
3679
3680
|
"exec",
|
|
3681
|
+
...request.cliArgs,
|
|
3680
3682
|
...modelArgv(request.model),
|
|
3681
3683
|
...request.reasoningEffort === void 0 ? [] : ["--config", `model_reasoning_effort=${request.reasoningEffort}`],
|
|
3682
3684
|
"-"
|
|
@@ -3687,19 +3689,23 @@ var EXTERNAL_HARNESS_ADAPTERS = {
|
|
|
3687
3689
|
},
|
|
3688
3690
|
cursor: {
|
|
3689
3691
|
executable: "cursor-agent",
|
|
3690
|
-
buildCommand: (request) => command(
|
|
3692
|
+
buildCommand: (request) => command(
|
|
3693
|
+
"cursor-agent",
|
|
3694
|
+
["--print", ...request.cliArgs, ...modelArgv(request.model)],
|
|
3695
|
+
request
|
|
3696
|
+
),
|
|
3691
3697
|
authenticationArgv: () => ["status"]
|
|
3692
3698
|
},
|
|
3693
3699
|
gemini: {
|
|
3694
3700
|
executable: "gemini",
|
|
3695
3701
|
// The empty positional prompt is the existing contract — content travels on
|
|
3696
3702
|
// stdin. It stays even when the model pair is dropped.
|
|
3697
|
-
buildCommand: (request) => command("gemini", ["--prompt", "", ...modelArgv(request.model)], request),
|
|
3703
|
+
buildCommand: (request) => command("gemini", ["--prompt", "", ...request.cliArgs, ...modelArgv(request.model)], request),
|
|
3698
3704
|
authenticationArgv: () => ["auth", "status"]
|
|
3699
3705
|
},
|
|
3700
3706
|
copilot: {
|
|
3701
3707
|
executable: "copilot",
|
|
3702
|
-
buildCommand: (request) => command("copilot", ["-p", "", ...modelArgv(request.model)], request),
|
|
3708
|
+
buildCommand: (request) => command("copilot", ["-p", "", ...request.cliArgs, ...modelArgv(request.model)], request),
|
|
3703
3709
|
authenticationArgv: () => ["auth", "status"]
|
|
3704
3710
|
},
|
|
3705
3711
|
opencode: {
|
|
@@ -3708,6 +3714,7 @@ var EXTERNAL_HARNESS_ADAPTERS = {
|
|
|
3708
3714
|
"opencode",
|
|
3709
3715
|
[
|
|
3710
3716
|
"run",
|
|
3717
|
+
...request.cliArgs,
|
|
3711
3718
|
...modelArgv(request.model),
|
|
3712
3719
|
...request.reasoningEffort === void 0 ? [] : ["--variant", request.reasoningEffort],
|
|
3713
3720
|
"-"
|
|
@@ -3723,27 +3730,30 @@ if (adapterKeys.join("\0") !== harnessKeys.join("\0")) {
|
|
|
3723
3730
|
throw new Error("External harness adapter registry does not cover SUPPORTED_HARNESSES exactly.");
|
|
3724
3731
|
}
|
|
3725
3732
|
var taskCommandRequest = (request) => ({
|
|
3733
|
+
cliArgs: request.cliArgs ?? [],
|
|
3726
3734
|
model: request.model,
|
|
3727
3735
|
reasoningEffort: request.reasoningEffort,
|
|
3728
3736
|
workspace: request.workspace,
|
|
3729
3737
|
prompt: taskPrompt(request)
|
|
3730
3738
|
});
|
|
3731
|
-
var executableOnPath = (executable) => (process.env.PATH ?? "").split(path2.delimiter).some(
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3739
|
+
var executableOnPath = (executable) => (/[\\/]/.test(executable) ? [""] : (process.env.PATH ?? "").split(path2.delimiter)).some(
|
|
3740
|
+
(directory) => {
|
|
3741
|
+
if (!directory && !/[\\/]/.test(executable)) return false;
|
|
3742
|
+
const candidate = directory === "" ? executable : path2.join(directory, executable);
|
|
3743
|
+
try {
|
|
3744
|
+
return fs.statSync(candidate).isFile();
|
|
3745
|
+
} catch {
|
|
3746
|
+
return false;
|
|
3747
|
+
}
|
|
3738
3748
|
}
|
|
3739
|
-
|
|
3749
|
+
);
|
|
3740
3750
|
var CAPTURED_STDOUT_LIMIT = 262144;
|
|
3741
3751
|
var STDIO_SLOTS = {
|
|
3742
3752
|
ignore: { stdout: "ignore" },
|
|
3743
3753
|
inherit: { stdout: "inherit" },
|
|
3744
3754
|
capture: { stdout: "pipe" }
|
|
3745
3755
|
};
|
|
3746
|
-
var runProcess = (executable, argv, cwd, stdin, outputMode = "ignore") => new Promise((
|
|
3756
|
+
var runProcess = (executable, argv, cwd, stdin, outputMode = "ignore") => new Promise((resolve4, reject) => {
|
|
3747
3757
|
let settled = false;
|
|
3748
3758
|
const fail = (error) => {
|
|
3749
3759
|
if (settled) return;
|
|
@@ -3775,7 +3785,7 @@ var runProcess = (executable, argv, cwd, stdin, outputMode = "ignore") => new Pr
|
|
|
3775
3785
|
child.once("close", (code) => {
|
|
3776
3786
|
if (settled) return;
|
|
3777
3787
|
settled = true;
|
|
3778
|
-
|
|
3788
|
+
resolve4({
|
|
3779
3789
|
exitCode: code ?? 1,
|
|
3780
3790
|
...outputMode === "capture" ? { stdout: captured } : {}
|
|
3781
3791
|
});
|
|
@@ -3826,11 +3836,12 @@ var prepareLaunch = async (harness, input, active, guard) => {
|
|
|
3826
3836
|
}
|
|
3827
3837
|
const blocked = guard?.();
|
|
3828
3838
|
if (blocked) return blocked;
|
|
3829
|
-
|
|
3839
|
+
const executable = adapter.executable;
|
|
3840
|
+
if (!active.executableExists(executable)) {
|
|
3830
3841
|
return {
|
|
3831
3842
|
kind: "fallback",
|
|
3832
3843
|
reason: "executable-unavailable",
|
|
3833
|
-
detail: `${
|
|
3844
|
+
detail: `${executable} is unavailable.`
|
|
3834
3845
|
};
|
|
3835
3846
|
}
|
|
3836
3847
|
const commandSpec = adapter.buildCommand(input);
|
|
@@ -3874,191 +3885,14 @@ var dispatchExternalTask = async (request, overrides = {}) => {
|
|
|
3874
3885
|
};
|
|
3875
3886
|
|
|
3876
3887
|
// src/skill-scripts/shared/harness-availability.ts
|
|
3877
|
-
var
|
|
3878
|
-
var path3 = __toESM(require("path"));
|
|
3888
|
+
var import_crypto2 = require("crypto");
|
|
3879
3889
|
var import_child_process3 = require("child_process");
|
|
3880
|
-
var
|
|
3881
|
-
var
|
|
3882
|
-
var
|
|
3883
|
-
var PROBE_TIMEOUT_MS = 2e4;
|
|
3884
|
-
var AVAILABILITY_CACHE_RELATIVE_PATH = path3.join("runtime", "harness-availability.json");
|
|
3885
|
-
var PROBE_PROMPT = "Reply with OK.";
|
|
3886
|
-
var probeCommand = (executable, argv, cwd, stdin = PROBE_PROMPT) => ({ executable, argv, cwd, stdin });
|
|
3887
|
-
var HARNESS_AVAILABILITY_REGISTRY = {
|
|
3888
|
-
claude: {
|
|
3889
|
-
version: AVAILABILITY_REGISTRY_VERSION,
|
|
3890
|
-
executable: "claude",
|
|
3891
|
-
buildCommand: (cwd) => probeCommand("claude", ["-p"], cwd)
|
|
3892
|
-
},
|
|
3893
|
-
codex: {
|
|
3894
|
-
version: AVAILABILITY_REGISTRY_VERSION,
|
|
3895
|
-
executable: "codex",
|
|
3896
|
-
buildCommand: (cwd) => probeCommand("codex", ["exec", "-"], cwd)
|
|
3897
|
-
},
|
|
3898
|
-
cursor: {
|
|
3899
|
-
version: AVAILABILITY_REGISTRY_VERSION,
|
|
3900
|
-
executable: "cursor-agent",
|
|
3901
|
-
buildCommand: (cwd) => probeCommand("cursor-agent", ["--print"], cwd)
|
|
3902
|
-
},
|
|
3903
|
-
gemini: {
|
|
3904
|
-
version: AVAILABILITY_REGISTRY_VERSION,
|
|
3905
|
-
executable: "gemini",
|
|
3906
|
-
buildCommand: (cwd) => probeCommand("gemini", ["--prompt", PROBE_PROMPT], cwd, "")
|
|
3907
|
-
},
|
|
3908
|
-
copilot: {
|
|
3909
|
-
version: AVAILABILITY_REGISTRY_VERSION,
|
|
3910
|
-
executable: "copilot",
|
|
3911
|
-
buildCommand: (cwd) => probeCommand("copilot", ["-p", PROBE_PROMPT], cwd, "")
|
|
3912
|
-
},
|
|
3913
|
-
opencode: {
|
|
3914
|
-
version: AVAILABILITY_REGISTRY_VERSION,
|
|
3915
|
-
executable: "opencode",
|
|
3916
|
-
buildCommand: (cwd) => probeCommand("opencode", ["run", "-"], cwd)
|
|
3917
|
-
}
|
|
3918
|
-
};
|
|
3919
|
-
var registryKeys = Object.keys(HARNESS_AVAILABILITY_REGISTRY).sort();
|
|
3920
|
-
var harnessKeys2 = [...SUPPORTED_HARNESSES].sort();
|
|
3921
|
-
if (registryKeys.join("\0") !== harnessKeys2.join("\0")) {
|
|
3922
|
-
throw new Error("Harness availability registry does not cover SUPPORTED_HARNESSES exactly.");
|
|
3923
|
-
}
|
|
3924
|
-
for (const harness of SUPPORTED_HARNESSES) {
|
|
3925
|
-
const availability = HARNESS_AVAILABILITY_REGISTRY[harness];
|
|
3926
|
-
if (availability.executable !== EXTERNAL_HARNESS_ADAPTERS[harness].executable) {
|
|
3927
|
-
throw new Error(`Harness availability executable disagrees with the ${harness} adapter.`);
|
|
3928
|
-
}
|
|
3929
|
-
}
|
|
3930
|
-
var safeReason = (value, fallback) => {
|
|
3931
|
-
if (typeof value !== "string") return fallback;
|
|
3932
|
-
const firstLine = value.replace(/[\r\n]+/g, " ").trim().slice(0, 200);
|
|
3933
|
-
return firstLine || fallback;
|
|
3934
|
-
};
|
|
3935
|
-
var isOutcome = (value) => {
|
|
3936
|
-
if (!value || typeof value !== "object") return false;
|
|
3937
|
-
const entry = value;
|
|
3938
|
-
return typeof entry.available === "boolean" && typeof entry.observedAt === "number" && Number.isFinite(entry.observedAt) && typeof entry.expiresAt === "number" && Number.isFinite(entry.expiresAt) && typeof entry.reason === "string";
|
|
3939
|
-
};
|
|
3940
|
-
var readCache = (cachePath) => {
|
|
3941
|
-
try {
|
|
3942
|
-
const parsed = JSON.parse(fs2.readFileSync(cachePath, "utf8"));
|
|
3943
|
-
if (!parsed || typeof parsed !== "object") throw new Error("invalid cache");
|
|
3944
|
-
const record = parsed;
|
|
3945
|
-
if (record.version !== 1 || !record.harnesses || typeof record.harnesses !== "object") {
|
|
3946
|
-
throw new Error("invalid cache");
|
|
3947
|
-
}
|
|
3948
|
-
const harnesses = {};
|
|
3949
|
-
for (const harness of SUPPORTED_HARNESSES) {
|
|
3950
|
-
const candidate = record.harnesses[harness];
|
|
3951
|
-
if (isOutcome(candidate)) harnesses[harness] = candidate;
|
|
3952
|
-
}
|
|
3953
|
-
return { version: 1, harnesses };
|
|
3954
|
-
} catch {
|
|
3955
|
-
return { version: 1, harnesses: {} };
|
|
3956
|
-
}
|
|
3957
|
-
};
|
|
3958
|
-
var writeCache = (cachePath, harness, outcome) => {
|
|
3959
|
-
fs2.mkdirSync(path3.dirname(cachePath), { recursive: true });
|
|
3960
|
-
const cache = readCache(cachePath);
|
|
3961
|
-
const existing = cache.harnesses[harness];
|
|
3962
|
-
if (!existing || existing.observedAt <= outcome.observedAt) {
|
|
3963
|
-
cache.harnesses[harness] = {
|
|
3964
|
-
available: outcome.available,
|
|
3965
|
-
observedAt: outcome.observedAt,
|
|
3966
|
-
expiresAt: outcome.expiresAt,
|
|
3967
|
-
reason: outcome.reason
|
|
3968
|
-
};
|
|
3969
|
-
}
|
|
3970
|
-
const temporary = `${cachePath}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
3971
|
-
try {
|
|
3972
|
-
fs2.writeFileSync(temporary, `${JSON.stringify(cache, null, 2)}
|
|
3973
|
-
`, { mode: 384 });
|
|
3974
|
-
fs2.renameSync(temporary, cachePath);
|
|
3975
|
-
} finally {
|
|
3976
|
-
try {
|
|
3977
|
-
fs2.unlinkSync(temporary);
|
|
3978
|
-
} catch {
|
|
3979
|
-
}
|
|
3980
|
-
}
|
|
3981
|
-
};
|
|
3982
|
-
var runProbe = (command2, timeoutMs) => new Promise((resolve3) => {
|
|
3983
|
-
let settled = false;
|
|
3984
|
-
let diagnostics = "";
|
|
3985
|
-
const finish = (result) => {
|
|
3986
|
-
if (settled) return;
|
|
3987
|
-
settled = true;
|
|
3988
|
-
resolve3(result);
|
|
3989
|
-
};
|
|
3990
|
-
const child = (0, import_child_process3.spawn)(command2.executable, command2.argv, {
|
|
3991
|
-
cwd: command2.cwd,
|
|
3992
|
-
shell: false,
|
|
3993
|
-
stdio: ["pipe", "ignore", "pipe"]
|
|
3994
|
-
});
|
|
3995
|
-
const timer = setTimeout(() => {
|
|
3996
|
-
child.kill("SIGKILL");
|
|
3997
|
-
finish({ exitCode: 1, timedOut: true, detail: "Probe timed out." });
|
|
3998
|
-
}, timeoutMs);
|
|
3999
|
-
child.stderr?.on("data", (chunk) => {
|
|
4000
|
-
if (diagnostics.length < 400) diagnostics += String(chunk).slice(0, 400 - diagnostics.length);
|
|
4001
|
-
});
|
|
4002
|
-
child.once("error", (error) => {
|
|
4003
|
-
clearTimeout(timer);
|
|
4004
|
-
finish({ exitCode: 1, detail: error.message });
|
|
4005
|
-
});
|
|
4006
|
-
child.once("close", (code) => {
|
|
4007
|
-
clearTimeout(timer);
|
|
4008
|
-
finish({ exitCode: code ?? 1, detail: diagnostics });
|
|
4009
|
-
});
|
|
4010
|
-
child.stdin?.on("error", () => void 0);
|
|
4011
|
-
child.stdin?.end(command2.stdin);
|
|
4012
|
-
});
|
|
4013
|
-
var defaultDependencies = {
|
|
4014
|
-
now: Date.now,
|
|
4015
|
-
runProbe
|
|
4016
|
-
};
|
|
4017
|
-
var checkHarnessAvailability = async (request, overrides = {}) => {
|
|
4018
|
-
const active = { ...defaultDependencies, ...overrides };
|
|
4019
|
-
const now = active.now();
|
|
4020
|
-
if (request.harness === void 0 || request.harness === request.currentHarness) {
|
|
4021
|
-
return {
|
|
4022
|
-
harness: request.harness ?? request.currentHarness,
|
|
4023
|
-
available: true,
|
|
4024
|
-
observedAt: now,
|
|
4025
|
-
expiresAt: now,
|
|
4026
|
-
reason: "Native/current harness targets do not require a probe.",
|
|
4027
|
-
source: "bypass"
|
|
4028
|
-
};
|
|
4029
|
-
}
|
|
4030
|
-
const harness = request.harness;
|
|
4031
|
-
const cachePath = path3.join(request.strikethrooRoot, AVAILABILITY_CACHE_RELATIVE_PATH);
|
|
4032
|
-
const cached = readCache(cachePath).harnesses[harness];
|
|
4033
|
-
if (cached && cached.expiresAt > now) return { harness, ...cached, source: "cache" };
|
|
4034
|
-
const definition = HARNESS_AVAILABILITY_REGISTRY[harness];
|
|
4035
|
-
let probe;
|
|
4036
|
-
try {
|
|
4037
|
-
probe = await active.runProbe(definition.buildCommand(request.workspace), PROBE_TIMEOUT_MS);
|
|
4038
|
-
} catch (error) {
|
|
4039
|
-
probe = { exitCode: 1, detail: error instanceof Error ? error.message : String(error) };
|
|
4040
|
-
}
|
|
4041
|
-
const available = probe.exitCode === 0 && !probe.timedOut;
|
|
4042
|
-
const reason = available ? "Harness probe succeeded." : safeReason(
|
|
4043
|
-
probe.detail,
|
|
4044
|
-
probe.timedOut ? "Harness probe timed out." : "Harness probe failed."
|
|
4045
|
-
);
|
|
4046
|
-
const outcome = {
|
|
4047
|
-
harness,
|
|
4048
|
-
available,
|
|
4049
|
-
observedAt: now,
|
|
4050
|
-
expiresAt: now + (available ? AVAILABLE_TTL_MS : UNAVAILABLE_TTL_MS),
|
|
4051
|
-
reason,
|
|
4052
|
-
source: "probe"
|
|
4053
|
-
};
|
|
4054
|
-
try {
|
|
4055
|
-
writeCache(cachePath, harness, outcome);
|
|
4056
|
-
} catch {
|
|
4057
|
-
}
|
|
4058
|
-
return outcome;
|
|
4059
|
-
};
|
|
3890
|
+
var fs4 = __toESM(require("fs"));
|
|
3891
|
+
var os = __toESM(require("os"));
|
|
3892
|
+
var path5 = __toESM(require("path"));
|
|
4060
3893
|
|
|
4061
|
-
// src/skill-scripts/shared/
|
|
3894
|
+
// src/skill-scripts/shared/harness-configuration.ts
|
|
3895
|
+
var import_crypto = require("crypto");
|
|
4062
3896
|
var fs3 = __toESM(require("fs"));
|
|
4063
3897
|
var path4 = __toESM(require("path"));
|
|
4064
3898
|
|
|
@@ -6285,7 +6119,9 @@ var DEFAULT_DUMP_OPTIONS = {
|
|
|
6285
6119
|
};
|
|
6286
6120
|
|
|
6287
6121
|
// src/skill-scripts/shared/execution-routing.ts
|
|
6288
|
-
var
|
|
6122
|
+
var fs2 = __toESM(require("fs"));
|
|
6123
|
+
var path3 = __toESM(require("path"));
|
|
6124
|
+
var WORKSPACE_CONFIG_RELPATH = path3.join("config", "config.yaml");
|
|
6289
6125
|
var EXECUTION_ROUTING_SECTION = "execution_routing";
|
|
6290
6126
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6291
6127
|
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
@@ -6360,10 +6196,10 @@ var validateProfile = (name, raw, supportedHarnesses, errors) => {
|
|
|
6360
6196
|
return { name, description: raw.description.trim(), targets };
|
|
6361
6197
|
};
|
|
6362
6198
|
var loadRoutingConfig = (strikethrooRoot, supportedHarnesses) => {
|
|
6363
|
-
const configPath =
|
|
6199
|
+
const configPath = path3.join(strikethrooRoot, WORKSPACE_CONFIG_RELPATH);
|
|
6364
6200
|
let contents;
|
|
6365
6201
|
try {
|
|
6366
|
-
contents =
|
|
6202
|
+
contents = fs2.readFileSync(configPath, "utf8");
|
|
6367
6203
|
} catch {
|
|
6368
6204
|
return { kind: "no-config" };
|
|
6369
6205
|
}
|
|
@@ -6430,6 +6266,349 @@ var loadRoutingConfig = (strikethrooRoot, supportedHarnesses) => {
|
|
|
6430
6266
|
return { kind: "config", config };
|
|
6431
6267
|
};
|
|
6432
6268
|
|
|
6269
|
+
// src/skill-scripts/shared/harness-configuration.ts
|
|
6270
|
+
var HARNESS_CONFIGURATION_SECTION = "harnesses";
|
|
6271
|
+
var HARNESS_CONFIGURATION_NORMALIZATION_VERSION = 1;
|
|
6272
|
+
var isPlainObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6273
|
+
var hashHarnessCliArgs = (harness, cliArgs, normalizationVersion = HARNESS_CONFIGURATION_NORMALIZATION_VERSION) => (0, import_crypto.createHash)("sha256").update(
|
|
6274
|
+
JSON.stringify({
|
|
6275
|
+
schema: normalizationVersion,
|
|
6276
|
+
harness,
|
|
6277
|
+
cliArgs
|
|
6278
|
+
}),
|
|
6279
|
+
"utf8"
|
|
6280
|
+
).digest("hex");
|
|
6281
|
+
var normalizeInvocation = (harness, cliArgs) => {
|
|
6282
|
+
const immutableArgs = Object.freeze([...cliArgs]);
|
|
6283
|
+
return Object.freeze({
|
|
6284
|
+
cliArgs: immutableArgs,
|
|
6285
|
+
cliArgsHash: hashHarnessCliArgs(harness, immutableArgs)
|
|
6286
|
+
});
|
|
6287
|
+
};
|
|
6288
|
+
var emptyConfiguration = () => Object.freeze(
|
|
6289
|
+
Object.fromEntries(
|
|
6290
|
+
SUPPORTED_HARNESSES.map((harness) => [harness, normalizeInvocation(harness, [])])
|
|
6291
|
+
)
|
|
6292
|
+
);
|
|
6293
|
+
var validateHarnessEntry = (harness, raw, errors) => {
|
|
6294
|
+
const entryPath = `config.yaml ${HARNESS_CONFIGURATION_SECTION}.${harness}`;
|
|
6295
|
+
if (!isPlainObject3(raw)) {
|
|
6296
|
+
errors.push(`${entryPath} must be a mapping.`);
|
|
6297
|
+
return null;
|
|
6298
|
+
}
|
|
6299
|
+
for (const key of Object.keys(raw)) {
|
|
6300
|
+
if (key !== "cli_args") errors.push(`${entryPath}.${key} is not supported.`);
|
|
6301
|
+
}
|
|
6302
|
+
if (!("cli_args" in raw)) return normalizeInvocation(harness, []);
|
|
6303
|
+
if (!Array.isArray(raw.cli_args)) {
|
|
6304
|
+
errors.push(`${entryPath}.cli_args must be an array of exact strings.`);
|
|
6305
|
+
return null;
|
|
6306
|
+
}
|
|
6307
|
+
const cliArgs = [];
|
|
6308
|
+
raw.cli_args.forEach((value, index) => {
|
|
6309
|
+
const valuePath = `${entryPath}.cli_args[${index}]`;
|
|
6310
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
6311
|
+
errors.push(`${valuePath} must be a non-empty string.`);
|
|
6312
|
+
return;
|
|
6313
|
+
}
|
|
6314
|
+
if (value.includes("\0")) {
|
|
6315
|
+
errors.push(`${valuePath} must not contain a NUL character.`);
|
|
6316
|
+
return;
|
|
6317
|
+
}
|
|
6318
|
+
cliArgs.push(value);
|
|
6319
|
+
});
|
|
6320
|
+
return normalizeInvocation(harness, cliArgs);
|
|
6321
|
+
};
|
|
6322
|
+
var loadHarnessConfiguration = (strikethrooRoot) => {
|
|
6323
|
+
const configPath = path4.join(strikethrooRoot, WORKSPACE_CONFIG_RELPATH);
|
|
6324
|
+
let contents;
|
|
6325
|
+
try {
|
|
6326
|
+
contents = fs3.readFileSync(configPath, "utf8");
|
|
6327
|
+
} catch (error) {
|
|
6328
|
+
if (error.code === "ENOENT") {
|
|
6329
|
+
return { kind: "config", config: emptyConfiguration() };
|
|
6330
|
+
}
|
|
6331
|
+
return {
|
|
6332
|
+
kind: "invalid",
|
|
6333
|
+
errors: [
|
|
6334
|
+
`config.yaml could not be read: ${error instanceof Error ? error.message : String(error)}`
|
|
6335
|
+
]
|
|
6336
|
+
};
|
|
6337
|
+
}
|
|
6338
|
+
let document;
|
|
6339
|
+
try {
|
|
6340
|
+
document = load(contents);
|
|
6341
|
+
} catch (error) {
|
|
6342
|
+
return {
|
|
6343
|
+
kind: "invalid",
|
|
6344
|
+
errors: [
|
|
6345
|
+
`config.yaml is not valid YAML: ${error instanceof Error ? error.message : String(error)}`
|
|
6346
|
+
]
|
|
6347
|
+
};
|
|
6348
|
+
}
|
|
6349
|
+
if (document === null || document === void 0) {
|
|
6350
|
+
return { kind: "config", config: emptyConfiguration() };
|
|
6351
|
+
}
|
|
6352
|
+
if (!isPlainObject3(document)) {
|
|
6353
|
+
return { kind: "invalid", errors: ["config.yaml must be a YAML mapping."] };
|
|
6354
|
+
}
|
|
6355
|
+
const section = document[HARNESS_CONFIGURATION_SECTION];
|
|
6356
|
+
if (section === null || section === void 0) {
|
|
6357
|
+
return { kind: "config", config: emptyConfiguration() };
|
|
6358
|
+
}
|
|
6359
|
+
if (!isPlainObject3(section)) {
|
|
6360
|
+
return {
|
|
6361
|
+
kind: "invalid",
|
|
6362
|
+
errors: [`config.yaml ${HARNESS_CONFIGURATION_SECTION} must be a YAML mapping.`]
|
|
6363
|
+
};
|
|
6364
|
+
}
|
|
6365
|
+
const errors = [];
|
|
6366
|
+
const supportedHarnesses = new Set(SUPPORTED_HARNESSES);
|
|
6367
|
+
for (const harness of Object.keys(section)) {
|
|
6368
|
+
if (!supportedHarnesses.has(harness)) {
|
|
6369
|
+
errors.push(`config.yaml ${HARNESS_CONFIGURATION_SECTION}.${harness} is not supported.`);
|
|
6370
|
+
}
|
|
6371
|
+
}
|
|
6372
|
+
const entries = {};
|
|
6373
|
+
for (const harness of SUPPORTED_HARNESSES) {
|
|
6374
|
+
if (!(harness in section)) {
|
|
6375
|
+
entries[harness] = normalizeInvocation(harness, []);
|
|
6376
|
+
continue;
|
|
6377
|
+
}
|
|
6378
|
+
const entry = validateHarnessEntry(harness, section[harness], errors);
|
|
6379
|
+
if (entry) entries[harness] = entry;
|
|
6380
|
+
}
|
|
6381
|
+
if (errors.length > 0) return { kind: "invalid", errors };
|
|
6382
|
+
return { kind: "config", config: Object.freeze(entries) };
|
|
6383
|
+
};
|
|
6384
|
+
|
|
6385
|
+
// src/skill-scripts/shared/harness-availability.ts
|
|
6386
|
+
var AVAILABILITY_REGISTRY_VERSION = 3;
|
|
6387
|
+
var AVAILABLE_TTL_MS = 30 * 60 * 1e3;
|
|
6388
|
+
var UNAVAILABLE_TTL_MS = 5 * 60 * 1e3;
|
|
6389
|
+
var PROBE_TIMEOUT_MS = 2e4;
|
|
6390
|
+
var AVAILABILITY_CACHE_RELATIVE_PATH = path5.join("runtime", "harness-availability.json");
|
|
6391
|
+
var CACHE_VERSION = 2;
|
|
6392
|
+
var availabilityDefinition = (harness) => {
|
|
6393
|
+
const adapter = EXTERNAL_HARNESS_ADAPTERS[harness];
|
|
6394
|
+
return {
|
|
6395
|
+
executable: adapter.executable,
|
|
6396
|
+
buildCommand: (cwd, cliArgs, prompt) => adapter.buildCommand({ cliArgs, workspace: cwd, prompt })
|
|
6397
|
+
};
|
|
6398
|
+
};
|
|
6399
|
+
var HARNESS_AVAILABILITY_REGISTRY = Object.freeze(
|
|
6400
|
+
Object.fromEntries(
|
|
6401
|
+
SUPPORTED_HARNESSES.map((harness) => [harness, availabilityDefinition(harness)])
|
|
6402
|
+
)
|
|
6403
|
+
);
|
|
6404
|
+
var resolveExecutable = (executable) => {
|
|
6405
|
+
const extensions = process.platform === "win32" ? ["", ...(process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";")] : [""];
|
|
6406
|
+
const directories = /[\\/]/.test(executable) ? [""] : (process.env.PATH ?? "").split(path5.delimiter).filter(Boolean);
|
|
6407
|
+
for (const directory of directories) {
|
|
6408
|
+
for (const extension of extensions) {
|
|
6409
|
+
const candidate = path5.resolve(directory, `${executable}${extension}`);
|
|
6410
|
+
try {
|
|
6411
|
+
fs4.accessSync(
|
|
6412
|
+
candidate,
|
|
6413
|
+
process.platform === "win32" ? fs4.constants.F_OK : fs4.constants.X_OK
|
|
6414
|
+
);
|
|
6415
|
+
if (fs4.statSync(candidate).isFile()) return fs4.realpathSync(candidate);
|
|
6416
|
+
} catch {
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
return void 0;
|
|
6421
|
+
};
|
|
6422
|
+
var runProbe = (command2, timeoutMs) => new Promise((resolve4) => {
|
|
6423
|
+
let settled = false;
|
|
6424
|
+
let timedOut = false;
|
|
6425
|
+
const finish = (result) => {
|
|
6426
|
+
if (settled) return;
|
|
6427
|
+
settled = true;
|
|
6428
|
+
resolve4(result);
|
|
6429
|
+
};
|
|
6430
|
+
const child = (0, import_child_process3.spawn)(command2.executable, command2.argv, {
|
|
6431
|
+
cwd: command2.cwd,
|
|
6432
|
+
shell: false,
|
|
6433
|
+
stdio: ["pipe", "ignore", "ignore"]
|
|
6434
|
+
});
|
|
6435
|
+
const timer = setTimeout(() => {
|
|
6436
|
+
timedOut = true;
|
|
6437
|
+
child.kill("SIGKILL");
|
|
6438
|
+
}, timeoutMs);
|
|
6439
|
+
child.once("error", () => {
|
|
6440
|
+
clearTimeout(timer);
|
|
6441
|
+
finish({ exitCode: 1, timedOut });
|
|
6442
|
+
});
|
|
6443
|
+
child.once("close", (code) => {
|
|
6444
|
+
clearTimeout(timer);
|
|
6445
|
+
finish({ exitCode: code ?? 1, timedOut });
|
|
6446
|
+
});
|
|
6447
|
+
child.stdin?.on("error", () => void 0);
|
|
6448
|
+
child.stdin?.end(command2.stdin);
|
|
6449
|
+
});
|
|
6450
|
+
var defaultDependencies = {
|
|
6451
|
+
now: Date.now,
|
|
6452
|
+
resolveExecutable,
|
|
6453
|
+
runProbe
|
|
6454
|
+
};
|
|
6455
|
+
var isHarness = (value) => typeof value === "string" && SUPPORTED_HARNESSES.includes(value);
|
|
6456
|
+
var isCacheEntry = (value) => {
|
|
6457
|
+
if (!value || typeof value !== "object") return false;
|
|
6458
|
+
const entry = value;
|
|
6459
|
+
return typeof entry.key === "string" && isHarness(entry.harness) && typeof entry.available === "boolean" && typeof entry.observedAt === "number" && Number.isFinite(entry.observedAt) && typeof entry.expiresAt === "number" && Number.isFinite(entry.expiresAt) && typeof entry.reason === "string";
|
|
6460
|
+
};
|
|
6461
|
+
var emptyCache = () => ({ version: CACHE_VERSION, entries: [] });
|
|
6462
|
+
var readCache = (cachePath) => {
|
|
6463
|
+
try {
|
|
6464
|
+
const parsed = JSON.parse(fs4.readFileSync(cachePath, "utf8"));
|
|
6465
|
+
if (!parsed || typeof parsed !== "object") return emptyCache();
|
|
6466
|
+
const record = parsed;
|
|
6467
|
+
if (record.version !== CACHE_VERSION || !Array.isArray(record.entries)) return emptyCache();
|
|
6468
|
+
return { version: CACHE_VERSION, entries: record.entries.filter(isCacheEntry) };
|
|
6469
|
+
} catch {
|
|
6470
|
+
return emptyCache();
|
|
6471
|
+
}
|
|
6472
|
+
};
|
|
6473
|
+
var writeCache = (cachePath, entry) => {
|
|
6474
|
+
fs4.mkdirSync(path5.dirname(cachePath), { recursive: true });
|
|
6475
|
+
const cache = readCache(cachePath);
|
|
6476
|
+
const existingIndex = cache.entries.findIndex((candidate) => candidate.key === entry.key);
|
|
6477
|
+
if (existingIndex === -1) cache.entries.push(entry);
|
|
6478
|
+
else if (cache.entries[existingIndex].observedAt <= entry.observedAt) {
|
|
6479
|
+
cache.entries[existingIndex] = entry;
|
|
6480
|
+
}
|
|
6481
|
+
const temporary = `${cachePath}.${process.pid}.${(0, import_crypto2.randomUUID)()}.tmp`;
|
|
6482
|
+
try {
|
|
6483
|
+
fs4.writeFileSync(temporary, `${JSON.stringify(cache, null, 2)}
|
|
6484
|
+
`, { mode: 384 });
|
|
6485
|
+
fs4.renameSync(temporary, cachePath);
|
|
6486
|
+
} finally {
|
|
6487
|
+
try {
|
|
6488
|
+
fs4.unlinkSync(temporary);
|
|
6489
|
+
} catch {
|
|
6490
|
+
}
|
|
6491
|
+
}
|
|
6492
|
+
};
|
|
6493
|
+
var cacheKey = (harness, executableIdentity, invocation) => (0, import_crypto2.createHash)("sha256").update(
|
|
6494
|
+
JSON.stringify({
|
|
6495
|
+
harness,
|
|
6496
|
+
executableIdentity,
|
|
6497
|
+
cliArgsHash: invocation.cliArgsHash,
|
|
6498
|
+
normalizationVersion: HARNESS_CONFIGURATION_NORMALIZATION_VERSION,
|
|
6499
|
+
probeRegistryVersion: AVAILABILITY_REGISTRY_VERSION
|
|
6500
|
+
})
|
|
6501
|
+
).digest("hex");
|
|
6502
|
+
var readinessEvidence = () => {
|
|
6503
|
+
const nonce = (0, import_crypto2.randomUUID)();
|
|
6504
|
+
return {
|
|
6505
|
+
file: "strikethroo-readiness.txt",
|
|
6506
|
+
content: `strikethroo-readiness:${nonce}
|
|
6507
|
+
`
|
|
6508
|
+
};
|
|
6509
|
+
};
|
|
6510
|
+
var readinessPrompt = (evidence) => `Run a shell command that creates ${evidence.file} in the current workspace with the exact UTF-8 content ${JSON.stringify(evidence.content)}. Do not use a file editing tool.
|
|
6511
|
+
STRIKETHROO_READINESS=${JSON.stringify(evidence)}
|
|
6512
|
+
`;
|
|
6513
|
+
var initializeProbeWorkspace = () => {
|
|
6514
|
+
const workspace = fs4.mkdtempSync(path5.join(os.tmpdir(), "strikethroo-harness-probe-"));
|
|
6515
|
+
const initialized = (0, import_child_process3.spawnSync)("git", ["init", "--quiet"], {
|
|
6516
|
+
cwd: workspace,
|
|
6517
|
+
shell: false,
|
|
6518
|
+
stdio: "ignore",
|
|
6519
|
+
timeout: 5e3
|
|
6520
|
+
});
|
|
6521
|
+
if (initialized.status === 0 && !initialized.error) return workspace;
|
|
6522
|
+
fs4.rmSync(workspace, { recursive: true, force: true });
|
|
6523
|
+
return void 0;
|
|
6524
|
+
};
|
|
6525
|
+
var hasReadinessEvidence = (workspace, evidence) => {
|
|
6526
|
+
const target = path5.join(workspace, evidence.file);
|
|
6527
|
+
try {
|
|
6528
|
+
return fs4.lstatSync(target).isFile() && fs4.readFileSync(target, "utf8") === evidence.content;
|
|
6529
|
+
} catch {
|
|
6530
|
+
return false;
|
|
6531
|
+
}
|
|
6532
|
+
};
|
|
6533
|
+
var outcome = (harness, available, now, reason) => ({
|
|
6534
|
+
harness,
|
|
6535
|
+
available,
|
|
6536
|
+
observedAt: now,
|
|
6537
|
+
expiresAt: now + (available ? AVAILABLE_TTL_MS : UNAVAILABLE_TTL_MS),
|
|
6538
|
+
reason,
|
|
6539
|
+
source: "probe"
|
|
6540
|
+
});
|
|
6541
|
+
var invocationFor = (request, harness) => {
|
|
6542
|
+
if (request.invocation) return request.invocation;
|
|
6543
|
+
const loaded = loadHarnessConfiguration(request.strikethrooRoot);
|
|
6544
|
+
return loaded.kind === "config" ? loaded.config[harness] : void 0;
|
|
6545
|
+
};
|
|
6546
|
+
var checkHarnessAvailability = async (request, overrides = {}) => {
|
|
6547
|
+
const active = { ...defaultDependencies, ...overrides };
|
|
6548
|
+
const now = active.now();
|
|
6549
|
+
if (request.harness === void 0 || request.harness === request.currentHarness) {
|
|
6550
|
+
return {
|
|
6551
|
+
harness: request.harness ?? request.currentHarness,
|
|
6552
|
+
available: true,
|
|
6553
|
+
observedAt: now,
|
|
6554
|
+
expiresAt: now,
|
|
6555
|
+
reason: "Native/current harness targets do not require a probe.",
|
|
6556
|
+
source: "bypass"
|
|
6557
|
+
};
|
|
6558
|
+
}
|
|
6559
|
+
const harness = request.harness;
|
|
6560
|
+
const invocation = invocationFor(request, harness);
|
|
6561
|
+
if (!invocation) return outcome(harness, false, now, "Harness configuration is invalid.");
|
|
6562
|
+
const definition = HARNESS_AVAILABILITY_REGISTRY[harness];
|
|
6563
|
+
const executableIdentity = active.resolveExecutable(definition.executable);
|
|
6564
|
+
if (!executableIdentity)
|
|
6565
|
+
return outcome(harness, false, now, "Harness executable is unavailable.");
|
|
6566
|
+
const key = cacheKey(harness, executableIdentity, invocation);
|
|
6567
|
+
const cachePath = path5.join(request.strikethrooRoot, AVAILABILITY_CACHE_RELATIVE_PATH);
|
|
6568
|
+
const cached = readCache(cachePath).entries.find(
|
|
6569
|
+
(entry) => entry.key === key && entry.expiresAt > now
|
|
6570
|
+
);
|
|
6571
|
+
if (cached) {
|
|
6572
|
+
const { key: _key, ...cachedOutcome } = cached;
|
|
6573
|
+
return { ...cachedOutcome, source: "cache" };
|
|
6574
|
+
}
|
|
6575
|
+
const complete = (result) => {
|
|
6576
|
+
const { source: _source, ...cacheEntry } = result;
|
|
6577
|
+
try {
|
|
6578
|
+
writeCache(cachePath, { key, ...cacheEntry });
|
|
6579
|
+
} catch {
|
|
6580
|
+
}
|
|
6581
|
+
return result;
|
|
6582
|
+
};
|
|
6583
|
+
const probeWorkspace = initializeProbeWorkspace();
|
|
6584
|
+
if (!probeWorkspace) {
|
|
6585
|
+
return complete(outcome(harness, false, now, "Harness readiness check failed."));
|
|
6586
|
+
}
|
|
6587
|
+
try {
|
|
6588
|
+
const evidence = readinessEvidence();
|
|
6589
|
+
const command2 = definition.buildCommand(
|
|
6590
|
+
probeWorkspace,
|
|
6591
|
+
invocation.cliArgs,
|
|
6592
|
+
readinessPrompt(evidence)
|
|
6593
|
+
);
|
|
6594
|
+
const probe = await active.runProbe(
|
|
6595
|
+
{ ...command2, executable: executableIdentity },
|
|
6596
|
+
PROBE_TIMEOUT_MS
|
|
6597
|
+
);
|
|
6598
|
+
const available = probe.exitCode === 0 && !probe.timedOut && hasReadinessEvidence(probeWorkspace, evidence);
|
|
6599
|
+
return complete(
|
|
6600
|
+
outcome(
|
|
6601
|
+
harness,
|
|
6602
|
+
available,
|
|
6603
|
+
now,
|
|
6604
|
+
available ? "Harness readiness verified." : "Harness readiness check failed."
|
|
6605
|
+
)
|
|
6606
|
+
);
|
|
6607
|
+
} finally {
|
|
6608
|
+
fs4.rmSync(probeWorkspace, { recursive: true, force: true });
|
|
6609
|
+
}
|
|
6610
|
+
};
|
|
6611
|
+
|
|
6433
6612
|
// src/skill-scripts/dispatch-task-execution.ts
|
|
6434
6613
|
var emit = (result, exitCode) => {
|
|
6435
6614
|
process.stdout.write(`${JSON.stringify(result)}
|
|
@@ -6482,6 +6661,7 @@ var resolveDispatchRoute = async (request) => {
|
|
|
6482
6661
|
}
|
|
6483
6662
|
const avoided = /* @__PURE__ */ new Set();
|
|
6484
6663
|
const unavailable = [];
|
|
6664
|
+
let harnessConfiguration;
|
|
6485
6665
|
const candidateCount = configResult.config.profiles.find((candidate) => candidate.name === profile)?.targets.length ?? 0;
|
|
6486
6666
|
for (let attempt = 0; attempt < Math.max(1, candidateCount); attempt += 1) {
|
|
6487
6667
|
const selection = selectDispatchTarget(configResult.config, profile, avoided, {
|
|
@@ -6499,11 +6679,23 @@ var resolveDispatchRoute = async (request) => {
|
|
|
6499
6679
|
...selection.target.reasoning_effort === void 0 ? {} : { reasoningEffort: selection.target.reasoning_effort }
|
|
6500
6680
|
};
|
|
6501
6681
|
}
|
|
6682
|
+
harnessConfiguration ??= loadHarnessConfiguration(request.strikethrooRoot);
|
|
6683
|
+
if (harnessConfiguration.kind === "invalid") {
|
|
6684
|
+
return {
|
|
6685
|
+
kind: "fallback",
|
|
6686
|
+
reason: "invalid-execution",
|
|
6687
|
+
detail: `Harness invocation configuration is invalid: ${harnessConfiguration.errors.join(
|
|
6688
|
+
" "
|
|
6689
|
+
)}`
|
|
6690
|
+
};
|
|
6691
|
+
}
|
|
6692
|
+
const invocation = harnessConfiguration.config[harness];
|
|
6502
6693
|
const availability = await checkHarnessAvailability({
|
|
6503
6694
|
strikethrooRoot: request.strikethrooRoot,
|
|
6504
6695
|
workspace: request.workspace,
|
|
6505
6696
|
harness,
|
|
6506
|
-
currentHarness: request.currentHarness
|
|
6697
|
+
currentHarness: request.currentHarness,
|
|
6698
|
+
invocation
|
|
6507
6699
|
});
|
|
6508
6700
|
if (availability.available) {
|
|
6509
6701
|
return externalRoute(harness, selection.target.model, selection.target.reasoning_effort);
|
|
@@ -6541,26 +6733,41 @@ var main = async () => {
|
|
|
6541
6733
|
const validWorkspace = workspace;
|
|
6542
6734
|
const validPlanId = planId;
|
|
6543
6735
|
const validTaskId = taskId;
|
|
6544
|
-
const taskPath =
|
|
6545
|
-
const taskMarkdown =
|
|
6736
|
+
const taskPath = path6.resolve(validTaskFile);
|
|
6737
|
+
const taskMarkdown = fs5.readFileSync(taskPath, "utf8");
|
|
6546
6738
|
if (mode === "resolve") {
|
|
6547
6739
|
emit(
|
|
6548
6740
|
await resolveDispatchRoute({
|
|
6549
6741
|
taskMarkdown,
|
|
6550
6742
|
currentHarness: validCurrentHarness,
|
|
6551
|
-
workspace:
|
|
6552
|
-
strikethrooRoot:
|
|
6743
|
+
workspace: path6.resolve(validWorkspace),
|
|
6744
|
+
strikethrooRoot: path6.join(path6.resolve(validWorkspace), ".ai", "strikethroo"),
|
|
6553
6745
|
taskId: Number(validTaskId)
|
|
6554
6746
|
}),
|
|
6555
6747
|
0
|
|
6556
6748
|
);
|
|
6557
6749
|
}
|
|
6558
6750
|
const handoff = decodeHandoff(handoffArg);
|
|
6751
|
+
const executionConfiguration = loadHarnessConfiguration(
|
|
6752
|
+
path6.join(path6.resolve(validWorkspace), ".ai", "strikethroo")
|
|
6753
|
+
);
|
|
6754
|
+
if (executionConfiguration.kind === "invalid") {
|
|
6755
|
+
return emit(
|
|
6756
|
+
{
|
|
6757
|
+
kind: "infrastructure-failure",
|
|
6758
|
+
detail: `Harness invocation configuration is invalid: ${executionConfiguration.errors.join(
|
|
6759
|
+
" "
|
|
6760
|
+
)}`
|
|
6761
|
+
},
|
|
6762
|
+
2
|
|
6763
|
+
);
|
|
6764
|
+
}
|
|
6559
6765
|
const routed = {
|
|
6560
6766
|
harness: handoff.harness,
|
|
6767
|
+
cliArgs: executionConfiguration.config[handoff.harness].cliArgs,
|
|
6561
6768
|
model: handoff.model,
|
|
6562
6769
|
...handoff.reasoningEffort === void 0 ? {} : { reasoningEffort: handoff.reasoningEffort },
|
|
6563
|
-
workspace:
|
|
6770
|
+
workspace: path6.resolve(validWorkspace),
|
|
6564
6771
|
planId: validPlanId,
|
|
6565
6772
|
taskId: validTaskId,
|
|
6566
6773
|
taskFile: taskPath,
|