loopable-cli 0.2.1 → 0.3.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/.output/nitro.json +1 -1
- package/.output/public/assets/_connectorId-CDCuSgpN.js +1 -0
- package/.output/public/assets/_loopId-DOnIsVTW.js +1 -0
- package/.output/public/assets/_taskId-BO5MZnlZ.js +1 -0
- package/.output/public/assets/agents-CBozi7oi.js +1 -0
- package/.output/public/assets/alert-Bn_wjgTX.js +1 -0
- package/.output/public/assets/button-K3ypIhAZ.js +1 -0
- package/.output/public/assets/card-DiVnaTIE.js +1 -0
- package/.output/public/assets/chevron-right-BrctLtFK.js +1 -0
- package/.output/public/assets/connection-status-DKWelvLO.js +1 -0
- package/.output/public/assets/connector-icon-CEbdE71G.js +1 -0
- package/.output/public/assets/connectors-JyX3IzJj.js +1 -0
- package/.output/public/assets/gaps-PjmcbaWo.js +1 -0
- package/.output/public/assets/inbox-CujRR0Cz.js +1 -0
- package/.output/public/assets/index-C9SQ_Baq.js +16 -0
- package/.output/public/assets/loop-form-Dw3cuTzw.js +1 -0
- package/.output/public/assets/loops-DcEfZa2_.js +1 -0
- package/.output/public/assets/manifests-yJpevyye.js +1 -0
- package/.output/public/assets/new-CwsnNuRW.js +1 -0
- package/.output/public/assets/page-bvnfRMum.js +1 -0
- package/.output/public/assets/play-yHLs4DjK.js +1 -0
- package/.output/public/assets/plus-Ber25lrU.js +1 -0
- package/.output/public/assets/preload-helper-BoU_7EQC.js +3 -0
- package/.output/public/assets/{refresh-cw-C3xBnKfy.js → refresh-cw-BzSY7M8I.js} +1 -1
- package/.output/public/assets/rotate-ccw-DLv9EfCX.js +1 -0
- package/.output/public/assets/runners-DzX-RU3i.js +2 -0
- package/.output/public/assets/select-C9grIFwG.js +1 -0
- package/.output/public/assets/setting-fields-DUc3npgh.js +3 -0
- package/.output/public/assets/styles-B9B98zLk.css +2 -0
- package/.output/public/assets/switch-DwABVI6d.js +1 -0
- package/.output/public/assets/task-list-Ddk8-qt7.js +1 -0
- package/.output/public/assets/textarea-Ds-gIYUQ.js +1 -0
- package/.output/public/assets/time-goBWd-5J.js +1 -0
- package/.output/public/assets/use-live-tasks-DZNNuECy.js +1 -0
- package/.output/public/assets/useCompositeListItem-P4Nmmn7j.js +1 -0
- package/.output/public/assets/usePositioner-B7i9Ejzh.js +1 -0
- package/.output/server/_chunks/ssr-renderer.mjs +1 -1
- package/.output/server/{_connectorId-C9yydJrC.mjs → _connectorId-COuQN02a.mjs} +198 -188
- package/.output/server/_libs/@base-ui/react+[...].mjs +1410 -804
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
- package/.output/server/_libs/lucide-react.mjs +93 -84
- package/.output/server/_libs/next-themes.mjs +1 -1
- package/.output/server/_libs/sonner.mjs +1 -1
- package/.output/server/_loopId-CZh6_Yhr.mjs +310 -0
- package/.output/server/_ssr/{agents-DG643yoJ.mjs → agents-B_qo1gpL.mjs} +195 -6
- package/.output/server/_ssr/{agents-C7B6RJ6-.mjs → agents-Bz10gz_m.mjs} +8 -8
- package/.output/server/_ssr/agents-CjbOUp3Z.mjs +206 -0
- package/.output/server/_ssr/{alert-DQvzE7bu.mjs → alert-C2WBWfzo.mjs} +2 -2
- package/.output/server/_ssr/card-r1cV-PCN.mjs +36 -0
- package/.output/server/_ssr/{client-BtVRVhQ2.mjs → client-Dk3SD8Il.mjs} +5 -1
- package/.output/server/_ssr/connection-status-BogAL-Fj.mjs +32 -0
- package/.output/server/_ssr/{connections-Df-aDpfJ.mjs → connections-Cqvb6Gw2.mjs} +372 -325
- package/.output/server/_ssr/connector-icon-DrhVbhs6.mjs +190 -0
- package/.output/server/_ssr/connectors-BfS5tQKr.mjs +81 -0
- package/.output/server/_ssr/{connectors-e0mf2pMs.mjs → connectors-DJI-rzPU.mjs} +10 -10
- package/.output/server/_ssr/{createServerRpc-DPDrnFdH.mjs → createServerRpc-DDrp2nLT.mjs} +2 -2
- package/.output/server/_ssr/{gaps-Cz76ZicM.mjs → gaps-CcvHiLcj.mjs} +15 -7
- package/.output/server/_ssr/inbox-D1ef761v.mjs +178 -0
- package/.output/server/_ssr/loop-form-DWwOR05R.mjs +346 -0
- package/.output/server/_ssr/{loops-D8WuK7Ke.mjs → loops-6WhUe_lc.mjs} +37 -27
- package/.output/server/_ssr/loops-DHPjzG-t.mjs +217 -0
- package/.output/server/_ssr/new-ChKBdcXJ.mjs +245 -0
- package/.output/server/_ssr/page-DZVxKvdn.mjs +120 -0
- package/.output/server/_ssr/{router-54IDWTVz.mjs → router-DdwREiOf.mjs} +162 -489
- package/.output/server/_ssr/runners-CK9Cx9fS.mjs +217 -0
- package/.output/server/_ssr/runners-CrznFPHt.mjs +140 -0
- package/.output/server/_ssr/{runners-Cj6z9Mqh.mjs → runners-W-pgo5yo.mjs} +5 -5
- package/.output/server/_ssr/{secrets-CRnpwGBh.mjs → secrets-CV5scFlt.mjs} +2 -2
- package/.output/server/_ssr/select-BtndHhHb.mjs +76 -0
- package/.output/server/_ssr/{setting-fields-DzBlslan.mjs → setting-fields-LNgywAW7.mjs} +25 -20
- package/.output/server/_ssr/ssr.mjs +43 -42
- package/.output/server/_ssr/{start-Vq3Oan3v.mjs → start-C_j-e4vF.mjs} +9 -4
- package/.output/server/_ssr/{switch-1pnd_bPJ.mjs → switch-odxNO_S4.mjs} +3 -3
- package/.output/server/_ssr/task-list-Dnmq_WeE.mjs +150 -0
- package/.output/server/_ssr/{tasks-Qtml5TlK.mjs → tasks-D-kXLgVP.mjs} +13 -13
- package/.output/server/_ssr/{tasks-BDqznm57.mjs → tasks-D7aUvA33.mjs} +44 -17
- package/.output/server/_ssr/{textarea-CHJTKtsJ.mjs → textarea-D2c_vTIC.mjs} +2 -2
- package/.output/server/_ssr/time-Cy8TZP0Z.mjs +13 -0
- package/.output/server/_ssr/use-live-tasks-BzhTkEOL.mjs +40 -0
- package/.output/server/_tanstack-start-manifest_v-2HUdn-2E.mjs +166 -0
- package/.output/server/_taskId-D3KkNJW1.mjs +263 -0
- package/.output/server/index.mjs +199 -164
- package/README.md +36 -6
- package/dist/cli.mjs +161 -8
- package/dist/dispatcher.mjs +671 -285
- package/dist/runner.mjs +333 -46
- package/drizzle/0025_prompt_tasks_done.sql +2 -0
- package/drizzle/0026_guidance_into_prompt.sql +3 -0
- package/drizzle/0027_relative_folders.sql +5 -0
- package/drizzle/0028_runner_version.sql +5 -0
- package/drizzle/meta/_journal.json +29 -1
- package/package.json +4 -2
- package/.output/public/assets/_connectorId-CkygNLny.js +0 -1
- package/.output/public/assets/_loopId-Cshlc5Ja.js +0 -1
- package/.output/public/assets/_taskId-BKDIJ_Fg.js +0 -1
- package/.output/public/assets/alert-BT2EVMJP.js +0 -1
- package/.output/public/assets/arrow-left-CWUZt6k2.js +0 -1
- package/.output/public/assets/arrow-right-dy_oOg_c.js +0 -1
- package/.output/public/assets/connection-status-DCqqmY_6.js +0 -1
- package/.output/public/assets/connector-icon-BUoK6Cru.js +0 -1
- package/.output/public/assets/connectors-CeLBtEtg.js +0 -1
- package/.output/public/assets/external-link-DC11orFA.js +0 -1
- package/.output/public/assets/gaps-BtFoD7mF.js +0 -1
- package/.output/public/assets/inbox-BYNjkNDJ.js +0 -1
- package/.output/public/assets/index-0yP3Jn_G.js +0 -18
- package/.output/public/assets/loader-B4Epchm_.js +0 -1
- package/.output/public/assets/loop-form-DnSJNc1k.js +0 -1
- package/.output/public/assets/loops-1CvbqO6m.js +0 -1
- package/.output/public/assets/new-m5NlqYQT.js +0 -1
- package/.output/public/assets/play-DD4xQgvi.js +0 -1
- package/.output/public/assets/preload-helper-CfdAYKD7.js +0 -3
- package/.output/public/assets/rolldown-runtime-CbXtAM7H.js +0 -1
- package/.output/public/assets/runners-D8QVl-Y6.js +0 -1
- package/.output/public/assets/select-Cppu-hti.js +0 -1
- package/.output/public/assets/setting-fields-bJ_gTG7Q.js +0 -3
- package/.output/public/assets/styles-ClTGaXU0.css +0 -2
- package/.output/public/assets/switch-hRIbNGOj.js +0 -1
- package/.output/public/assets/task-list-BAxjcVgr.js +0 -1
- package/.output/public/assets/textarea-Fyuzi6Vp.js +0 -1
- package/.output/public/assets/trash-2-BXZzBsoV.js +0 -1
- package/.output/public/assets/useValueChanged-VVyq4hb9.js +0 -1
- package/.output/server/_loopId-B0VG-eBC.mjs +0 -301
- package/.output/server/_ssr/connection-status-BZr3Y-IC.mjs +0 -31
- package/.output/server/_ssr/connector-icon-WvxwZ5TF.mjs +0 -56
- package/.output/server/_ssr/connectors-BU0IiRge.mjs +0 -107
- package/.output/server/_ssr/inbox-CAUBa1I3.mjs +0 -114
- package/.output/server/_ssr/loop-form-FqSaXiHl.mjs +0 -413
- package/.output/server/_ssr/loops-Dqoebe8q.mjs +0 -222
- package/.output/server/_ssr/new-bBsVaWD6.mjs +0 -169
- package/.output/server/_ssr/runners-D2UAdLyj.mjs +0 -106
- package/.output/server/_ssr/runners-DGWaVvWi.mjs +0 -116
- package/.output/server/_ssr/task-list-_qgBS9LU.mjs +0 -187
- package/.output/server/_tanstack-start-manifest_v-CvheE7ZF.mjs +0 -131
- package/.output/server/_taskId-V4QLBO2N.mjs +0 -256
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { i as __toESM } from "../_runtime.mjs";
|
|
2
|
+
import { K as require_jsx_runtime, q as require_react } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
|
+
import { p as useNavigate } from "../_libs/@tanstack/react-router+[...].mjs";
|
|
4
|
+
import { b as writerName, f as isInboxOnly, l as connectorWorkflow, o as connectorAction, s as connectorManifest, x as writers } from "./connections-Cqvb6Gw2.mjs";
|
|
5
|
+
import { t as AGENT_MANIFESTS } from "./agents-B_qo1gpL.mjs";
|
|
6
|
+
import { F as ChevronRight } from "../_libs/lucide-react.mjs";
|
|
7
|
+
import { n as toast } from "../_libs/sonner.mjs";
|
|
8
|
+
import { C as saveLoop, g as Input$1, v as Button$1 } from "./router-DdwREiOf.mjs";
|
|
9
|
+
import { n as Field, s as Section } from "./page-DZVxKvdn.mjs";
|
|
10
|
+
import { a as SelectValue, i as SelectTrigger, n as SelectContent, r as SelectItem, t as Select$1 } from "./select-BtndHhHb.mjs";
|
|
11
|
+
import { t as Textarea } from "./textarea-D2c_vTIC.mjs";
|
|
12
|
+
import { n as initialFieldValues, t as SettingFieldInputs } from "./setting-fields-LNgywAW7.mjs";
|
|
13
|
+
import { n as AlertDescription, r as AlertTitle, t as Alert } from "./alert-C2WBWfzo.mjs";
|
|
14
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/loop-form-DWwOR05R.js
|
|
15
|
+
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
16
|
+
var import_jsx_runtime = require_jsx_runtime();
|
|
17
|
+
var DEFAULT_AGENT = "__default";
|
|
18
|
+
/** Zero is stored as null: "as often as the dispatcher does" is not a duration. */
|
|
19
|
+
var POLL_CHOICES = [
|
|
20
|
+
{
|
|
21
|
+
value: "0",
|
|
22
|
+
label: "Every couple of minutes"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
value: String(6e4),
|
|
26
|
+
label: "Every minute"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
value: String(6e5),
|
|
30
|
+
label: "Every 10 minutes"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
value: String(18e5),
|
|
34
|
+
label: "Every 30 minutes"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: String(36e5),
|
|
38
|
+
label: "Every hour"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
value: String(144e5),
|
|
42
|
+
label: "Every 4 hours"
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
var RUNS_IN = {
|
|
46
|
+
checkout: "A fresh clone of the repository",
|
|
47
|
+
folder: "The folder this loop names",
|
|
48
|
+
temp: "A scratch folder with only what it was given"
|
|
49
|
+
};
|
|
50
|
+
var ANSWER = {
|
|
51
|
+
review: "A summary, plus comments on lines",
|
|
52
|
+
code: "A change to the code",
|
|
53
|
+
text: "One block of text"
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The parts of a workflow a loop cannot change: what it asks the service,
|
|
57
|
+
* where the agent runs, and how the answer is read. Folded away, since they
|
|
58
|
+
* are worth checking once and never editing.
|
|
59
|
+
*/
|
|
60
|
+
function WorkflowDetails({ workflow }) {
|
|
61
|
+
const rows = [];
|
|
62
|
+
if (workflow.watches) rows.push(["Looks for", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
|
|
63
|
+
className: "font-mono text-xs",
|
|
64
|
+
children: workflow.watches
|
|
65
|
+
})]);
|
|
66
|
+
rows.push(["Runs in", RUNS_IN[workflow.runsIn ?? "temp"]]);
|
|
67
|
+
rows.push(["Answer", ANSWER[workflow.answer]]);
|
|
68
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", {
|
|
69
|
+
suppressHydrationWarning: true,
|
|
70
|
+
className: "group text-sm",
|
|
71
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", {
|
|
72
|
+
className: "flex w-fit cursor-pointer list-none items-center gap-1 text-xs text-muted-foreground hover:text-foreground",
|
|
73
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { className: "size-3.5 transition-transform group-open:rotate-90" }), "Fixed by the trigger"]
|
|
74
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dl", {
|
|
75
|
+
className: "mt-2 grid grid-cols-[6rem_1fr] gap-x-3 gap-y-1.5 rounded-lg bg-muted/50 p-3 text-xs",
|
|
76
|
+
children: rows.map(([label, value]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
77
|
+
className: "contents",
|
|
78
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
79
|
+
className: "text-muted-foreground",
|
|
80
|
+
children: label
|
|
81
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: value })]
|
|
82
|
+
}, label))
|
|
83
|
+
})]
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A loop is one of a connector's workflows with its own answers to the
|
|
88
|
+
* questions it asks: what narrows it, which agent runs it and with what
|
|
89
|
+
* words, and where the answer goes.
|
|
90
|
+
*
|
|
91
|
+
* Serves a loop that exists and one that does not. A loop with no id has been
|
|
92
|
+
* chosen and not saved, so leaving this page is the end of it.
|
|
93
|
+
*/
|
|
94
|
+
function LoopForm({ loop, trigger }) {
|
|
95
|
+
const navigate = useNavigate();
|
|
96
|
+
const fresh = loop.id === null;
|
|
97
|
+
const connector = connectorManifest(loop.connectorId);
|
|
98
|
+
const workflow = connectorWorkflow(loop.connectorId, loop.workflowId);
|
|
99
|
+
const [name, setName] = (0, import_react.useState)(loop.name);
|
|
100
|
+
const [prompt, setPrompt] = (0, import_react.useState)(loop.prompt);
|
|
101
|
+
const [folder, setFolder] = (0, import_react.useState)(() => {
|
|
102
|
+
const saved = typeof loop.settings.folder === "string" ? loop.settings.folder : "";
|
|
103
|
+
return saved.startsWith("~/") ? saved.slice(2) : saved;
|
|
104
|
+
});
|
|
105
|
+
const [agentId, setAgentId] = (0, import_react.useState)(loop.agentId ?? DEFAULT_AGENT);
|
|
106
|
+
const [settings, setSettings] = (0, import_react.useState)(() => initialFieldValues(workflow?.settings ?? [], loop.settings));
|
|
107
|
+
const [pollEveryMs, setPollEveryMs] = (0, import_react.useState)(String(loop.pollEveryMs ?? 0));
|
|
108
|
+
const [actionConnectorId, setActionConnectorId] = (0, import_react.useState)(loop.actionConnectorId);
|
|
109
|
+
const [actionId, setActionId] = (0, import_react.useState)(loop.actionId);
|
|
110
|
+
const [actionTarget, setActionTarget] = (0, import_react.useState)(() => initialFieldValues(connectorAction(loop.actionConnectorId, loop.actionId)?.target ?? [], loop.actionTarget));
|
|
111
|
+
const [saving, setSaving] = (0, import_react.useState)(false);
|
|
112
|
+
const [written] = (0, import_react.useState)(loop.prompt.trim() !== "");
|
|
113
|
+
const action = connectorAction(actionConnectorId, actionId);
|
|
114
|
+
const sourceName = connector?.name ?? loop.connectorId;
|
|
115
|
+
const chooseDestination = (connectorId, id) => {
|
|
116
|
+
setActionConnectorId(connectorId);
|
|
117
|
+
setActionId(id);
|
|
118
|
+
setActionTarget(initialFieldValues(connectorAction(connectorId, id)?.target ?? [], {}));
|
|
119
|
+
};
|
|
120
|
+
if (!workflow) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, {
|
|
121
|
+
variant: "destructive",
|
|
122
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "This workflow is no longer offered" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AlertDescription, { children: [
|
|
123
|
+
sourceName,
|
|
124
|
+
" no longer has ",
|
|
125
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: loop.workflowId }),
|
|
126
|
+
", so this loop cannot run or be edited. You can still delete it."
|
|
127
|
+
] })]
|
|
128
|
+
});
|
|
129
|
+
const save = async () => {
|
|
130
|
+
setSaving(true);
|
|
131
|
+
try {
|
|
132
|
+
const saved = await saveLoop({ data: {
|
|
133
|
+
id: loop.id,
|
|
134
|
+
name,
|
|
135
|
+
connectorId: loop.connectorId,
|
|
136
|
+
workflowId: loop.workflowId,
|
|
137
|
+
prompt,
|
|
138
|
+
guidance: null,
|
|
139
|
+
agentId: agentId === DEFAULT_AGENT ? null : agentId,
|
|
140
|
+
settings: workflow.runsIn === "folder" ? {
|
|
141
|
+
...settings,
|
|
142
|
+
folder
|
|
143
|
+
} : settings,
|
|
144
|
+
actionConnectorId,
|
|
145
|
+
actionId,
|
|
146
|
+
actionTarget,
|
|
147
|
+
pollEveryMs: Number(pollEveryMs) || null,
|
|
148
|
+
enabled: loop.enabled
|
|
149
|
+
} });
|
|
150
|
+
toast.success(fresh ? `Added ${saved.name}` : `Saved ${saved.name}`);
|
|
151
|
+
await navigate({
|
|
152
|
+
to: "/loops/$loopId",
|
|
153
|
+
params: { loopId: saved.id }
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
toast.error(error instanceof Error ? error.message : String(error));
|
|
157
|
+
} finally {
|
|
158
|
+
setSaving(false);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const crosses = action && actionConnectorId !== loop.connectorId;
|
|
162
|
+
const flattens = action && workflow.answer === "review" && !action.accepts.includes("review");
|
|
163
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
164
|
+
className: "flex flex-col",
|
|
165
|
+
children: [
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
|
|
167
|
+
title: "When",
|
|
168
|
+
description: `When ${workflow.trigger}.`,
|
|
169
|
+
children: [
|
|
170
|
+
trigger,
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
172
|
+
label: "Name",
|
|
173
|
+
htmlFor: "loop-name",
|
|
174
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
|
|
175
|
+
id: "loop-name",
|
|
176
|
+
value: name,
|
|
177
|
+
onChange: (event) => setName(event.target.value)
|
|
178
|
+
})
|
|
179
|
+
}),
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingFieldInputs, {
|
|
181
|
+
fields: workflow.settings,
|
|
182
|
+
values: settings,
|
|
183
|
+
idPrefix: "setting-",
|
|
184
|
+
onChange: (key, value) => setSettings((prev) => ({
|
|
185
|
+
...prev,
|
|
186
|
+
[key]: value
|
|
187
|
+
}))
|
|
188
|
+
}),
|
|
189
|
+
loop.connectorId === "schedule" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
190
|
+
label: "Check",
|
|
191
|
+
htmlFor: "loop-every",
|
|
192
|
+
className: "sm:max-w-xs",
|
|
193
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
194
|
+
value: pollEveryMs,
|
|
195
|
+
onValueChange: (value) => value && setPollEveryMs(value),
|
|
196
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
197
|
+
id: "loop-every",
|
|
198
|
+
className: "w-full",
|
|
199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { children: (value) => POLL_CHOICES.find((choice) => choice.value === value)?.label ?? `Every ${Math.round(Number(value) / 6e4)} minutes` })
|
|
200
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: POLL_CHOICES.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
201
|
+
value: choice.value,
|
|
202
|
+
children: choice.label
|
|
203
|
+
}, choice.value)) })]
|
|
204
|
+
})
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(WorkflowDetails, { workflow })
|
|
207
|
+
]
|
|
208
|
+
}),
|
|
209
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
|
|
210
|
+
title: "Agent",
|
|
211
|
+
children: [
|
|
212
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
213
|
+
label: "Run with",
|
|
214
|
+
htmlFor: "loop-agent",
|
|
215
|
+
className: "sm:max-w-xs",
|
|
216
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
217
|
+
value: agentId,
|
|
218
|
+
onValueChange: (value) => value && setAgentId(value),
|
|
219
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
220
|
+
id: "loop-agent",
|
|
221
|
+
className: "w-full",
|
|
222
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { children: (value) => value === DEFAULT_AGENT ? "Default agent" : AGENT_MANIFESTS.find((entry) => entry.id === value)?.name ?? value })
|
|
223
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
224
|
+
value: DEFAULT_AGENT,
|
|
225
|
+
children: "Default agent"
|
|
226
|
+
}), AGENT_MANIFESTS.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
227
|
+
value: entry.id,
|
|
228
|
+
children: entry.name
|
|
229
|
+
}, entry.id))] })]
|
|
230
|
+
})
|
|
231
|
+
}),
|
|
232
|
+
workflow.runsIn === "folder" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
233
|
+
label: "Folder",
|
|
234
|
+
htmlFor: "loop-folder",
|
|
235
|
+
hint: "Inside the runner's home folder. The agent works here.",
|
|
236
|
+
className: "sm:max-w-sm",
|
|
237
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
238
|
+
className: "flex items-center rounded-lg border border-input focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50",
|
|
239
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
240
|
+
className: "pl-2.5 font-mono text-sm text-muted-foreground",
|
|
241
|
+
children: "~/"
|
|
242
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
|
|
243
|
+
id: "loop-folder",
|
|
244
|
+
value: folder,
|
|
245
|
+
placeholder: "code/web",
|
|
246
|
+
onChange: (event) => setFolder(event.target.value),
|
|
247
|
+
className: "border-0 pl-1 font-mono shadow-none focus-visible:ring-0"
|
|
248
|
+
})]
|
|
249
|
+
})
|
|
250
|
+
}) : null,
|
|
251
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
252
|
+
label: "Prompt",
|
|
253
|
+
htmlFor: "loop-prompt",
|
|
254
|
+
hint: written ? `Starts as “${workflow.name}”. Changes stay on this loop.` : void 0,
|
|
255
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Textarea, {
|
|
256
|
+
id: "loop-prompt",
|
|
257
|
+
rows: 10,
|
|
258
|
+
className: "font-mono text-xs",
|
|
259
|
+
placeholder: "What should the agent do?",
|
|
260
|
+
value: prompt,
|
|
261
|
+
onChange: (event) => setPrompt(event.target.value)
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
]
|
|
265
|
+
}),
|
|
266
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
|
|
267
|
+
title: "Answer",
|
|
268
|
+
children: [
|
|
269
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
270
|
+
className: "grid gap-4 sm:grid-cols-2",
|
|
271
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
272
|
+
label: "Send to",
|
|
273
|
+
htmlFor: "loop-writer",
|
|
274
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
275
|
+
value: actionConnectorId,
|
|
276
|
+
onValueChange: (value) => value && chooseDestination(value, connectorManifest(value).actions[0].id),
|
|
277
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
278
|
+
id: "loop-writer",
|
|
279
|
+
className: "w-full",
|
|
280
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { children: (value) => writerName(value) })
|
|
281
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: writers().map((writer) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
282
|
+
value: writer.id,
|
|
283
|
+
children: writerName(writer.id)
|
|
284
|
+
}, writer.id)) })]
|
|
285
|
+
})
|
|
286
|
+
}), isInboxOnly(actionConnectorId, actionId) ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
287
|
+
label: "As",
|
|
288
|
+
htmlFor: "loop-action",
|
|
289
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
290
|
+
value: actionId,
|
|
291
|
+
onValueChange: (value) => value && chooseDestination(actionConnectorId, value),
|
|
292
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
293
|
+
id: "loop-action",
|
|
294
|
+
className: "w-full",
|
|
295
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { children: (value) => connectorAction(actionConnectorId, value)?.name ?? value })
|
|
296
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: (connectorManifest(actionConnectorId)?.actions ?? []).map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
297
|
+
value: entry.id,
|
|
298
|
+
children: entry.name
|
|
299
|
+
}, entry.id)) })]
|
|
300
|
+
})
|
|
301
|
+
})]
|
|
302
|
+
}),
|
|
303
|
+
crosses && !isInboxOnly(actionConnectorId, actionId) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
|
|
304
|
+
className: "-mt-2 text-xs text-muted-foreground",
|
|
305
|
+
children: [
|
|
306
|
+
sourceName,
|
|
307
|
+
" and ",
|
|
308
|
+
writerName(actionConnectorId),
|
|
309
|
+
" both need a connection."
|
|
310
|
+
]
|
|
311
|
+
}) : flattens ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
312
|
+
className: "-mt-2 text-xs text-muted-foreground",
|
|
313
|
+
children: "Line comments arrive as text, with file and line written in."
|
|
314
|
+
}) : null,
|
|
315
|
+
action && action.target.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingFieldInputs, {
|
|
316
|
+
fields: action.target,
|
|
317
|
+
values: actionTarget,
|
|
318
|
+
idPrefix: "target-",
|
|
319
|
+
onChange: (key, value) => setActionTarget((prev) => ({
|
|
320
|
+
...prev,
|
|
321
|
+
[key]: value
|
|
322
|
+
}))
|
|
323
|
+
}) : null
|
|
324
|
+
]
|
|
325
|
+
}),
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
327
|
+
className: "flex items-center gap-2 border-t pt-6 md:pl-52",
|
|
328
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
329
|
+
onClick: save,
|
|
330
|
+
disabled: saving,
|
|
331
|
+
children: saving ? "Saving..." : fresh ? "Add loop" : "Save changes"
|
|
332
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
333
|
+
variant: "ghost",
|
|
334
|
+
onClick: () => navigate(fresh ? { to: "/loops/new" } : {
|
|
335
|
+
to: "/loops/$loopId",
|
|
336
|
+
params: { loopId: loop.id }
|
|
337
|
+
}),
|
|
338
|
+
disabled: saving,
|
|
339
|
+
children: "Cancel"
|
|
340
|
+
})]
|
|
341
|
+
})
|
|
342
|
+
]
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
export { LoopForm as t };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as createServerFn } from "./ssr.mjs";
|
|
2
2
|
import { d as and, f as eq, l as asc, p as inArray, v as sql } from "../_libs/drizzle-orm.mjs";
|
|
3
|
-
import { a as connections, c as loops, h as signals, s as db } from "./client-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { i as enqueueSignal, n as defaultAgentFor } from "./tasks-
|
|
8
|
-
import { t as createServerRpc } from "./createServerRpc-
|
|
3
|
+
import { a as connections, c as loops, h as signals, s as db } from "./client-Dk3SD8Il.mjs";
|
|
4
|
+
import { c as connectorRuntime, l as connectorWorkflow, o as connectorAction, s as connectorManifest, u as credentialForConnector } from "./connections-Cqvb6Gw2.mjs";
|
|
5
|
+
import { n as availableAgentIds } from "./runners-CK9Cx9fS.mjs";
|
|
6
|
+
import { i as listAgents, n as agentManifest, r as agentRuntime, s as settingsFor } from "./agents-B_qo1gpL.mjs";
|
|
7
|
+
import { i as enqueueSignal, n as defaultAgentFor, o as folderIsLegacy, p as normalizeFolder } from "./tasks-D7aUvA33.mjs";
|
|
8
|
+
import { t as createServerRpc } from "./createServerRpc-DDrp2nLT.mjs";
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import { mkdtempSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/loops-
|
|
13
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/loops-6WhUe_lc.js
|
|
14
14
|
var NAME_LIMIT = 80;
|
|
15
15
|
var PROMPT_LIMIT = 8e3;
|
|
16
16
|
var GUIDANCE_LIMIT = 4e3;
|
|
@@ -76,16 +76,22 @@ function validate(draft) {
|
|
|
76
76
|
if (prompt.length > PROMPT_LIMIT) throw new Error(`Keep what you ask under ${PROMPT_LIMIT} characters.`);
|
|
77
77
|
const guidance = draft.guidance?.trim() || null;
|
|
78
78
|
if (guidance && guidance.length > GUIDANCE_LIMIT) throw new Error(`Keep the guidance under ${GUIDANCE_LIMIT} characters.`);
|
|
79
|
+
let folder;
|
|
79
80
|
if (workflow.runsIn === "folder") {
|
|
80
|
-
const
|
|
81
|
-
|
|
81
|
+
const given = typeof draft.settings.folder === "string" ? draft.settings.folder : "";
|
|
82
|
+
folder = normalizeFolder(given);
|
|
83
|
+
if (!folder) throw new Error("Say which folder this should work in.");
|
|
84
|
+
if (folderIsLegacy(folder)) throw new Error("Give the folder relative to the runner's home, such as code/web.");
|
|
82
85
|
}
|
|
83
86
|
return {
|
|
84
87
|
...draft,
|
|
85
88
|
name,
|
|
86
89
|
prompt,
|
|
87
90
|
guidance,
|
|
88
|
-
settings:
|
|
91
|
+
settings: {
|
|
92
|
+
...cleanConditions(workflow.settings, draft.settings),
|
|
93
|
+
...folder ? { folder } : {}
|
|
94
|
+
},
|
|
89
95
|
actionTarget: cleanConditions(action.target, draft.actionTarget)
|
|
90
96
|
};
|
|
91
97
|
}
|
|
@@ -176,13 +182,15 @@ async function loopReadiness() {
|
|
|
176
182
|
const connected = await db().selectDistinct({ connectorId: connections.connectorId }).from(connections).all();
|
|
177
183
|
const available = await availableAgentIds();
|
|
178
184
|
const host = await availableAgentIds(true);
|
|
185
|
+
const folder = await availableAgentIds(false, 2);
|
|
179
186
|
const chosen = agents.find((agent) => agent.isDefault)?.agentId ?? null;
|
|
180
187
|
const defaultAgentId = (chosen && available.includes(chosen) ? chosen : null) ?? (available.length === 1 ? available[0] : null);
|
|
181
188
|
return {
|
|
182
189
|
connectedConnectorIds: connected.map((row) => row.connectorId),
|
|
183
190
|
defaultAgentId,
|
|
184
191
|
availableAgentIds: available,
|
|
185
|
-
hostAgentIds: host
|
|
192
|
+
hostAgentIds: host,
|
|
193
|
+
folderAgentIds: folder
|
|
186
194
|
};
|
|
187
195
|
}
|
|
188
196
|
var NOTHING_ASKED = "nothing in it was being asked of you";
|
|
@@ -299,12 +307,13 @@ async function pollLoop(loop, claimed) {
|
|
|
299
307
|
try {
|
|
300
308
|
const manifest = connectorManifest(loop.connectorId);
|
|
301
309
|
if (!manifest) throw new Error(`Unknown connector: ${loop.connectorId}`);
|
|
302
|
-
|
|
310
|
+
const workflow = connectorWorkflow(loop.connectorId, loop.workflowId);
|
|
311
|
+
if (!workflow) throw new Error(`${manifest.name} no longer offers ${loop.workflowId}.`);
|
|
303
312
|
const runtime = connectorRuntime(loop.connectorId);
|
|
304
313
|
if (!runtime.poll) throw new Error(`${manifest.name} cannot watch for anything yet.`);
|
|
305
314
|
const { credential } = await credentialForConnector(loop.connectorId);
|
|
306
315
|
const answer = await runtime.poll({
|
|
307
|
-
workflowId:
|
|
316
|
+
workflowId: workflow.triggerId,
|
|
308
317
|
settings: loop.settings,
|
|
309
318
|
credential,
|
|
310
319
|
cursor: loop.pollCursor ?? null
|
|
@@ -398,14 +407,15 @@ async function loopPollState(loopId) {
|
|
|
398
407
|
};
|
|
399
408
|
}
|
|
400
409
|
/**
|
|
401
|
-
* Run
|
|
402
|
-
*
|
|
403
|
-
*
|
|
410
|
+
* Run what the loop is holding: one item when `key` is given, or all of it.
|
|
411
|
+
* Asked for explicitly, because something held back for being too big is
|
|
412
|
+
* being run against the connector's advice.
|
|
404
413
|
*/
|
|
405
|
-
async function runBacklog(loopId) {
|
|
414
|
+
async function runBacklog(loopId, key) {
|
|
406
415
|
const loop = await db().select().from(loops).where(eq(loops.id, loopId)).get();
|
|
407
416
|
if (!loop) throw new Error("Loop not found");
|
|
408
|
-
const waiting = await db().select().from(signals).where(and(eq(signals.loopId, loopId), inArray(signals.outcome, [...WAITING]))).all();
|
|
417
|
+
const waiting = await db().select().from(signals).where(and(eq(signals.loopId, loopId), inArray(signals.outcome, [...WAITING]), key === void 0 ? void 0 : eq(signals.key, key))).all();
|
|
418
|
+
if (key !== void 0 && waiting.length === 0) throw new Error("That item is no longer waiting.");
|
|
409
419
|
for (const row of waiting) {
|
|
410
420
|
const task = await enqueueSignal({
|
|
411
421
|
loop,
|
|
@@ -451,13 +461,13 @@ var getLoopById_createServerFn_handler = createServerRpc({
|
|
|
451
461
|
name: "getLoopById",
|
|
452
462
|
filename: "src/server/functions/loops.ts"
|
|
453
463
|
}, (opts) => getLoopById.__executeServer(opts));
|
|
454
|
-
var getLoopById = createServerFn({ method: "GET" }).
|
|
464
|
+
var getLoopById = createServerFn({ method: "GET" }).validator((data) => data).handler(getLoopById_createServerFn_handler, async ({ data }) => await getLoop(data.id));
|
|
455
465
|
var saveLoop_createServerFn_handler = createServerRpc({
|
|
456
466
|
id: "e91fc2fd51633c7ca9184fea4beb66fe775ed0b4e6323111a4690da916a78b00",
|
|
457
467
|
name: "saveLoop",
|
|
458
468
|
filename: "src/server/functions/loops.ts"
|
|
459
469
|
}, (opts) => saveLoop.__executeServer(opts));
|
|
460
|
-
var saveLoop = createServerFn({ method: "POST" }).
|
|
470
|
+
var saveLoop = createServerFn({ method: "POST" }).validator(edit).handler(saveLoop_createServerFn_handler, async ({ data }) => {
|
|
461
471
|
const { id, ...values } = data;
|
|
462
472
|
return id ? await updateLoop(id, values) : await createLoop(values);
|
|
463
473
|
});
|
|
@@ -466,13 +476,13 @@ var toggleLoop_createServerFn_handler = createServerRpc({
|
|
|
466
476
|
name: "toggleLoop",
|
|
467
477
|
filename: "src/server/functions/loops.ts"
|
|
468
478
|
}, (opts) => toggleLoop.__executeServer(opts));
|
|
469
|
-
var toggleLoop = createServerFn({ method: "POST" }).
|
|
479
|
+
var toggleLoop = createServerFn({ method: "POST" }).validator((data) => data).handler(toggleLoop_createServerFn_handler, async ({ data }) => await setLoopEnabled(data.id, data.enabled));
|
|
470
480
|
var removeLoop_createServerFn_handler = createServerRpc({
|
|
471
481
|
id: "b5a89ca2d07f4ccf2827b5132ca52e7c7a42d584e702b0ab3963b2d5763c35b0",
|
|
472
482
|
name: "removeLoop",
|
|
473
483
|
filename: "src/server/functions/loops.ts"
|
|
474
484
|
}, (opts) => removeLoop.__executeServer(opts));
|
|
475
|
-
var removeLoop = createServerFn({ method: "POST" }).
|
|
485
|
+
var removeLoop = createServerFn({ method: "POST" }).validator((data) => data).handler(removeLoop_createServerFn_handler, async ({ data }) => {
|
|
476
486
|
await deleteLoop(data.id);
|
|
477
487
|
return await listLoops();
|
|
478
488
|
});
|
|
@@ -481,24 +491,24 @@ var reorderLoop_createServerFn_handler = createServerRpc({
|
|
|
481
491
|
name: "reorderLoop",
|
|
482
492
|
filename: "src/server/functions/loops.ts"
|
|
483
493
|
}, (opts) => reorderLoop.__executeServer(opts));
|
|
484
|
-
var reorderLoop = createServerFn({ method: "POST" }).
|
|
494
|
+
var reorderLoop = createServerFn({ method: "POST" }).validator((data) => data).handler(reorderLoop_createServerFn_handler, async ({ data }) => await moveLoop(data.id, data.direction));
|
|
485
495
|
var getLoopPollState_createServerFn_handler = createServerRpc({
|
|
486
496
|
id: "4fd3855e3e9ed954e102071a55b98d91651c9b1e353161f7223768ed6f2b8c28",
|
|
487
497
|
name: "getLoopPollState",
|
|
488
498
|
filename: "src/server/functions/loops.ts"
|
|
489
499
|
}, (opts) => getLoopPollState.__executeServer(opts));
|
|
490
|
-
var getLoopPollState = createServerFn({ method: "GET" }).
|
|
500
|
+
var getLoopPollState = createServerFn({ method: "GET" }).validator((data) => data).handler(getLoopPollState_createServerFn_handler, async ({ data }) => await loopPollState(data.id));
|
|
491
501
|
var runLoopBacklog_createServerFn_handler = createServerRpc({
|
|
492
502
|
id: "65494cbfd06143dbd9a012808fbba21163d9902e387869503fb8b68b0674902b",
|
|
493
503
|
name: "runLoopBacklog",
|
|
494
504
|
filename: "src/server/functions/loops.ts"
|
|
495
505
|
}, (opts) => runLoopBacklog.__executeServer(opts));
|
|
496
|
-
var runLoopBacklog = createServerFn({ method: "POST" }).
|
|
506
|
+
var runLoopBacklog = createServerFn({ method: "POST" }).validator((data) => data).handler(runLoopBacklog_createServerFn_handler, async ({ data }) => ({ queued: await runBacklog(data.id, data.key) }));
|
|
497
507
|
var lookLoopNow_createServerFn_handler = createServerRpc({
|
|
498
508
|
id: "965ff21ee2f1e1f5a1cb78d50570cbad6f58ccdbdcc7955f02f816a9c0684f8e",
|
|
499
509
|
name: "lookLoopNow",
|
|
500
510
|
filename: "src/server/functions/loops.ts"
|
|
501
511
|
}, (opts) => lookLoopNow.__executeServer(opts));
|
|
502
|
-
var lookLoopNow = createServerFn({ method: "POST" }).
|
|
512
|
+
var lookLoopNow = createServerFn({ method: "POST" }).validator((data) => data).handler(lookLoopNow_createServerFn_handler, async ({ data }) => await lookNow(data.id));
|
|
503
513
|
//#endregion
|
|
504
514
|
export { getLoopById_createServerFn_handler, getLoopPollState_createServerFn_handler, getLoopReadiness_createServerFn_handler, getLoopsPage_createServerFn_handler, lookLoopNow_createServerFn_handler, removeLoop_createServerFn_handler, reorderLoop_createServerFn_handler, runLoopBacklog_createServerFn_handler, saveLoop_createServerFn_handler, toggleLoop_createServerFn_handler };
|