loopable-cli 0.1.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.
Files changed (133) hide show
  1. package/.output/nitro.json +17 -0
  2. package/.output/public/apple-touch-icon.png +0 -0
  3. package/.output/public/assets/_connectorId-BWjYn5tm.js +1 -0
  4. package/.output/public/assets/_loopId-Ds4RkyEc.js +1 -0
  5. package/.output/public/assets/_taskId-BOzICXDf.js +1 -0
  6. package/.output/public/assets/alert-Bn9-Zm0l.js +1 -0
  7. package/.output/public/assets/arrow-left-BF9juV9T.js +1 -0
  8. package/.output/public/assets/arrow-right-CzqvnOY1.js +1 -0
  9. package/.output/public/assets/button-HCY6DCY-.js +1 -0
  10. package/.output/public/assets/connection-status-CYZB8kLy.js +1 -0
  11. package/.output/public/assets/connector-icon-BZ_MUJV_.js +1 -0
  12. package/.output/public/assets/connectors-BvzttfSu.js +1 -0
  13. package/.output/public/assets/connectors-DdJNwRN_.js +1 -0
  14. package/.output/public/assets/external-link-D46X-bXa.js +1 -0
  15. package/.output/public/assets/gaps-D-I6xiDc.js +1 -0
  16. package/.output/public/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  17. package/.output/public/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  18. package/.output/public/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  19. package/.output/public/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  20. package/.output/public/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  21. package/.output/public/assets/inbox-BUUu9xxE.js +1 -0
  22. package/.output/public/assets/index-ztzex0FN.js +10 -0
  23. package/.output/public/assets/loader-CcBl2u8m.js +1 -0
  24. package/.output/public/assets/loop-form-dB3CLcZb.js +1 -0
  25. package/.output/public/assets/loops-DRunQrxL.js +1 -0
  26. package/.output/public/assets/loops-oSdqMd29.js +1 -0
  27. package/.output/public/assets/manifests-DNMqf7Vi.js +7 -0
  28. package/.output/public/assets/new-uyFxVjuB.js +1 -0
  29. package/.output/public/assets/preload-helper-ORbuV86A.js +3 -0
  30. package/.output/public/assets/runners-DSU3r5Ww.js +1 -0
  31. package/.output/public/assets/setting-fields-ixkpdBb-.js +3 -0
  32. package/.output/public/assets/styles-DZL5V1o7.css +2 -0
  33. package/.output/public/assets/switch-d5ummmHY.js +1 -0
  34. package/.output/public/assets/task-list-BpOStt9v.js +1 -0
  35. package/.output/public/assets/tasks-B8MsKgic.js +1 -0
  36. package/.output/public/assets/trash-2-D6u6NpzO.js +1 -0
  37. package/.output/public/favicon.svg +9 -0
  38. package/.output/server/_chunks/ssr-renderer.mjs +26 -0
  39. package/.output/server/_connectorId-8nb5yOzG.mjs +421 -0
  40. package/.output/server/_libs/@base-ui/react+[...].mjs +12841 -0
  41. package/.output/server/_libs/@tanstack/react-router+[...].mjs +14349 -0
  42. package/.output/server/_libs/class-variance-authority+clsx.mjs +69 -0
  43. package/.output/server/_libs/dijkstrajs.mjs +118 -0
  44. package/.output/server/_libs/drizzle-orm.mjs +4349 -0
  45. package/.output/server/_libs/h3+rou3+srvx.mjs +1361 -0
  46. package/.output/server/_libs/lucide-react.mjs +911 -0
  47. package/.output/server/_libs/next-themes.mjs +53 -0
  48. package/.output/server/_libs/pngjs.mjs +1680 -0
  49. package/.output/server/_libs/qrcode.mjs +2583 -0
  50. package/.output/server/_libs/sonner.mjs +955 -0
  51. package/.output/server/_libs/tailwind-merge.mjs +3380 -0
  52. package/.output/server/_libs/tanstack__history.mjs +341 -0
  53. package/.output/server/_libs/ufo.mjs +64 -0
  54. package/.output/server/_loopId-BsUL1SeL.mjs +272 -0
  55. package/.output/server/_runtime.mjs +35 -0
  56. package/.output/server/_ssr/access-zIl15o8y.mjs +42 -0
  57. package/.output/server/_ssr/agents-Btql102J.mjs +657 -0
  58. package/.output/server/_ssr/agents-DAOZPgO2.mjs +76 -0
  59. package/.output/server/_ssr/alert-NEiOCTOl.mjs +37 -0
  60. package/.output/server/_ssr/callback-CUINvl7M.mjs +62 -0
  61. package/.output/server/_ssr/client-CKkOfh-s.mjs +335 -0
  62. package/.output/server/_ssr/connection-status-Bi5peUAk.mjs +31 -0
  63. package/.output/server/_ssr/connections-qnw2GVlP.mjs +2542 -0
  64. package/.output/server/_ssr/connector-icon-DZXQLLFo.mjs +37 -0
  65. package/.output/server/_ssr/connectors-BHNwuIMj.mjs +106 -0
  66. package/.output/server/_ssr/connectors-C28g0i4c.mjs +83 -0
  67. package/.output/server/_ssr/createServerRpc-DPDrnFdH.mjs +12 -0
  68. package/.output/server/_ssr/empty-plugin-adapters-BJ4m9L8g.mjs +5 -0
  69. package/.output/server/_ssr/gaps-RAFSXLZf.mjs +53 -0
  70. package/.output/server/_ssr/inbox-k5zHergU.mjs +35 -0
  71. package/.output/server/_ssr/loop-form-DlObSewZ.mjs +412 -0
  72. package/.output/server/_ssr/loops-APFcP0y6.mjs +311 -0
  73. package/.output/server/_ssr/loops-xt2Bn7_q.mjs +222 -0
  74. package/.output/server/_ssr/new-DfKyd2Wa.mjs +169 -0
  75. package/.output/server/_ssr/router-3WmpE5b_.mjs +1553 -0
  76. package/.output/server/_ssr/runners-By-mwc3F.mjs +32 -0
  77. package/.output/server/_ssr/runners-DI_NxpHC.mjs +116 -0
  78. package/.output/server/_ssr/runners-DtXs4Q8a.mjs +106 -0
  79. package/.output/server/_ssr/secrets-Hqti-niS.mjs +199 -0
  80. package/.output/server/_ssr/setting-fields-8vKFj4df.mjs +92 -0
  81. package/.output/server/_ssr/ssr.mjs +6605 -0
  82. package/.output/server/_ssr/start-Bdc2GJUI.mjs +51 -0
  83. package/.output/server/_ssr/switch-ReNglgH6.mjs +18 -0
  84. package/.output/server/_ssr/task-list-CUITIqkb.mjs +186 -0
  85. package/.output/server/_ssr/tasks-SAjNovX6.mjs +110 -0
  86. package/.output/server/_ssr/tasks-vcoodp_D.mjs +533 -0
  87. package/.output/server/_tanstack-start-manifest_v-C0cP5F0M.mjs +125 -0
  88. package/.output/server/_taskId-CXS3lod0.mjs +249 -0
  89. package/.output/server/index.mjs +541 -0
  90. package/README.md +81 -0
  91. package/dist/cli.mjs +165 -0
  92. package/dist/dispatcher.mjs +9871 -0
  93. package/dist/runner.mjs +657 -0
  94. package/drizzle/0000_cold_demogoblin.sql +29 -0
  95. package/drizzle/0001_fancy_blonde_phantom.sql +13 -0
  96. package/drizzle/0002_spooky_smiling_tiger.sql +16 -0
  97. package/drizzle/0003_small_golden_guardian.sql +25 -0
  98. package/drizzle/0004_wonderful_thunderbolts.sql +39 -0
  99. package/drizzle/0005_named_workflows.sql +7 -0
  100. package/drizzle/0006_signals.sql +18 -0
  101. package/drizzle/0007_review_comments.sql +1 -0
  102. package/drizzle/0008_held_signals.sql +1 -0
  103. package/drizzle/0009_work_item_ref.sql +58 -0
  104. package/drizzle/0010_signal_payload.sql +2 -0
  105. package/drizzle/0011_rule_poll_cursor.sql +1 -0
  106. package/drizzle/0012_loops.sql +63 -0
  107. package/drizzle/0013_loop_owns_action_and_prompt.sql +154 -0
  108. package/drizzle/0014_loop_poll_every.sql +4 -0
  109. package/drizzle/0015_machines.sql +10 -0
  110. package/drizzle/0016_task_machine.sql +1 -0
  111. package/drizzle/0017_loop_machine.sql +1 -0
  112. package/drizzle/0018_runners.sql +1 -0
  113. package/drizzle/0019_task_runner.sql +1 -0
  114. package/drizzle/0020_loop_runner.sql +1 -0
  115. package/drizzle/0021_drop_runner_kind.sql +1 -0
  116. package/drizzle/0022_drop_loop_runner.sql +1 -0
  117. package/drizzle/0023_shared_host.sql +6 -0
  118. package/drizzle/meta/0000_snapshot.json +206 -0
  119. package/drizzle/meta/0001_snapshot.json +284 -0
  120. package/drizzle/meta/0002_snapshot.json +390 -0
  121. package/drizzle/meta/0003_snapshot.json +566 -0
  122. package/drizzle/meta/0004_snapshot.json +633 -0
  123. package/drizzle/meta/0005_snapshot.json +626 -0
  124. package/drizzle/meta/0006_snapshot.json +752 -0
  125. package/drizzle/meta/0007_snapshot.json +759 -0
  126. package/drizzle/meta/0008_snapshot.json +766 -0
  127. package/drizzle/meta/0009_snapshot.json +752 -0
  128. package/drizzle/meta/0010_snapshot.json +766 -0
  129. package/drizzle/meta/0011_snapshot.json +773 -0
  130. package/drizzle/meta/0012_snapshot.json +773 -0
  131. package/drizzle/meta/0013_snapshot.json +817 -0
  132. package/drizzle/meta/_journal.json +174 -0
  133. package/package.json +88 -0
