@versatly/workgraph 1.2.0 → 1.3.1
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.
|
@@ -622,8 +622,7 @@ var BUILT_IN_TYPES = [
|
|
|
622
622
|
proposed_at: { type: "date" },
|
|
623
623
|
promoted_at: { type: "date" },
|
|
624
624
|
depends_on: { type: "list", default: [], description: "Skill dependencies by slug or path" },
|
|
625
|
-
distribution: { type: "string", default: "
|
|
626
|
-
tailscale_path: { type: "string", description: "Shared vault path over Tailscale" },
|
|
625
|
+
distribution: { type: "string", default: "shared-vault", description: "Distribution channel for skill usage" },
|
|
627
626
|
tags: { type: "list", default: [] },
|
|
628
627
|
created: { type: "date", required: true },
|
|
629
628
|
updated: { type: "date", required: true }
|
|
@@ -841,8 +840,24 @@ function ensureBuiltIns(registry) {
|
|
|
841
840
|
for (const t of BUILT_IN_TYPES) {
|
|
842
841
|
if (!registry.types[t.name]) {
|
|
843
842
|
registry.types[t.name] = t;
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
const existing = registry.types[t.name];
|
|
846
|
+
if (existing.builtIn) {
|
|
847
|
+
registry.types[t.name] = {
|
|
848
|
+
...existing,
|
|
849
|
+
description: t.description,
|
|
850
|
+
directory: t.directory,
|
|
851
|
+
fields: {
|
|
852
|
+
...existing.fields,
|
|
853
|
+
...t.fields
|
|
854
|
+
}
|
|
855
|
+
};
|
|
844
856
|
}
|
|
845
857
|
}
|
|
858
|
+
if (registry.types.skill?.builtIn && "tailscale_path" in registry.types.skill.fields) {
|
|
859
|
+
delete registry.types.skill.fields.tailscale_path;
|
|
860
|
+
}
|
|
846
861
|
return registry;
|
|
847
862
|
}
|
|
848
863
|
|
|
@@ -4163,6 +4178,9 @@ function asDate(value) {
|
|
|
4163
4178
|
return new Date(timestamp);
|
|
4164
4179
|
}
|
|
4165
4180
|
|
|
4181
|
+
// src/adapter-shell-worker.ts
|
|
4182
|
+
import { spawn } from "child_process";
|
|
4183
|
+
|
|
4166
4184
|
// src/orientation.ts
|
|
4167
4185
|
var orientation_exports = {};
|
|
4168
4186
|
__export(orientation_exports, {
|
|
@@ -4564,9 +4582,523 @@ function renderSummary(data) {
|
|
|
4564
4582
|
return lines.join("\n");
|
|
4565
4583
|
}
|
|
4566
4584
|
|
|
4585
|
+
// src/adapter-shell-worker.ts
|
|
4586
|
+
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
4587
|
+
var MAX_CAPTURE_CHARS = 12e3;
|
|
4588
|
+
var ShellWorkerAdapter = class {
|
|
4589
|
+
name = "shell-worker";
|
|
4590
|
+
fallback = new CursorCloudAdapter();
|
|
4591
|
+
async create(_input) {
|
|
4592
|
+
return { runId: "shell-worker-managed", status: "queued" };
|
|
4593
|
+
}
|
|
4594
|
+
async status(runId) {
|
|
4595
|
+
return { runId, status: "running" };
|
|
4596
|
+
}
|
|
4597
|
+
async followup(runId, _actor, _input) {
|
|
4598
|
+
return { runId, status: "running" };
|
|
4599
|
+
}
|
|
4600
|
+
async stop(runId, _actor) {
|
|
4601
|
+
return { runId, status: "cancelled" };
|
|
4602
|
+
}
|
|
4603
|
+
async logs(_runId) {
|
|
4604
|
+
return [];
|
|
4605
|
+
}
|
|
4606
|
+
async execute(input) {
|
|
4607
|
+
const command = readString(input.context?.shell_command);
|
|
4608
|
+
if (!command) {
|
|
4609
|
+
return this.fallback.execute(input);
|
|
4610
|
+
}
|
|
4611
|
+
const shellCwd = readString(input.context?.shell_cwd) ?? input.workspacePath;
|
|
4612
|
+
const timeoutMs = clampInt(readNumber(input.context?.shell_timeout_ms), DEFAULT_TIMEOUT_MS, 1e3, 60 * 60 * 1e3);
|
|
4613
|
+
const shellEnv = readEnv(input.context?.shell_env);
|
|
4614
|
+
const logs2 = [];
|
|
4615
|
+
const startedAt = Date.now();
|
|
4616
|
+
const outputParts = [];
|
|
4617
|
+
const errorParts = [];
|
|
4618
|
+
pushLog2(logs2, "info", `shell-worker starting command: ${command}`);
|
|
4619
|
+
pushLog2(logs2, "info", `shell-worker cwd: ${shellCwd}`);
|
|
4620
|
+
const result = await runShellCommand({
|
|
4621
|
+
command,
|
|
4622
|
+
cwd: shellCwd,
|
|
4623
|
+
timeoutMs,
|
|
4624
|
+
env: shellEnv,
|
|
4625
|
+
isCancelled: input.isCancelled,
|
|
4626
|
+
onStdout: (chunk) => {
|
|
4627
|
+
outputParts.push(chunk);
|
|
4628
|
+
pushLog2(logs2, "info", `[stdout] ${chunk.trimEnd()}`);
|
|
4629
|
+
},
|
|
4630
|
+
onStderr: (chunk) => {
|
|
4631
|
+
errorParts.push(chunk);
|
|
4632
|
+
pushLog2(logs2, "warn", `[stderr] ${chunk.trimEnd()}`);
|
|
4633
|
+
}
|
|
4634
|
+
});
|
|
4635
|
+
const elapsedMs = Date.now() - startedAt;
|
|
4636
|
+
const stdout = truncateText(outputParts.join(""), MAX_CAPTURE_CHARS);
|
|
4637
|
+
const stderr = truncateText(errorParts.join(""), MAX_CAPTURE_CHARS);
|
|
4638
|
+
if (result.cancelled) {
|
|
4639
|
+
pushLog2(logs2, "warn", `shell-worker command cancelled after ${elapsedMs}ms`);
|
|
4640
|
+
return {
|
|
4641
|
+
status: "cancelled",
|
|
4642
|
+
output: formatShellOutput(command, result.exitCode, stdout, stderr, elapsedMs, true),
|
|
4643
|
+
logs: logs2
|
|
4644
|
+
};
|
|
4645
|
+
}
|
|
4646
|
+
if (result.timedOut) {
|
|
4647
|
+
pushLog2(logs2, "error", `shell-worker command timed out after ${elapsedMs}ms`);
|
|
4648
|
+
return {
|
|
4649
|
+
status: "failed",
|
|
4650
|
+
error: formatShellOutput(command, result.exitCode, stdout, stderr, elapsedMs, false),
|
|
4651
|
+
logs: logs2
|
|
4652
|
+
};
|
|
4653
|
+
}
|
|
4654
|
+
if (result.exitCode !== 0) {
|
|
4655
|
+
pushLog2(logs2, "error", `shell-worker command failed with exit code ${result.exitCode}`);
|
|
4656
|
+
return {
|
|
4657
|
+
status: "failed",
|
|
4658
|
+
error: formatShellOutput(command, result.exitCode, stdout, stderr, elapsedMs, false),
|
|
4659
|
+
logs: logs2
|
|
4660
|
+
};
|
|
4661
|
+
}
|
|
4662
|
+
pushLog2(logs2, "info", `shell-worker command succeeded in ${elapsedMs}ms`);
|
|
4663
|
+
return {
|
|
4664
|
+
status: "succeeded",
|
|
4665
|
+
output: formatShellOutput(command, result.exitCode, stdout, stderr, elapsedMs, false),
|
|
4666
|
+
logs: logs2,
|
|
4667
|
+
metrics: {
|
|
4668
|
+
elapsedMs,
|
|
4669
|
+
exitCode: result.exitCode,
|
|
4670
|
+
adapter: "shell-worker"
|
|
4671
|
+
}
|
|
4672
|
+
};
|
|
4673
|
+
}
|
|
4674
|
+
};
|
|
4675
|
+
async function runShellCommand(options) {
|
|
4676
|
+
return new Promise((resolve) => {
|
|
4677
|
+
const child = spawn(options.command, {
|
|
4678
|
+
cwd: options.cwd,
|
|
4679
|
+
env: { ...process.env, ...options.env },
|
|
4680
|
+
shell: true,
|
|
4681
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4682
|
+
});
|
|
4683
|
+
let resolved = false;
|
|
4684
|
+
let timedOut = false;
|
|
4685
|
+
let cancelled = false;
|
|
4686
|
+
const timeoutHandle = setTimeout(() => {
|
|
4687
|
+
timedOut = true;
|
|
4688
|
+
child.kill("SIGTERM");
|
|
4689
|
+
setTimeout(() => child.kill("SIGKILL"), 1500).unref();
|
|
4690
|
+
}, options.timeoutMs);
|
|
4691
|
+
const cancelWatcher = setInterval(() => {
|
|
4692
|
+
if (options.isCancelled?.()) {
|
|
4693
|
+
cancelled = true;
|
|
4694
|
+
child.kill("SIGTERM");
|
|
4695
|
+
}
|
|
4696
|
+
}, 200);
|
|
4697
|
+
cancelWatcher.unref();
|
|
4698
|
+
child.stdout.on("data", (chunk) => {
|
|
4699
|
+
options.onStdout(chunk.toString("utf-8"));
|
|
4700
|
+
});
|
|
4701
|
+
child.stderr.on("data", (chunk) => {
|
|
4702
|
+
options.onStderr(chunk.toString("utf-8"));
|
|
4703
|
+
});
|
|
4704
|
+
child.on("close", (code) => {
|
|
4705
|
+
if (resolved) return;
|
|
4706
|
+
resolved = true;
|
|
4707
|
+
clearTimeout(timeoutHandle);
|
|
4708
|
+
clearInterval(cancelWatcher);
|
|
4709
|
+
resolve({
|
|
4710
|
+
exitCode: typeof code === "number" ? code : 1,
|
|
4711
|
+
timedOut,
|
|
4712
|
+
cancelled
|
|
4713
|
+
});
|
|
4714
|
+
});
|
|
4715
|
+
child.on("error", () => {
|
|
4716
|
+
if (resolved) return;
|
|
4717
|
+
resolved = true;
|
|
4718
|
+
clearTimeout(timeoutHandle);
|
|
4719
|
+
clearInterval(cancelWatcher);
|
|
4720
|
+
resolve({
|
|
4721
|
+
exitCode: 1,
|
|
4722
|
+
timedOut,
|
|
4723
|
+
cancelled
|
|
4724
|
+
});
|
|
4725
|
+
});
|
|
4726
|
+
});
|
|
4727
|
+
}
|
|
4728
|
+
function pushLog2(target, level, message) {
|
|
4729
|
+
target.push({
|
|
4730
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4731
|
+
level,
|
|
4732
|
+
message
|
|
4733
|
+
});
|
|
4734
|
+
}
|
|
4735
|
+
function readEnv(value) {
|
|
4736
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
4737
|
+
const input = value;
|
|
4738
|
+
const result = {};
|
|
4739
|
+
for (const [key, raw] of Object.entries(input)) {
|
|
4740
|
+
if (!key) continue;
|
|
4741
|
+
if (raw === void 0 || raw === null) continue;
|
|
4742
|
+
result[key] = String(raw);
|
|
4743
|
+
}
|
|
4744
|
+
return result;
|
|
4745
|
+
}
|
|
4746
|
+
function readString(value) {
|
|
4747
|
+
if (typeof value !== "string") return void 0;
|
|
4748
|
+
const trimmed = value.trim();
|
|
4749
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
4750
|
+
}
|
|
4751
|
+
function readNumber(value) {
|
|
4752
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4753
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
4754
|
+
const parsed = Number(value);
|
|
4755
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
4756
|
+
}
|
|
4757
|
+
return void 0;
|
|
4758
|
+
}
|
|
4759
|
+
function clampInt(value, fallback, min, max) {
|
|
4760
|
+
const raw = typeof value === "number" ? Math.trunc(value) : fallback;
|
|
4761
|
+
return Math.min(max, Math.max(min, raw));
|
|
4762
|
+
}
|
|
4763
|
+
function truncateText(value, limit) {
|
|
4764
|
+
if (value.length <= limit) return value;
|
|
4765
|
+
return `${value.slice(0, limit)}
|
|
4766
|
+
...[truncated]`;
|
|
4767
|
+
}
|
|
4768
|
+
function formatShellOutput(command, exitCode, stdout, stderr, elapsedMs, cancelled) {
|
|
4769
|
+
const lines = [
|
|
4770
|
+
"Shell worker execution summary",
|
|
4771
|
+
`Command: ${command}`,
|
|
4772
|
+
`Exit code: ${exitCode}`,
|
|
4773
|
+
`Elapsed ms: ${elapsedMs}`,
|
|
4774
|
+
`Cancelled: ${cancelled ? "yes" : "no"}`,
|
|
4775
|
+
"",
|
|
4776
|
+
"STDOUT:",
|
|
4777
|
+
stdout || "(empty)",
|
|
4778
|
+
"",
|
|
4779
|
+
"STDERR:",
|
|
4780
|
+
stderr || "(empty)"
|
|
4781
|
+
];
|
|
4782
|
+
return lines.join("\n");
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
// src/adapter-claude-code.ts
|
|
4786
|
+
var ClaudeCodeAdapter = class {
|
|
4787
|
+
name = "claude-code";
|
|
4788
|
+
shellWorker = new ShellWorkerAdapter();
|
|
4789
|
+
async create(input) {
|
|
4790
|
+
return this.shellWorker.create(input);
|
|
4791
|
+
}
|
|
4792
|
+
async status(runId) {
|
|
4793
|
+
return this.shellWorker.status(runId);
|
|
4794
|
+
}
|
|
4795
|
+
async followup(runId, actor, input) {
|
|
4796
|
+
return this.shellWorker.followup(runId, actor, input);
|
|
4797
|
+
}
|
|
4798
|
+
async stop(runId, actor) {
|
|
4799
|
+
return this.shellWorker.stop(runId, actor);
|
|
4800
|
+
}
|
|
4801
|
+
async logs(runId) {
|
|
4802
|
+
return this.shellWorker.logs(runId);
|
|
4803
|
+
}
|
|
4804
|
+
async execute(input) {
|
|
4805
|
+
const template = readString2(input.context?.claude_command_template) ?? process.env.WORKGRAPH_CLAUDE_COMMAND_TEMPLATE;
|
|
4806
|
+
if (!template) {
|
|
4807
|
+
return {
|
|
4808
|
+
status: "failed",
|
|
4809
|
+
error: [
|
|
4810
|
+
"claude-code adapter requires a command template.",
|
|
4811
|
+
"Set context.claude_command_template or WORKGRAPH_CLAUDE_COMMAND_TEMPLATE.",
|
|
4812
|
+
"Template tokens: {workspace}, {run_id}, {actor}, {objective}, {prompt}, {prompt_shell}.",
|
|
4813
|
+
"Example: claude -p {prompt_shell}"
|
|
4814
|
+
].join(" "),
|
|
4815
|
+
logs: [
|
|
4816
|
+
{
|
|
4817
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4818
|
+
level: "error",
|
|
4819
|
+
message: "Missing Claude command template."
|
|
4820
|
+
}
|
|
4821
|
+
]
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
const prompt = buildPrompt(input);
|
|
4825
|
+
const command = applyTemplate(template, {
|
|
4826
|
+
workspace: input.workspacePath,
|
|
4827
|
+
run_id: input.runId,
|
|
4828
|
+
actor: input.actor,
|
|
4829
|
+
objective: input.objective,
|
|
4830
|
+
prompt,
|
|
4831
|
+
prompt_shell: quoteForShell(prompt)
|
|
4832
|
+
});
|
|
4833
|
+
const context = {
|
|
4834
|
+
...input.context,
|
|
4835
|
+
shell_command: command,
|
|
4836
|
+
shell_cwd: readString2(input.context?.shell_cwd) ?? input.workspacePath,
|
|
4837
|
+
shell_timeout_ms: input.context?.shell_timeout_ms ?? process.env.WORKGRAPH_CLAUDE_TIMEOUT_MS
|
|
4838
|
+
};
|
|
4839
|
+
const result = await this.shellWorker.execute({
|
|
4840
|
+
...input,
|
|
4841
|
+
context
|
|
4842
|
+
});
|
|
4843
|
+
const logs2 = [
|
|
4844
|
+
{
|
|
4845
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4846
|
+
level: "info",
|
|
4847
|
+
message: "claude-code adapter dispatched shell execution from command template."
|
|
4848
|
+
},
|
|
4849
|
+
...result.logs ?? []
|
|
4850
|
+
];
|
|
4851
|
+
return {
|
|
4852
|
+
...result,
|
|
4853
|
+
logs: logs2,
|
|
4854
|
+
metrics: {
|
|
4855
|
+
...result.metrics ?? {},
|
|
4856
|
+
adapter: "claude-code"
|
|
4857
|
+
}
|
|
4858
|
+
};
|
|
4859
|
+
}
|
|
4860
|
+
};
|
|
4861
|
+
function buildPrompt(input) {
|
|
4862
|
+
const extraInstructions = readString2(input.context?.claude_instructions);
|
|
4863
|
+
const sections = [
|
|
4864
|
+
`Workgraph run id: ${input.runId}`,
|
|
4865
|
+
`Actor: ${input.actor}`,
|
|
4866
|
+
`Objective: ${input.objective}`,
|
|
4867
|
+
`Workspace: ${input.workspacePath}`
|
|
4868
|
+
];
|
|
4869
|
+
if (extraInstructions) {
|
|
4870
|
+
sections.push(`Instructions: ${extraInstructions}`);
|
|
4871
|
+
}
|
|
4872
|
+
return sections.join("\n");
|
|
4873
|
+
}
|
|
4874
|
+
function applyTemplate(template, values) {
|
|
4875
|
+
let rendered = template;
|
|
4876
|
+
for (const [key, value] of Object.entries(values)) {
|
|
4877
|
+
rendered = rendered.replaceAll(`{${key}}`, value);
|
|
4878
|
+
}
|
|
4879
|
+
return rendered;
|
|
4880
|
+
}
|
|
4881
|
+
function quoteForShell(value) {
|
|
4882
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
4883
|
+
}
|
|
4884
|
+
function readString2(value) {
|
|
4885
|
+
if (typeof value !== "string") return void 0;
|
|
4886
|
+
const trimmed = value.trim();
|
|
4887
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
// src/adapter-http-webhook.ts
|
|
4891
|
+
var DEFAULT_POLL_MS = 1e3;
|
|
4892
|
+
var DEFAULT_MAX_WAIT_MS = 9e4;
|
|
4893
|
+
var HttpWebhookAdapter = class {
|
|
4894
|
+
name = "http-webhook";
|
|
4895
|
+
async create(_input) {
|
|
4896
|
+
return { runId: "http-webhook-managed", status: "queued" };
|
|
4897
|
+
}
|
|
4898
|
+
async status(runId) {
|
|
4899
|
+
return { runId, status: "running" };
|
|
4900
|
+
}
|
|
4901
|
+
async followup(runId, _actor, _input) {
|
|
4902
|
+
return { runId, status: "running" };
|
|
4903
|
+
}
|
|
4904
|
+
async stop(runId, _actor) {
|
|
4905
|
+
return { runId, status: "cancelled" };
|
|
4906
|
+
}
|
|
4907
|
+
async logs(_runId) {
|
|
4908
|
+
return [];
|
|
4909
|
+
}
|
|
4910
|
+
async execute(input) {
|
|
4911
|
+
const logs2 = [];
|
|
4912
|
+
const webhookUrl = resolveUrl(input.context?.webhook_url, process.env.WORKGRAPH_DISPATCH_WEBHOOK_URL);
|
|
4913
|
+
if (!webhookUrl) {
|
|
4914
|
+
return {
|
|
4915
|
+
status: "failed",
|
|
4916
|
+
error: "http-webhook adapter requires context.webhook_url or WORKGRAPH_DISPATCH_WEBHOOK_URL.",
|
|
4917
|
+
logs: logs2
|
|
4918
|
+
};
|
|
4919
|
+
}
|
|
4920
|
+
const token = readString3(input.context?.webhook_token) ?? process.env.WORKGRAPH_DISPATCH_WEBHOOK_TOKEN;
|
|
4921
|
+
const headers = {
|
|
4922
|
+
"content-type": "application/json",
|
|
4923
|
+
...extractHeaders(input.context?.webhook_headers),
|
|
4924
|
+
...token ? { authorization: `Bearer ${token}` } : {}
|
|
4925
|
+
};
|
|
4926
|
+
const payload = {
|
|
4927
|
+
runId: input.runId,
|
|
4928
|
+
actor: input.actor,
|
|
4929
|
+
objective: input.objective,
|
|
4930
|
+
workspacePath: input.workspacePath,
|
|
4931
|
+
context: input.context ?? {},
|
|
4932
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
4933
|
+
};
|
|
4934
|
+
pushLog3(logs2, "info", `http-webhook posting run ${input.runId} to ${webhookUrl}`);
|
|
4935
|
+
const response = await fetch(webhookUrl, {
|
|
4936
|
+
method: "POST",
|
|
4937
|
+
headers,
|
|
4938
|
+
body: JSON.stringify(payload)
|
|
4939
|
+
});
|
|
4940
|
+
const rawText = await response.text();
|
|
4941
|
+
const parsed = safeParseJson(rawText);
|
|
4942
|
+
pushLog3(logs2, response.ok ? "info" : "error", `http-webhook response status: ${response.status}`);
|
|
4943
|
+
if (!response.ok) {
|
|
4944
|
+
return {
|
|
4945
|
+
status: "failed",
|
|
4946
|
+
error: `http-webhook request failed (${response.status}): ${rawText || response.statusText}`,
|
|
4947
|
+
logs: logs2
|
|
4948
|
+
};
|
|
4949
|
+
}
|
|
4950
|
+
const immediateStatus = normalizeRunStatus(parsed?.status);
|
|
4951
|
+
if (immediateStatus && isTerminalStatus(immediateStatus)) {
|
|
4952
|
+
return {
|
|
4953
|
+
status: immediateStatus,
|
|
4954
|
+
output: typeof parsed?.output === "string" ? parsed.output : rawText,
|
|
4955
|
+
error: typeof parsed?.error === "string" ? parsed.error : void 0,
|
|
4956
|
+
logs: logs2,
|
|
4957
|
+
metrics: {
|
|
4958
|
+
adapter: "http-webhook",
|
|
4959
|
+
httpStatus: response.status
|
|
4960
|
+
}
|
|
4961
|
+
};
|
|
4962
|
+
}
|
|
4963
|
+
const pollUrl = resolveUrl(parsed?.pollUrl, input.context?.webhook_status_url, process.env.WORKGRAPH_DISPATCH_WEBHOOK_STATUS_URL);
|
|
4964
|
+
if (!pollUrl) {
|
|
4965
|
+
return {
|
|
4966
|
+
status: "succeeded",
|
|
4967
|
+
output: rawText || "http-webhook acknowledged run successfully.",
|
|
4968
|
+
logs: logs2,
|
|
4969
|
+
metrics: {
|
|
4970
|
+
adapter: "http-webhook",
|
|
4971
|
+
httpStatus: response.status
|
|
4972
|
+
}
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
const pollMs = clampInt2(readNumber2(input.context?.webhook_poll_ms), DEFAULT_POLL_MS, 200, 3e4);
|
|
4976
|
+
const maxWaitMs = clampInt2(readNumber2(input.context?.webhook_max_wait_ms), DEFAULT_MAX_WAIT_MS, 1e3, 15 * 6e4);
|
|
4977
|
+
const startedAt = Date.now();
|
|
4978
|
+
pushLog3(logs2, "info", `http-webhook polling status from ${pollUrl}`);
|
|
4979
|
+
while (Date.now() - startedAt < maxWaitMs) {
|
|
4980
|
+
if (input.isCancelled?.()) {
|
|
4981
|
+
pushLog3(logs2, "warn", "http-webhook run cancelled while polling");
|
|
4982
|
+
return {
|
|
4983
|
+
status: "cancelled",
|
|
4984
|
+
output: "http-webhook polling cancelled by dispatcher.",
|
|
4985
|
+
logs: logs2
|
|
4986
|
+
};
|
|
4987
|
+
}
|
|
4988
|
+
const pollResponse = await fetch(pollUrl, {
|
|
4989
|
+
method: "GET",
|
|
4990
|
+
headers: {
|
|
4991
|
+
...headers
|
|
4992
|
+
}
|
|
4993
|
+
});
|
|
4994
|
+
const pollText = await pollResponse.text();
|
|
4995
|
+
const pollJson = safeParseJson(pollText);
|
|
4996
|
+
const pollStatus = normalizeRunStatus(pollJson?.status);
|
|
4997
|
+
pushLog3(logs2, "info", `poll status=${pollResponse.status} run_status=${pollStatus ?? "unknown"}`);
|
|
4998
|
+
if (pollStatus && isTerminalStatus(pollStatus)) {
|
|
4999
|
+
return {
|
|
5000
|
+
status: pollStatus,
|
|
5001
|
+
output: typeof pollJson?.output === "string" ? pollJson.output : pollText,
|
|
5002
|
+
error: typeof pollJson?.error === "string" ? pollJson.error : void 0,
|
|
5003
|
+
logs: logs2,
|
|
5004
|
+
metrics: {
|
|
5005
|
+
adapter: "http-webhook",
|
|
5006
|
+
pollUrl,
|
|
5007
|
+
pollHttpStatus: pollResponse.status,
|
|
5008
|
+
elapsedMs: Date.now() - startedAt
|
|
5009
|
+
}
|
|
5010
|
+
};
|
|
5011
|
+
}
|
|
5012
|
+
await sleep3(pollMs);
|
|
5013
|
+
}
|
|
5014
|
+
return {
|
|
5015
|
+
status: "failed",
|
|
5016
|
+
error: `http-webhook polling exceeded timeout (${maxWaitMs}ms) for run ${input.runId}.`,
|
|
5017
|
+
logs: logs2
|
|
5018
|
+
};
|
|
5019
|
+
}
|
|
5020
|
+
};
|
|
5021
|
+
function pushLog3(target, level, message) {
|
|
5022
|
+
target.push({
|
|
5023
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5024
|
+
level,
|
|
5025
|
+
message
|
|
5026
|
+
});
|
|
5027
|
+
}
|
|
5028
|
+
function readString3(value) {
|
|
5029
|
+
if (typeof value !== "string") return void 0;
|
|
5030
|
+
const trimmed = value.trim();
|
|
5031
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
5032
|
+
}
|
|
5033
|
+
function resolveUrl(...values) {
|
|
5034
|
+
for (const value of values) {
|
|
5035
|
+
const parsed = readString3(value);
|
|
5036
|
+
if (!parsed) continue;
|
|
5037
|
+
try {
|
|
5038
|
+
const url = new URL(parsed);
|
|
5039
|
+
if (url.protocol === "http:" || url.protocol === "https:") {
|
|
5040
|
+
return url.toString();
|
|
5041
|
+
}
|
|
5042
|
+
} catch {
|
|
5043
|
+
continue;
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
return void 0;
|
|
5047
|
+
}
|
|
5048
|
+
function extractHeaders(input) {
|
|
5049
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return {};
|
|
5050
|
+
const record = input;
|
|
5051
|
+
const out = {};
|
|
5052
|
+
for (const [key, value] of Object.entries(record)) {
|
|
5053
|
+
if (!key || value === void 0 || value === null) continue;
|
|
5054
|
+
out[key.toLowerCase()] = String(value);
|
|
5055
|
+
}
|
|
5056
|
+
return out;
|
|
5057
|
+
}
|
|
5058
|
+
function safeParseJson(value) {
|
|
5059
|
+
if (!value || !value.trim()) return null;
|
|
5060
|
+
try {
|
|
5061
|
+
const parsed = JSON.parse(value);
|
|
5062
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
5063
|
+
return parsed;
|
|
5064
|
+
} catch {
|
|
5065
|
+
return null;
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
function normalizeRunStatus(value) {
|
|
5069
|
+
const normalized = String(value ?? "").toLowerCase();
|
|
5070
|
+
if (normalized === "queued" || normalized === "running" || normalized === "succeeded" || normalized === "failed" || normalized === "cancelled") {
|
|
5071
|
+
return normalized;
|
|
5072
|
+
}
|
|
5073
|
+
return void 0;
|
|
5074
|
+
}
|
|
5075
|
+
function isTerminalStatus(status2) {
|
|
5076
|
+
return status2 === "succeeded" || status2 === "failed" || status2 === "cancelled";
|
|
5077
|
+
}
|
|
5078
|
+
function readNumber2(value) {
|
|
5079
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
5080
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
5081
|
+
const parsed = Number(value);
|
|
5082
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
5083
|
+
}
|
|
5084
|
+
return void 0;
|
|
5085
|
+
}
|
|
5086
|
+
function clampInt2(value, fallback, min, max) {
|
|
5087
|
+
const raw = typeof value === "number" ? Math.trunc(value) : fallback;
|
|
5088
|
+
return Math.min(max, Math.max(min, raw));
|
|
5089
|
+
}
|
|
5090
|
+
function sleep3(ms) {
|
|
5091
|
+
return new Promise((resolve) => {
|
|
5092
|
+
setTimeout(resolve, ms);
|
|
5093
|
+
});
|
|
5094
|
+
}
|
|
5095
|
+
|
|
4567
5096
|
// src/runtime-adapter-registry.ts
|
|
4568
5097
|
var adapterFactories = /* @__PURE__ */ new Map([
|
|
4569
|
-
["
|
|
5098
|
+
["claude-code", () => new ClaudeCodeAdapter()],
|
|
5099
|
+
["cursor-cloud", () => new CursorCloudAdapter()],
|
|
5100
|
+
["http-webhook", () => new HttpWebhookAdapter()],
|
|
5101
|
+
["shell-worker", () => new ShellWorkerAdapter()]
|
|
4570
5102
|
]);
|
|
4571
5103
|
function resolveDispatchAdapter(name) {
|
|
4572
5104
|
const safeName = normalizeName(name);
|
|
@@ -5049,9 +5581,9 @@ function resolveThreadRef2(threadRef) {
|
|
|
5049
5581
|
// src/autonomy.ts
|
|
5050
5582
|
async function runAutonomyLoop(workspacePath, options) {
|
|
5051
5583
|
const watch = options.watch === true;
|
|
5052
|
-
const pollMs =
|
|
5053
|
-
const maxCycles =
|
|
5054
|
-
const maxIdleCycles =
|
|
5584
|
+
const pollMs = clampInt3(options.pollMs, 2e3, 100, 6e4);
|
|
5585
|
+
const maxCycles = clampInt3(options.maxCycles, watch ? Number.MAX_SAFE_INTEGER : 20, 1, Number.MAX_SAFE_INTEGER);
|
|
5586
|
+
const maxIdleCycles = clampInt3(options.maxIdleCycles, watch ? Number.MAX_SAFE_INTEGER : 2, 1, Number.MAX_SAFE_INTEGER);
|
|
5055
5587
|
const cycles = [];
|
|
5056
5588
|
let idleCycles = 0;
|
|
5057
5589
|
for (let cycle = 1; cycle <= maxCycles; cycle++) {
|
|
@@ -5110,7 +5642,7 @@ async function runAutonomyLoop(workspacePath, options) {
|
|
|
5110
5642
|
if (cycle >= maxCycles) {
|
|
5111
5643
|
break;
|
|
5112
5644
|
}
|
|
5113
|
-
await
|
|
5645
|
+
await sleep4(pollMs);
|
|
5114
5646
|
}
|
|
5115
5647
|
const finalReadyThreads = (options.space ? listReadyThreadsInSpace(workspacePath, options.space) : listReadyThreads(workspacePath)).length;
|
|
5116
5648
|
writeHeartbeat(options.heartbeatFile, {
|
|
@@ -5124,11 +5656,11 @@ async function runAutonomyLoop(workspacePath, options) {
|
|
|
5124
5656
|
finalDriftOk: true
|
|
5125
5657
|
};
|
|
5126
5658
|
}
|
|
5127
|
-
function
|
|
5659
|
+
function clampInt3(value, fallback, min, max) {
|
|
5128
5660
|
const raw = typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : fallback;
|
|
5129
5661
|
return Math.min(max, Math.max(min, raw));
|
|
5130
5662
|
}
|
|
5131
|
-
function
|
|
5663
|
+
function sleep4(ms) {
|
|
5132
5664
|
return new Promise((resolve) => {
|
|
5133
5665
|
setTimeout(resolve, ms);
|
|
5134
5666
|
});
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
saveRegistry,
|
|
27
27
|
stop,
|
|
28
28
|
update
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-BJVBE7F4.js";
|
|
30
30
|
|
|
31
31
|
// src/workspace.ts
|
|
32
32
|
var workspace_exports = {};
|
|
@@ -363,8 +363,7 @@ function writeSkill(workspacePath, title, body, actor, options = {}) {
|
|
|
363
363
|
owner: options.owner ?? actor,
|
|
364
364
|
version: options.version ?? "0.1.0",
|
|
365
365
|
status,
|
|
366
|
-
distribution: options.distribution ?? "
|
|
367
|
-
tailscale_path: options.tailscalePath,
|
|
366
|
+
distribution: options.distribution ?? "shared-vault",
|
|
368
367
|
reviewers: options.reviewers ?? [],
|
|
369
368
|
depends_on: options.dependsOn ?? [],
|
|
370
369
|
tags: options.tags ?? []
|
|
@@ -379,8 +378,7 @@ function writeSkill(workspacePath, title, body, actor, options = {}) {
|
|
|
379
378
|
owner: options.owner ?? existing.fields.owner ?? actor,
|
|
380
379
|
version: options.version ?? existing.fields.version ?? "0.1.0",
|
|
381
380
|
status,
|
|
382
|
-
distribution: options.distribution ?? existing.fields.distribution ?? "
|
|
383
|
-
tailscale_path: options.tailscalePath ?? existing.fields.tailscale_path,
|
|
381
|
+
distribution: options.distribution ?? existing.fields.distribution ?? "shared-vault",
|
|
384
382
|
reviewers: options.reviewers ?? existing.fields.reviewers ?? [],
|
|
385
383
|
depends_on: options.dependsOn ?? existing.fields.depends_on ?? [],
|
|
386
384
|
tags: options.tags ?? existing.fields.tags ?? []
|
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
swarm_exports,
|
|
15
15
|
trigger_exports,
|
|
16
16
|
workspace_exports
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NGRQ6T4O.js";
|
|
18
18
|
import {
|
|
19
19
|
autonomy_exports,
|
|
20
20
|
dispatch_exports,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
thread_audit_exports,
|
|
31
31
|
thread_exports,
|
|
32
32
|
trigger_engine_exports
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-BJVBE7F4.js";
|
|
34
34
|
|
|
35
35
|
// src/cli.ts
|
|
36
36
|
import fs from "fs";
|
package/dist/index.d.ts
CHANGED
|
@@ -614,11 +614,11 @@ interface WriteSkillOptions {
|
|
|
614
614
|
version?: string;
|
|
615
615
|
status?: 'draft' | 'proposed' | 'active' | 'deprecated' | 'archived';
|
|
616
616
|
distribution?: string;
|
|
617
|
-
tailscalePath?: string;
|
|
618
617
|
reviewers?: string[];
|
|
619
618
|
tags?: string[];
|
|
620
619
|
dependsOn?: string[];
|
|
621
620
|
expectedUpdatedAt?: string;
|
|
621
|
+
tailscalePath?: string;
|
|
622
622
|
}
|
|
623
623
|
interface ProposeSkillOptions {
|
|
624
624
|
proposalThread?: string;
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
swarm_exports,
|
|
17
17
|
trigger_exports,
|
|
18
18
|
workspace_exports
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-NGRQ6T4O.js";
|
|
20
20
|
import {
|
|
21
21
|
CursorCloudAdapter,
|
|
22
22
|
THREAD_STATUS_TRANSITIONS,
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
thread_audit_exports,
|
|
39
39
|
thread_exports,
|
|
40
40
|
trigger_engine_exports
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-BJVBE7F4.js";
|
|
42
42
|
export {
|
|
43
43
|
CursorCloudAdapter,
|
|
44
44
|
THREAD_STATUS_TRANSITIONS,
|
package/dist/mcp-server.js
CHANGED
package/package.json
CHANGED