@@ -0,0 +1,341 @@
1
+ //#region node_modules/.pnpm/@tanstack+history@1.162.1/node_modules/@tanstack/history/dist/esm/index.js
2
+ var stateIndexKey = "__TSR_index";
3
+ var popStateEvent = "popstate";
4
+ var beforeUnloadEvent = "beforeunload";
5
+ function createHistory(opts) {
6
+ let location = opts.getLocation();
7
+ const subscribers = /* @__PURE__ */ new Set();
8
+ const notify = (action) => {
9
+ location = opts.getLocation();
10
+ subscribers.forEach((subscriber) => subscriber({
11
+ location,
12
+ action
13
+ }));
14
+ };
15
+ const handleIndexChange = (action) => {
16
+ if (opts.notifyOnIndexChange ?? true) notify(action);
17
+ else location = opts.getLocation();
18
+ };
19
+ const tryNavigation = async ({ task, navigateOpts, ...actionInfo }) => {
20
+ if (navigateOpts?.ignoreBlocker ?? false) {
21
+ task();
22
+ return;
23
+ }
24
+ const blockers = opts.getBlockers?.() ?? [];
25
+ const isPushOrReplace = actionInfo.type === "PUSH" || actionInfo.type === "REPLACE";
26
+ if (typeof document !== "undefined" && blockers.length && isPushOrReplace) for (const blocker of blockers) {
27
+ const nextLocation = parseHref(actionInfo.path, actionInfo.state);
28
+ if (await blocker.blockerFn({
29
+ currentLocation: location,
30
+ nextLocation,
31
+ action: actionInfo.type
32
+ })) {
33
+ opts.onBlocked?.();
34
+ return;
35
+ }
36
+ }
37
+ task();
38
+ };
39
+ return {
40
+ get location() {
41
+ return location;
42
+ },
43
+ get length() {
44
+ return opts.getLength();
45
+ },
46
+ subscribers,
47
+ subscribe: (cb) => {
48
+ subscribers.add(cb);
49
+ return () => {
50
+ subscribers.delete(cb);
51
+ };
52
+ },
53
+ push: (path, state, navigateOpts) => {
54
+ const currentIndex = location.state[stateIndexKey];
55
+ state = assignKeyAndIndex(currentIndex + 1, state);
56
+ tryNavigation({
57
+ task: () => {
58
+ opts.pushState(path, state);
59
+ notify({ type: "PUSH" });
60
+ },
61
+ navigateOpts,
62
+ type: "PUSH",
63
+ path,
64
+ state
65
+ });
66
+ },
67
+ replace: (path, state, navigateOpts) => {
68
+ const currentIndex = location.state[stateIndexKey];
69
+ state = assignKeyAndIndex(currentIndex, state);
70
+ tryNavigation({
71
+ task: () => {
72
+ opts.replaceState(path, state);
73
+ notify({ type: "REPLACE" });
74
+ },
75
+ navigateOpts,
76
+ type: "REPLACE",
77
+ path,
78
+ state
79
+ });
80
+ },
81
+ go: (index, navigateOpts) => {
82
+ tryNavigation({
83
+ task: () => {
84
+ opts.go(index);
85
+ handleIndexChange({
86
+ type: "GO",
87
+ index
88
+ });
89
+ },
90
+ navigateOpts,
91
+ type: "GO"
92
+ });
93
+ },
94
+ back: (navigateOpts) => {
95
+ tryNavigation({
96
+ task: () => {
97
+ opts.back(navigateOpts?.ignoreBlocker ?? false);
98
+ handleIndexChange({ type: "BACK" });
99
+ },
100
+ navigateOpts,
101
+ type: "BACK"
102
+ });
103
+ },
104
+ forward: (navigateOpts) => {
105
+ tryNavigation({
106
+ task: () => {
107
+ opts.forward(navigateOpts?.ignoreBlocker ?? false);
108
+ handleIndexChange({ type: "FORWARD" });
109
+ },
110
+ navigateOpts,
111
+ type: "FORWARD"
112
+ });
113
+ },
114
+ canGoBack: () => location.state[stateIndexKey] !== 0,
115
+ createHref: (str) => opts.createHref(str),
116
+ block: (blocker) => {
117
+ if (!opts.setBlockers) return () => {};
118
+ const blockers = opts.getBlockers?.() ?? [];
119
+ opts.setBlockers([...blockers, blocker]);
120
+ return () => {
121
+ const blockers = opts.getBlockers?.() ?? [];
122
+ opts.setBlockers?.(blockers.filter((b) => b !== blocker));
123
+ };
124
+ },
125
+ flush: () => opts.flush?.(),
126
+ destroy: () => opts.destroy?.(),
127
+ notify
128
+ };
129
+ }
130
+ function assignKeyAndIndex(index, state) {
131
+ if (!state) state = {};
132
+ const key = createRandomKey();
133
+ return {
134
+ ...state,
135
+ key,
136
+ __TSR_key: key,
137
+ [stateIndexKey]: index
138
+ };
139
+ }
140
+ /**
141
+ * Creates a history object that can be used to interact with the browser's
142
+ * navigation. This is a lightweight API wrapping the browser's native methods.
143
+ * It is designed to work with TanStack Router, but could be used as a standalone API as well.
144
+ * IMPORTANT: This API implements history throttling via a microtask to prevent
145
+ * excessive calls to the history API. In some browsers, calling history.pushState or
146
+ * history.replaceState in quick succession can cause the browser to ignore subsequent
147
+ * calls. This API smooths out those differences and ensures that your application
148
+ * state will *eventually* match the browser state. In most cases, this is not a problem,
149
+ * but if you need to ensure that the browser state is up to date, you can use the
150
+ * `history.flush` method to immediately flush all pending state changes to the browser URL.
151
+ * @param opts
152
+ * @param opts.getHref A function that returns the current href (path + search + hash)
153
+ * @param opts.createHref A function that takes a path and returns a href (path + search + hash)
154
+ * @returns A history instance
155
+ */
156
+ function createBrowserHistory(opts) {
157
+ const win = opts?.window ?? (typeof document !== "undefined" ? window : void 0);
158
+ const originalPushState = win.history.pushState;
159
+ const originalReplaceState = win.history.replaceState;
160
+ let blockers = [];
161
+ const _getBlockers = () => blockers;
162
+ const _setBlockers = (newBlockers) => blockers = newBlockers;
163
+ const createHref = opts?.createHref ?? ((path) => path);
164
+ const parseLocation = opts?.parseLocation ?? (() => parseHref(`${win.location.pathname}${win.location.search}${win.location.hash}`, win.history.state));
165
+ if (!win.history.state?.__TSR_key && !win.history.state?.key) {
166
+ const addedKey = createRandomKey();
167
+ win.history.replaceState({
168
+ [stateIndexKey]: 0,
169
+ key: addedKey,
170
+ __TSR_key: addedKey
171
+ }, "");
172
+ }
173
+ let currentLocation = parseLocation();
174
+ let rollbackLocation;
175
+ let nextPopIsGo = false;
176
+ let ignoreNextPop = false;
177
+ let skipBlockerNextPop = false;
178
+ let ignoreNextBeforeUnload = false;
179
+ const getLocation = () => currentLocation;
180
+ let next;
181
+ const flush = () => {
182
+ if (!next) return;
183
+ history._ignoreSubscribers = true;
184
+ (next[2] ? win.history.pushState : win.history.replaceState)(next[1], "", next[0]);
185
+ history._ignoreSubscribers = false;
186
+ next = void 0;
187
+ rollbackLocation = void 0;
188
+ };
189
+ const queueHistoryAction = (isPush, destHref, state) => {
190
+ const href = createHref(destHref);
191
+ const hasPendingAction = !!next;
192
+ if (!hasPendingAction) rollbackLocation = currentLocation;
193
+ currentLocation = parseHref(destHref, state);
194
+ next = [
195
+ href,
196
+ state,
197
+ next?.[2] || isPush
198
+ ];
199
+ if (!hasPendingAction) queueMicrotask(() => flush());
200
+ };
201
+ const onPushPop = (type) => {
202
+ currentLocation = parseLocation();
203
+ history.notify({ type });
204
+ };
205
+ const onPushPopEvent = async () => {
206
+ if (ignoreNextPop) {
207
+ ignoreNextPop = false;
208
+ return;
209
+ }
210
+ const nextLocation = parseLocation();
211
+ const delta = nextLocation.state[stateIndexKey] - currentLocation.state[stateIndexKey];
212
+ const isForward = delta === 1;
213
+ const isBack = delta === -1;
214
+ const isGo = !isForward && !isBack || nextPopIsGo;
215
+ nextPopIsGo = false;
216
+ const action = isGo ? "GO" : isBack ? "BACK" : "FORWARD";
217
+ const notify = isGo ? {
218
+ type: "GO",
219
+ index: delta
220
+ } : { type: isBack ? "BACK" : "FORWARD" };
221
+ if (skipBlockerNextPop) skipBlockerNextPop = false;
222
+ else {
223
+ const blockers = _getBlockers();
224
+ if (typeof document !== "undefined" && blockers.length) {
225
+ for (const blocker of blockers) if (await blocker.blockerFn({
226
+ currentLocation,
227
+ nextLocation,
228
+ action
229
+ })) {
230
+ ignoreNextPop = true;
231
+ win.history.go(1);
232
+ history.notify(notify);
233
+ return;
234
+ }
235
+ }
236
+ }
237
+ currentLocation = parseLocation();
238
+ history.notify(notify);
239
+ };
240
+ const onBeforeUnload = (e) => {
241
+ if (ignoreNextBeforeUnload) {
242
+ ignoreNextBeforeUnload = false;
243
+ return;
244
+ }
245
+ let shouldBlock = false;
246
+ const blockers = _getBlockers();
247
+ if (typeof document !== "undefined" && blockers.length) for (const blocker of blockers) {
248
+ const shouldHaveBeforeUnload = blocker.enableBeforeUnload ?? true;
249
+ if (shouldHaveBeforeUnload === true) {
250
+ shouldBlock = true;
251
+ break;
252
+ }
253
+ if (typeof shouldHaveBeforeUnload === "function" && shouldHaveBeforeUnload() === true) {
254
+ shouldBlock = true;
255
+ break;
256
+ }
257
+ }
258
+ if (shouldBlock) {
259
+ e.preventDefault();
260
+ return e.returnValue = "";
261
+ }
262
+ };
263
+ const history = createHistory({
264
+ getLocation,
265
+ getLength: () => win.history.length,
266
+ pushState: (href, state) => queueHistoryAction(true, href, state),
267
+ replaceState: (href, state) => queueHistoryAction(false, href, state),
268
+ back: (ignoreBlocker) => {
269
+ if (ignoreBlocker) skipBlockerNextPop = true;
270
+ ignoreNextBeforeUnload = true;
271
+ return win.history.back();
272
+ },
273
+ forward: (ignoreBlocker) => {
274
+ if (ignoreBlocker) skipBlockerNextPop = true;
275
+ ignoreNextBeforeUnload = true;
276
+ win.history.forward();
277
+ },
278
+ go: (n) => {
279
+ nextPopIsGo = true;
280
+ win.history.go(n);
281
+ },
282
+ createHref: (href) => createHref(href),
283
+ flush,
284
+ destroy: () => {
285
+ win.history.pushState = originalPushState;
286
+ win.history.replaceState = originalReplaceState;
287
+ win.removeEventListener(beforeUnloadEvent, onBeforeUnload, { capture: true });
288
+ win.removeEventListener(popStateEvent, onPushPopEvent);
289
+ },
290
+ onBlocked: () => {
291
+ if (rollbackLocation && currentLocation !== rollbackLocation) currentLocation = rollbackLocation;
292
+ },
293
+ getBlockers: _getBlockers,
294
+ setBlockers: _setBlockers,
295
+ notifyOnIndexChange: false
296
+ });
297
+ win.addEventListener(beforeUnloadEvent, onBeforeUnload, { capture: true });
298
+ win.addEventListener(popStateEvent, onPushPopEvent);
299
+ win.history.pushState = function(...args) {
300
+ const res = originalPushState.apply(win.history, args);
301
+ if (!history._ignoreSubscribers) onPushPop("PUSH");
302
+ return res;
303
+ };
304
+ win.history.replaceState = function(...args) {
305
+ const res = originalReplaceState.apply(win.history, args);
306
+ if (!history._ignoreSubscribers) onPushPop("REPLACE");
307
+ return res;
308
+ };
309
+ return history;
310
+ }
311
+ /**
312
+ * Sanitize a path to prevent open redirect vulnerabilities.
313
+ * Removes control characters and collapses leading double slashes.
314
+ */
315
+ function sanitizePath(path) {
316
+ let sanitized = path.replace(/[\x00-\x1f\x7f]/g, "");
317
+ if (sanitized.startsWith("//")) sanitized = "/" + sanitized.replace(/^\/+/, "");
318
+ return sanitized;
319
+ }
320
+ function parseHref(href, state) {
321
+ const sanitizedHref = sanitizePath(href);
322
+ const hashIndex = sanitizedHref.indexOf("#");
323
+ const searchIndex = sanitizedHref.indexOf("?");
324
+ const addedKey = createRandomKey();
325
+ return {
326
+ href: sanitizedHref,
327
+ pathname: sanitizedHref.substring(0, hashIndex > 0 ? searchIndex > 0 ? Math.min(hashIndex, searchIndex) : hashIndex : searchIndex > 0 ? searchIndex : sanitizedHref.length),
328
+ hash: hashIndex > -1 ? sanitizedHref.substring(hashIndex) : "",
329
+ search: searchIndex > -1 ? sanitizedHref.slice(searchIndex, hashIndex === -1 ? void 0 : hashIndex) : "",
330
+ state: state || {
331
+ [stateIndexKey]: 0,
332
+ key: addedKey,
333
+ __TSR_key: addedKey
334
+ }
335
+ };
336
+ }
337
+ function createRandomKey() {
338
+ return (Math.random() + 1).toString(36).substring(7);
339
+ }
340
+ //#endregion
341
+ export { parseHref as n, createBrowserHistory as t };
@@ -0,0 +1,64 @@
1
+ String.fromCharCode;
2
+ var ENC_SLASH_RE = /%2f/gi;
3
+ function decode(text = "") {
4
+ try {
5
+ return decodeURIComponent("" + text);
6
+ } catch {
7
+ return "" + text;
8
+ }
9
+ }
10
+ function decodePath(text) {
11
+ return decode(text.replace(ENC_SLASH_RE, "%252F"));
12
+ }
13
+ var TRAILING_SLASH_RE = /\/$|\/\?|\/#/;
14
+ var JOIN_LEADING_SLASH_RE = /^\.?\//;
15
+ function hasTrailingSlash(input = "", respectQueryAndFragment) {
16
+ if (!respectQueryAndFragment) return input.endsWith("/");
17
+ return TRAILING_SLASH_RE.test(input);
18
+ }
19
+ function withoutTrailingSlash(input = "", respectQueryAndFragment) {
20
+ if (!respectQueryAndFragment) return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || "/";
21
+ if (!hasTrailingSlash(input, true)) return input || "/";
22
+ let path = input;
23
+ let fragment = "";
24
+ const fragmentIndex = input.indexOf("#");
25
+ if (fragmentIndex !== -1) {
26
+ path = input.slice(0, fragmentIndex);
27
+ fragment = input.slice(fragmentIndex);
28
+ }
29
+ const [s0, ...s] = path.split("?");
30
+ return ((s0.endsWith("/") ? s0.slice(0, -1) : s0) || "/") + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
31
+ }
32
+ function withTrailingSlash(input = "", respectQueryAndFragment) {
33
+ if (!respectQueryAndFragment) return input.endsWith("/") ? input : input + "/";
34
+ if (hasTrailingSlash(input, true)) return input || "/";
35
+ let path = input;
36
+ let fragment = "";
37
+ const fragmentIndex = input.indexOf("#");
38
+ if (fragmentIndex !== -1) {
39
+ path = input.slice(0, fragmentIndex);
40
+ fragment = input.slice(fragmentIndex);
41
+ if (!path) return fragment;
42
+ }
43
+ const [s0, ...s] = path.split("?");
44
+ return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
45
+ }
46
+ function hasLeadingSlash(input = "") {
47
+ return input.startsWith("/");
48
+ }
49
+ function withLeadingSlash(input = "") {
50
+ return hasLeadingSlash(input) ? input : "/" + input;
51
+ }
52
+ function isNonEmptyURL(url) {
53
+ return url && url !== "/";
54
+ }
55
+ function joinURL(base, ...input) {
56
+ let url = base || "";
57
+ for (const segment of input.filter((url2) => isNonEmptyURL(url2))) if (url) {
58
+ const _segment = segment.replace(JOIN_LEADING_SLASH_RE, "");
59
+ url = withTrailingSlash(url) + _segment;
60
+ } else url = segment;
61
+ return url;
62
+ }
63
+ //#endregion
64
+ export { withoutTrailingSlash as i, joinURL as n, withLeadingSlash as r, decodePath as t };
@@ -0,0 +1,272 @@
1
+ import { i as __toESM } from "./_runtime.mjs";
2
+ import { U as require_jsx_runtime, W as require_react, i as TabsRoot, n as TabsPanel, r as TabsTab, t as TabsList$1 } from "./_libs/@base-ui/react+[...].mjs";
3
+ import { f as Link, m as useRouter } from "./_libs/@tanstack/react-router+[...].mjs";
4
+ import { t as cva } from "./_libs/class-variance-authority+clsx.mjs";
5
+ import { a as connectorManifest } from "./_ssr/connections-qnw2GVlP.mjs";
6
+ import { B as ArrowLeft, M as CircleAlert, S as Eye, f as Play } from "./_libs/lucide-react.mjs";
7
+ import { n as toast } from "./_libs/sonner.mjs";
8
+ import { C as Button$1, E as runLoopBacklog, L as Card, R as CardContent, S as Input$1, V as cn, b as Label, f as useLiveRefresh, k as runLoopNow, o as Route$10 } from "./_ssr/router-3WmpE5b_.mjs";
9
+ import { t as Switch$1 } from "./_ssr/switch-ReNglgH6.mjs";
10
+ import { n as AlertDescription, r as AlertTitle, t as Alert } from "./_ssr/alert-NEiOCTOl.mjs";
11
+ import { n as TaskList } from "./_ssr/task-list-CUITIqkb.mjs";
12
+ import { t as LoopForm } from "./_ssr/loop-form-DlObSewZ.mjs";
13
+ import { n as issuesFor } from "./_ssr/gaps-RAFSXLZf.mjs";
14
+ //#region node_modules/.nitro/vite/services/ssr/assets/_loopId-BsUL1SeL.js
15
+ var import_react = /* @__PURE__ */ __toESM(require_react());
16
+ var import_jsx_runtime = require_jsx_runtime();
17
+ function Tabs$1({ className, orientation = "horizontal", ...props }) {
18
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsRoot, {
19
+ "data-slot": "tabs",
20
+ "data-orientation": orientation,
21
+ className: cn("group/tabs flex gap-2 data-horizontal:flex-col", className),
22
+ ...props
23
+ });
24
+ }
25
+ var tabsListVariants = cva("group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none", {
26
+ variants: { variant: {
27
+ default: "bg-muted",
28
+ line: "gap-1 bg-transparent"
29
+ } },
30
+ defaultVariants: { variant: "default" }
31
+ });
32
+ function TabsList({ className, variant = "default", ...props }) {
33
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsList$1, {
34
+ "data-slot": "tabs-list",
35
+ "data-variant": variant,
36
+ className: cn(tabsListVariants({ variant }), className),
37
+ ...props
38
+ });
39
+ }
40
+ function TabsTrigger({ className, ...props }) {
41
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsTab, {
42
+ "data-slot": "tabs-trigger",
43
+ className: cn("relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground", "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100", className),
44
+ ...props
45
+ });
46
+ }
47
+ function TabsContent({ className, ...props }) {
48
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsPanel, {
49
+ "data-slot": "tabs-content",
50
+ className: cn("flex-1 text-sm outline-none", className),
51
+ ...props
52
+ });
53
+ }
54
+ function LoopPage() {
55
+ const { loop, tasks, poll, readiness } = Route$10.useLoaderData();
56
+ useLiveRefresh();
57
+ const issues = issuesFor(readiness, loop);
58
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
59
+ className: "flex flex-col gap-6",
60
+ children: [
61
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
62
+ to: "/loops",
63
+ className: "flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground",
64
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, { className: "size-4" }), "Loops"]
65
+ }),
66
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
67
+ className: "text-2xl font-semibold tracking-tight",
68
+ children: loop.name
69
+ }),
70
+ issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, { children: [
71
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleAlert, {}),
72
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "This loop cannot run yet" }),
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, {
74
+ className: "flex flex-col gap-1",
75
+ children: issues.map((line) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: line }, line))
76
+ })
77
+ ] }) : null,
78
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Watching, {
79
+ loop,
80
+ poll
81
+ }),
82
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Tabs$1, {
83
+ defaultValue: "settings",
84
+ children: [
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TabsList, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsTrigger, {
86
+ value: "settings",
87
+ children: "Settings"
88
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsTrigger, {
89
+ value: "tasks",
90
+ children: "Tasks"
91
+ })] }),
92
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsContent, {
93
+ value: "settings",
94
+ className: "pt-2",
95
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoopForm, { loop })
96
+ }),
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TabsContent, {
98
+ value: "tasks",
99
+ className: "flex flex-col gap-4 pt-2",
100
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunBox, { loop }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TaskList, {
101
+ tasks,
102
+ showLoop: false,
103
+ empty: "This loop has not run yet."
104
+ })]
105
+ })
106
+ ]
107
+ })
108
+ ]
109
+ });
110
+ }
111
+ function when(iso) {
112
+ return new Date(iso).toLocaleString();
113
+ }
114
+ /**
115
+ * Whether the loop is really watching is the one thing a page cannot work out
116
+ * for itself, and the thing a person most wants to know after turning one on.
117
+ */
118
+ function Watching({ loop, poll }) {
119
+ const router = useRouter();
120
+ const [busy, setBusy] = (0, import_react.useState)(false);
121
+ if (!loop.enabled) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "This loop is off" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: "Nothing is being watched for until you turn it back on." })] });
122
+ if (poll.pollError) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Alert, {
123
+ variant: "destructive",
124
+ children: [
125
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleAlert, {}),
126
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertTitle, { children: "The last look did not work" }),
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: poll.pollError })
128
+ ]
129
+ });
130
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardContent, {
131
+ className: "flex flex-col gap-4 pt-6",
132
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
133
+ className: "flex items-start gap-3 text-sm",
134
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Eye, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
135
+ className: "text-muted-foreground",
136
+ children: poll.polledAt ? `Watching. Last looked ${when(poll.polledAt)}.` : "Not looked yet. The dispatcher checks every couple of minutes; the first look records what is already waiting without running it."
137
+ })]
138
+ }), poll.backlog.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
139
+ className: "flex flex-col gap-3 rounded-lg border p-4",
140
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
141
+ className: "flex flex-wrap items-start justify-between gap-3",
142
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
143
+ className: "text-sm font-medium",
144
+ children: poll.backlog.length === 1 ? "One thing is waiting" : `${poll.backlog.length} things are waiting`
145
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
146
+ className: "mt-1 text-xs text-muted-foreground",
147
+ children: "Matched, but not run: either it was already there before the loop was made, or it was held back for the reason shown. Run them if you want them dealt with too."
148
+ })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
149
+ variant: "outline",
150
+ size: "sm",
151
+ disabled: busy,
152
+ onClick: async () => {
153
+ setBusy(true);
154
+ try {
155
+ const { queued } = await runLoopBacklog({ data: { id: loop.id } });
156
+ await router.invalidate();
157
+ toast.success(queued === 1 ? "Queued 1 run" : `Queued ${queued} runs`);
158
+ } catch (error) {
159
+ toast.error(error instanceof Error ? error.message : String(error));
160
+ } finally {
161
+ setBusy(false);
162
+ }
163
+ },
164
+ children: busy ? "Queueing..." : "Run these too"
165
+ })]
166
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
167
+ className: "flex flex-col gap-1 text-xs text-muted-foreground",
168
+ children: [poll.backlog.slice(0, 8).map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
169
+ className: "truncate",
170
+ children: [
171
+ item.sourceRef,
172
+ " · ",
173
+ item.sourceTitle,
174
+ item.hold ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
175
+ className: "text-foreground",
176
+ children: [" · ", item.hold]
177
+ }) : null
178
+ ]
179
+ }, item.key)), poll.backlog.length > 8 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
180
+ "and ",
181
+ poll.backlog.length - 8,
182
+ " more"
183
+ ] }) : null]
184
+ })]
185
+ }) : null]
186
+ }) });
187
+ }
188
+ /**
189
+ * A loop that runs by itself still has to be shaped, and waiting for a real
190
+ * signal to arrive is a slow way to do it. Dry run means that shaping leaves
191
+ * no marks on a real repository.
192
+ */
193
+ function RunBox({ loop }) {
194
+ const router = useRouter();
195
+ const [url, setUrl] = (0, import_react.useState)("");
196
+ const [dryRun, setDryRun] = (0, import_react.useState)(true);
197
+ const [running, setRunning] = (0, import_react.useState)(false);
198
+ const manifest = connectorManifest(loop.connectorId);
199
+ const byHand = manifest?.byHand ?? { kind: "none" };
200
+ const run = async () => {
201
+ setRunning(true);
202
+ try {
203
+ await runLoopNow({ data: {
204
+ loopId: loop.id,
205
+ url: url.trim(),
206
+ dryRun
207
+ } });
208
+ await router.invalidate();
209
+ setUrl("");
210
+ toast.success(dryRun ? "Queued as a dry run" : "Queued");
211
+ } catch (error) {
212
+ toast.error(error instanceof Error ? error.message : String(error));
213
+ } finally {
214
+ setRunning(false);
215
+ }
216
+ };
217
+ if (byHand.kind === "none") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardContent, {
218
+ className: "pt-6 text-sm text-muted-foreground",
219
+ children: "This loop can only run on something arriving, so there is nothing to start by hand. What it does with what arrives is worth trying on the first one, with dry run left on."
220
+ }) });
221
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CardContent, {
222
+ className: "flex flex-col gap-4 pt-6",
223
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
224
+ className: "flex flex-col gap-2",
225
+ children: byHand.kind === "now" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, { children: "Run it now, without waiting for the time" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
226
+ className: "flex items-center justify-between gap-4",
227
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
228
+ className: "text-xs text-muted-foreground",
229
+ children: "Runs exactly as it would when the clock came round, and does not count as that run: the next scheduled one still happens."
230
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
231
+ onClick: run,
232
+ disabled: running,
233
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Play, {}), "Run"]
234
+ })]
235
+ })] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Label, {
236
+ htmlFor: "run-url",
237
+ children: [
238
+ "Try this loop on a ",
239
+ manifest?.name ?? "",
240
+ " link"
241
+ ]
242
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
243
+ className: "flex gap-2",
244
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
245
+ id: "run-url",
246
+ value: url,
247
+ placeholder: byHand.placeholder,
248
+ onChange: (event) => setUrl(event.target.value)
249
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
250
+ onClick: run,
251
+ disabled: running || url.trim() === "",
252
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Play, {}), "Run"]
253
+ })]
254
+ })] })
255
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
256
+ className: "flex items-center justify-between gap-4",
257
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, {
258
+ htmlFor: "run-dry",
259
+ children: "Dry run"
260
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
261
+ className: "mt-1 text-xs text-muted-foreground",
262
+ children: dryRun ? "Prepare the result and show it to you, without writing anything." : "Write the result back, exactly as the loop would on its own."
263
+ })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Switch$1, {
264
+ id: "run-dry",
265
+ checked: dryRun,
266
+ onCheckedChange: setDryRun
267
+ })]
268
+ })]
269
+ }) });
270
+ }
271
+ //#endregion
272
+ export { LoopPage as component };