clay-server 4.1.0-beta.5 → 4.1.0-beta.7
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/LICENSE +661 -21
- package/LICENSES/MIT-legacy.txt +21 -0
- package/LICENSES/README.md +7 -0
- package/README.md +2 -2
- package/bin/cli.js +0 -2
- package/lib/autonomous-run-record.js +32 -0
- package/lib/autonomous-run-scheduler.js +92 -0
- package/lib/daemon.js +0 -2
- package/lib/default-ai-runtime.js +117 -0
- package/lib/durable-scheduler-record.js +61 -0
- package/lib/durable-scheduler-store.js +185 -0
- package/lib/durable-scheduler.js +495 -0
- package/lib/git-cli.js +1 -0
- package/lib/issue-work-session.js +10 -0
- package/lib/issues-comments.js +40 -0
- package/lib/issues-commit-verification.js +30 -0
- package/lib/issues-mcp-server.js +27 -0
- package/lib/issues-schema.js +119 -0
- package/lib/issues-service.js +339 -0
- package/lib/issues-store.js +210 -0
- package/lib/loop-cron.js +47 -0
- package/lib/loop-durable-schedule.js +159 -0
- package/lib/loop-guidance.js +35 -0
- package/lib/loop-registry-occurrence.js +76 -0
- package/lib/model-entry.js +15 -0
- package/lib/project-autonomous-run.js +498 -0
- package/lib/project-capsule-turn.js +1 -0
- package/lib/project-connection.js +6 -1
- package/lib/project-delegated-session.js +1 -0
- package/lib/project-filesystem.js +10 -10
- package/lib/project-full-access.js +86 -0
- package/lib/project-http.js +3 -1
- package/lib/project-issue-launch.js +154 -0
- package/lib/project-issues.js +58 -0
- package/lib/project-logs-mcp-server.js +8 -12
- package/lib/project-loop-interview.js +163 -0
- package/lib/project-loop.js +150 -64
- package/lib/project-message-delivery.js +4 -2
- package/lib/project-models.js +71 -3
- package/lib/project-pair-autonomous-stop.js +16 -0
- package/lib/project-pair-owned-stop.js +18 -0
- package/lib/project-pair-task-control.js +14 -1
- package/lib/project-pending-message-queue.js +264 -0
- package/lib/project-scheduled-messages.js +316 -0
- package/lib/project-scheduled-task-execution.js +236 -0
- package/lib/project-scheduled-tasks.js +481 -0
- package/lib/project-session-pair.js +16 -19
- package/lib/project-sessions.js +114 -31
- package/lib/project-tool-llm-runtime.js +48 -0
- package/lib/project-user-message.js +202 -60
- package/lib/project-workspace-query.js +25 -0
- package/lib/project.js +361 -69
- package/lib/public/app.js +85 -22
- package/lib/public/css/default-ai.css +33 -0
- package/lib/public/css/home-hub.css +15 -2
- package/lib/public/css/home-sidebar.css +50 -2
- package/lib/public/css/input.css +160 -5
- package/lib/public/css/issues.css +101 -0
- package/lib/public/css/messages.css +19 -0
- package/lib/public/css/pane.css +58 -7
- package/lib/public/css/pending-message-queue.css +187 -0
- package/lib/public/css/rewind.css +11 -2
- package/lib/public/css/scheduled-tasks.css +122 -0
- package/lib/public/index.html +42 -150
- package/lib/public/modules/app-connection.js +3 -0
- package/lib/public/modules/app-cursors.js +29 -12
- package/lib/public/modules/app-loop-ui.js +4 -8
- package/lib/public/modules/app-message-router.js +8 -0
- package/lib/public/modules/app-messages.js +34 -9
- package/lib/public/modules/app-projects.js +2 -0
- package/lib/public/modules/app-rate-limit.js +8 -5
- package/lib/public/modules/autonomous-run.js +285 -0
- package/lib/public/modules/clay-file-links.js +111 -0
- package/lib/public/modules/clay-issue-links.js +131 -0
- package/lib/public/modules/clay-log-links.js +2 -0
- package/lib/public/modules/cursor-sharing-preference.js +38 -0
- package/lib/public/modules/default-ai.js +377 -0
- package/lib/public/modules/filebrowser.js +43 -2
- package/lib/public/modules/home-sidebar.js +16 -8
- package/lib/public/modules/home-surface.js +5 -0
- package/lib/public/modules/input.js +11 -20
- package/lib/public/modules/issues-context.js +117 -0
- package/lib/public/modules/issues-render.js +29 -0
- package/lib/public/modules/issues.js +270 -0
- package/lib/public/modules/loop-interview.js +151 -0
- package/lib/public/modules/markdown.js +4 -0
- package/lib/public/modules/message-delivery.js +5 -3
- package/lib/public/modules/pending-message-image-editor.js +143 -0
- package/lib/public/modules/pending-message-queue-model.js +22 -0
- package/lib/public/modules/pending-message-queue.js +449 -0
- package/lib/public/modules/project-logs.js +2 -2
- package/lib/public/modules/scheduled-message-state.js +46 -0
- package/lib/public/modules/scheduled-task-edit-state.js +7 -0
- package/lib/public/modules/scheduled-task-engine.js +48 -0
- package/lib/public/modules/scheduled-task-form.js +122 -0
- package/lib/public/modules/scheduled-task-recurrence.js +46 -0
- package/lib/public/modules/scheduled-task-schedule-rule.js +115 -0
- package/lib/public/modules/scheduled-tasks.js +459 -0
- package/lib/public/modules/scheduler-config.js +6 -52
- package/lib/public/modules/scheduler.js +9 -21
- package/lib/public/modules/sidebar-mobile.js +3 -0
- package/lib/public/modules/sidebar.js +0 -11
- package/lib/public/modules/split-view.js +2 -0
- package/lib/public/modules/sticky-note-markdown.js +1 -0
- package/lib/public/modules/terminal.js +2 -0
- package/lib/public/modules/tool-palette-order.js +3 -3
- package/lib/public/modules/tools.js +5 -2
- package/lib/public/style.css +3 -0
- package/lib/record-revision.js +11 -0
- package/lib/schedule-rule.js +151 -0
- package/lib/schedule-validation.js +124 -0
- package/lib/scheduled-run-state.js +87 -0
- package/lib/scheduled-task-records.js +127 -0
- package/lib/scheduler.js +179 -196
- package/lib/sdk-bridge.js +157 -22
- package/lib/sdk-message-processor.js +3 -0
- package/lib/server-cursor-sharing.js +65 -0
- package/lib/server-default-ai.js +265 -0
- package/lib/server-durable-scheduler.js +26 -0
- package/lib/server-home-chat.js +29 -9
- package/lib/server-home-clay-entry.js +4 -1
- package/lib/server-home-debate-planning.js +32 -14
- package/lib/server-home-mate-creation.js +30 -11
- package/lib/server-home-models.js +14 -6
- package/lib/server-issue-links.js +18 -0
- package/lib/server.js +63 -0
- package/lib/session-notes-mcp-server.js +1 -1
- package/lib/session-pair-factory.js +42 -4
- package/lib/session-pair-query-start.js +22 -0
- package/lib/session-query-tool-bridge.js +52 -0
- package/lib/session-search.js +4 -1
- package/lib/session-split-groups.js +35 -1
- package/lib/sessions.js +51 -3
- package/lib/tool-llm.js +1 -0
- package/lib/users-default-ai-preferences.js +80 -0
- package/lib/users-home-surface-preferences.js +2 -1
- package/lib/users-preferences.js +35 -0
- package/lib/users-scheduled-task-preferences.js +44 -0
- package/lib/users.js +16 -0
- package/lib/workspace-query-projection.js +29 -0
- package/lib/workspace-query-service.js +19 -29
- package/lib/ws-schema.js +61 -1
- package/lib/yoke/adapters/antigravity.js +1 -0
- package/lib/yoke/adapters/claude-worker.js +11 -6
- package/lib/yoke/adapters/claude.js +35 -1
- package/lib/yoke/adapters/codex.js +3 -0
- package/lib/yoke/claude-user-input.js +2 -0
- package/lib/yoke/index.js +2 -0
- package/lib/yoke/mcp-bridge-server.js +7 -1
- package/lib/yoke/package.json +1 -1
- package/lib/yoke/session-tool-transport.js +53 -0
- package/lib/yoke/user-input.js +21 -7
- package/package.json +5 -6
- package/bin/claude-relay.js +0 -6
- package/lib/public/modules/app-loop-wizard.js +0 -439
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Shared production transport facts for query-bound Clay tools.
|
|
2
|
+
|
|
3
|
+
var vendorRegistry = require("./vendor-registry");
|
|
4
|
+
var CODEX_CATALOG_VERSION = 5;
|
|
5
|
+
var SCHEDULE_TOOLS = ["begin_scheduled_task_interview", "propose_scheduled_task", "list_scheduled_tasks", "read_scheduled_task", "update_scheduled_task", "report_scheduled_task_outcome"];
|
|
6
|
+
|
|
7
|
+
function capability(vendor) {
|
|
8
|
+
if (vendor === "claude") return { supported: true, kind: "sdk-mcp" };
|
|
9
|
+
if (vendor === "codex") return { supported: true, kind: "dynamic" };
|
|
10
|
+
var info = vendorRegistry.getVendorInfo(vendor);
|
|
11
|
+
if (info && info.sessionBoundTools === true) return { supported: true, kind: "stdio-mcp" };
|
|
12
|
+
return { supported: false, kind: "none" };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function availableForSession(session) {
|
|
16
|
+
var vendor = session && (session.vendor || "claude");
|
|
17
|
+
var transport = capability(vendor);
|
|
18
|
+
if (!transport.supported) return { available: false, reason: "This provider's current Clay adapter does not deliver custom session tools." };
|
|
19
|
+
if (vendor === "codex" && session.cliSessionId && Number(session.codexDynamicToolCatalogVersion || 0) < CODEX_CATALOG_VERSION) {
|
|
20
|
+
return { available: false, reason: "This Codex conversation predates Clay's scheduled-task tool catalog. Start a new conversation to use the assisted interview; manual task creation remains available here." };
|
|
21
|
+
}
|
|
22
|
+
return { available: true, reason: null };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function scheduleToolName(vendor, name) {
|
|
26
|
+
var kind = capability(vendor).kind;
|
|
27
|
+
if (kind === "sdk-mcp") return "mcp__clay-scheduled-tasks__" + name;
|
|
28
|
+
if (kind === "stdio-mcp") return "clay-scheduled-tasks__" + name;
|
|
29
|
+
return name;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function questionToolName(vendor) {
|
|
33
|
+
var kind = capability(vendor).kind;
|
|
34
|
+
if (kind === "sdk-mcp") return "mcp__yoke-user-input__ask_user_questions";
|
|
35
|
+
if (kind === "stdio-mcp") return "yoke-user-input__ask_user_questions";
|
|
36
|
+
return "ask_user_questions";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function bridgeServerForTool(name) {
|
|
40
|
+
if (name === "ask_user_questions") return "yoke-user-input";
|
|
41
|
+
if (SCHEDULE_TOOLS.indexOf(name) !== -1) return "clay-scheduled-tasks";
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
capability: capability,
|
|
47
|
+
availableForSession: availableForSession,
|
|
48
|
+
CODEX_CATALOG_VERSION: CODEX_CATALOG_VERSION,
|
|
49
|
+
scheduleToolName: scheduleToolName,
|
|
50
|
+
questionToolName: questionToolName,
|
|
51
|
+
bridgeServerForTool: bridgeServerForTool,
|
|
52
|
+
SCHEDULE_TOOLS: SCHEDULE_TOOLS,
|
|
53
|
+
};
|
package/lib/yoke/user-input.js
CHANGED
|
@@ -195,24 +195,38 @@ function elicitationResponse(result) {
|
|
|
195
195
|
return { action: "accept", content: content };
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
function buildQuestionShape() {
|
|
198
|
+
function buildQuestionShape(maxQuestions) {
|
|
199
199
|
if (!z) return {};
|
|
200
200
|
var option = z.object({ label: z.string().min(1).max(60), description: z.string().max(160).optional() }).passthrough();
|
|
201
201
|
var question = z.object({
|
|
202
202
|
id: z.string().max(128).optional(), header: z.string().max(40).optional(), question: z.string().min(1),
|
|
203
203
|
multiSelect: z.boolean().optional(), options: z.array(option).max(6).refine(function (items) { return items.length === 0 || items.length >= 2; }),
|
|
204
204
|
}).passthrough();
|
|
205
|
-
return { questions: z.array(question).min(1).max(3) };
|
|
205
|
+
return { questions: z.array(question).min(1).max(maxQuestions || 3) };
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
function
|
|
208
|
+
function questionLimit(options) {
|
|
209
|
+
var value = options && options.maxQuestions;
|
|
210
|
+
if (typeof value === "function") value = value();
|
|
211
|
+
return value === 1 ? 1 : null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function fallbackToolDefs(handler, options) {
|
|
215
|
+
options = options || {};
|
|
216
|
+
var initialLimit = questionLimit(options);
|
|
209
217
|
return [{
|
|
210
218
|
name: TOOL_NAME,
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
queryBound: true,
|
|
220
|
+
description: initialLimit === 1
|
|
221
|
+
? "Ask the user exactly one structured question, wait for the answer, then call again if another question is needed. Use zero options for freeform or 2-6 options for choices; never one option."
|
|
222
|
+
: "Ask the user 1-3 structured questions. Use zero options for freeform or 2-6 options for choices; never one option.",
|
|
223
|
+
inputSchema: buildQuestionShape(initialLimit),
|
|
213
224
|
handler: function (input) {
|
|
225
|
+
if (questionLimit(options) === 1 && input && Array.isArray(input.questions) && input.questions.length !== 1) {
|
|
226
|
+
return Promise.resolve({ content: [{ type: "text", text: "Ask exactly one question at a time, wait for the answer, then ask the next question." }], isError: true });
|
|
227
|
+
}
|
|
214
228
|
return dispatchUserInput(handler, input, { source: "mcp_fallback", native: false }).then(function (result) {
|
|
215
|
-
if (result.status !== "submitted") return { content: [{ type: "text", text: "The user cancelled this question." }], isError: true };
|
|
229
|
+
if (result.status !== "submitted") return { content: [{ type: "text", text: result.reason || "The user cancelled this question." }], isError: true };
|
|
216
230
|
return { content: [{ type: "text", text: JSON.stringify(result.answers) }] };
|
|
217
231
|
}).catch(function (error) { return { content: [{ type: "text", text: "Error: " + error.message }], isError: true }; });
|
|
218
232
|
},
|
|
@@ -235,7 +249,7 @@ function createFallbackServer(adapter, handler) {
|
|
|
235
249
|
var opts = arguments.length > 2 && arguments[2] ? arguments[2] : {};
|
|
236
250
|
if (!adapter || typeof adapter.createToolServer !== "function") return null;
|
|
237
251
|
if (capability(adapter).mode === "native" && opts.force !== true) return null;
|
|
238
|
-
return adapter.createToolServer({ name: "yoke-user-input", version: "1.0.0", tools: fallbackToolDefs(handler) });
|
|
252
|
+
return adapter.createToolServer({ name: "yoke-user-input", version: "1.0.0", tools: fallbackToolDefs(handler, opts) });
|
|
239
253
|
}
|
|
240
254
|
|
|
241
255
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clay-server",
|
|
3
|
-
"version": "4.1.0-beta.
|
|
3
|
+
"version": "4.1.0-beta.7",
|
|
4
4
|
"description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"clay-server": "./bin/cli.js"
|
|
7
|
-
"claude-relay": "./bin/claude-relay.js"
|
|
6
|
+
"clay-server": "./bin/cli.js"
|
|
8
7
|
},
|
|
9
8
|
"scripts": {
|
|
10
9
|
"dev": "node bin/cli.js --dev",
|
|
@@ -15,7 +14,8 @@
|
|
|
15
14
|
},
|
|
16
15
|
"files": [
|
|
17
16
|
"bin/",
|
|
18
|
-
"lib/"
|
|
17
|
+
"lib/",
|
|
18
|
+
"LICENSES/"
|
|
19
19
|
],
|
|
20
20
|
"keywords": [
|
|
21
21
|
"claude",
|
|
@@ -59,13 +59,12 @@
|
|
|
59
59
|
"web-push": "^3.6.7",
|
|
60
60
|
"ws": "^8.18.0"
|
|
61
61
|
},
|
|
62
|
-
"license": "
|
|
62
|
+
"license": "AGPL-3.0-only",
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=20.0.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@semantic-release/changelog": "^6.0.3",
|
|
68
|
-
"@semantic-release/exec": "^7.1.0",
|
|
69
68
|
"@semantic-release/git": "^10.0.1",
|
|
70
69
|
"semantic-release": "^25.0.3"
|
|
71
70
|
}
|
package/bin/claude-relay.js
DELETED
|
@@ -1,439 +0,0 @@
|
|
|
1
|
-
// app-loop-wizard.js - Ralph Loop wizard: step navigation, data collection, repeat picker
|
|
2
|
-
// Extracted from app-loop-ui.js
|
|
3
|
-
|
|
4
|
-
import { refreshIcons } from './icons.js';
|
|
5
|
-
import { store } from './store.js';
|
|
6
|
-
import { getWs } from './ws-ref.js';
|
|
7
|
-
import { requireSkills } from './app-skills-install.js';
|
|
8
|
-
|
|
9
|
-
// --- Module-owned state (not in store) ---
|
|
10
|
-
var wizardStep = 1;
|
|
11
|
-
var wizardSource = "ralph"; // "ralph" or "task"
|
|
12
|
-
var wizardMode = "draft"; // "draft" or "own"
|
|
13
|
-
var loopModeChoice = "judge"; // "simple" | "judge"
|
|
14
|
-
var promptAuthor = "clay"; // "clay" | "me"
|
|
15
|
-
var judgeAuthor = "clay"; // "clay" | "me"
|
|
16
|
-
|
|
17
|
-
// --- Module-local state accessors ---
|
|
18
|
-
export function getWizardSource() { return wizardSource; }
|
|
19
|
-
|
|
20
|
-
// --- DOM refs for repeat picker (captured in init) ---
|
|
21
|
-
var repeatSelect = null;
|
|
22
|
-
var repeatTimeRow = null;
|
|
23
|
-
var repeatCustom = null;
|
|
24
|
-
var repeatUnitSelect = null;
|
|
25
|
-
var repeatDowRow = null;
|
|
26
|
-
var cronPreview = null;
|
|
27
|
-
|
|
28
|
-
// ========================================================
|
|
29
|
-
// Init
|
|
30
|
-
// ========================================================
|
|
31
|
-
export function initLoopWizard() {
|
|
32
|
-
// Repeat picker DOM refs
|
|
33
|
-
repeatSelect = document.getElementById("ralph-repeat");
|
|
34
|
-
repeatTimeRow = document.getElementById("ralph-time-row");
|
|
35
|
-
repeatCustom = document.getElementById("ralph-custom-repeat");
|
|
36
|
-
repeatUnitSelect = document.getElementById("ralph-repeat-unit");
|
|
37
|
-
repeatDowRow = document.getElementById("ralph-custom-dow-row");
|
|
38
|
-
cronPreview = document.getElementById("ralph-cron-preview");
|
|
39
|
-
|
|
40
|
-
// --- Wizard button listeners ---
|
|
41
|
-
var wizardCloseBtn = document.getElementById("ralph-wizard-close");
|
|
42
|
-
var wizardBackdrop = document.querySelector(".ralph-wizard-backdrop");
|
|
43
|
-
var wizardBackBtn = document.getElementById("ralph-wizard-back");
|
|
44
|
-
var wizardSkipBtn = document.getElementById("ralph-wizard-skip");
|
|
45
|
-
var wizardNextBtn = document.getElementById("ralph-wizard-next");
|
|
46
|
-
|
|
47
|
-
if (wizardCloseBtn) wizardCloseBtn.addEventListener("click", closeRalphWizard);
|
|
48
|
-
if (wizardBackdrop) wizardBackdrop.addEventListener("click", closeRalphWizard);
|
|
49
|
-
if (wizardBackBtn) wizardBackBtn.addEventListener("click", wizardBack);
|
|
50
|
-
if (wizardSkipBtn) wizardSkipBtn.addEventListener("click", wizardSkip);
|
|
51
|
-
if (wizardNextBtn) wizardNextBtn.addEventListener("click", wizardNext);
|
|
52
|
-
|
|
53
|
-
// --- Mode cards (step 1: loop mode) ---
|
|
54
|
-
var modeCards = document.querySelectorAll(".ralph-mode-card");
|
|
55
|
-
for (var mc = 0; mc < modeCards.length; mc++) {
|
|
56
|
-
modeCards[mc].addEventListener("click", function () {
|
|
57
|
-
loopModeChoice = this.getAttribute("data-loop-mode");
|
|
58
|
-
var all = document.querySelectorAll(".ralph-mode-card");
|
|
59
|
-
for (var i = 0; i < all.length; i++) all[i].classList.remove("active");
|
|
60
|
-
this.classList.add("active");
|
|
61
|
-
updateModePreview();
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// --- Authorship toggles (step 3) ---
|
|
66
|
-
var authorBtns = document.querySelectorAll(".ralph-authorship-toggle .config-segment-btn");
|
|
67
|
-
for (var ab = 0; ab < authorBtns.length; ab++) {
|
|
68
|
-
authorBtns[ab].addEventListener("click", function () {
|
|
69
|
-
var toggle = this.parentElement;
|
|
70
|
-
var file = toggle.getAttribute("data-file");
|
|
71
|
-
var author = this.getAttribute("data-author");
|
|
72
|
-
var siblings = toggle.querySelectorAll(".config-segment-btn");
|
|
73
|
-
for (var s = 0; s < siblings.length; s++) siblings[s].classList.remove("active");
|
|
74
|
-
this.classList.add("active");
|
|
75
|
-
if (file === "prompt") promptAuthor = author;
|
|
76
|
-
if (file === "judge") judgeAuthor = author;
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// --- Repeat picker handlers ---
|
|
81
|
-
if (repeatSelect) {
|
|
82
|
-
repeatSelect.addEventListener("change", updateRepeatUI);
|
|
83
|
-
}
|
|
84
|
-
if (repeatUnitSelect) {
|
|
85
|
-
repeatUnitSelect.addEventListener("change", function () {
|
|
86
|
-
if (repeatDowRow) repeatDowRow.style.display = this.value === "week" ? "" : "none";
|
|
87
|
-
updateRepeatUI();
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
var timeInput = document.getElementById("ralph-time");
|
|
92
|
-
if (timeInput) timeInput.addEventListener("change", updateRepeatUI);
|
|
93
|
-
|
|
94
|
-
// DOW buttons in custom repeat
|
|
95
|
-
var customDowBtns = document.querySelectorAll("#ralph-custom-repeat .sched-dow-btn");
|
|
96
|
-
for (var di = 0; di < customDowBtns.length; di++) {
|
|
97
|
-
customDowBtns[di].addEventListener("click", function () {
|
|
98
|
-
this.classList.toggle("active");
|
|
99
|
-
updateRepeatUI();
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ========================================================
|
|
105
|
-
// Mode preview toggle
|
|
106
|
-
// ========================================================
|
|
107
|
-
|
|
108
|
-
function updateModePreview() {
|
|
109
|
-
var judgePreview = document.querySelector(".ralph-mode-preview-judge");
|
|
110
|
-
var simplePreview = document.querySelector(".ralph-mode-preview-simple");
|
|
111
|
-
if (judgePreview) judgePreview.style.display = loopModeChoice === "judge" ? "" : "none";
|
|
112
|
-
if (simplePreview) simplePreview.style.display = loopModeChoice === "simple" ? "" : "none";
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ========================================================
|
|
116
|
-
// requireClayRalph
|
|
117
|
-
// ========================================================
|
|
118
|
-
|
|
119
|
-
function requireClayRalph(cb) {
|
|
120
|
-
requireSkills({
|
|
121
|
-
title: "Skill Installation Required",
|
|
122
|
-
reason: "This feature requires the following skill to be installed.",
|
|
123
|
-
skills: [{ name: "clay-ralph", url: "https://github.com/chadbyte/clay-ralph", scope: "global" }]
|
|
124
|
-
}, cb);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ========================================================
|
|
128
|
-
// Ralph Wizard (exported: openRalphWizard, closeRalphWizard)
|
|
129
|
-
// ========================================================
|
|
130
|
-
|
|
131
|
-
export function openRalphWizard(source) {
|
|
132
|
-
requireClayRalph(function () {
|
|
133
|
-
wizardSource = source || "ralph";
|
|
134
|
-
store.set({ wizardData: { name: "", task: "", maxIterations: null } });
|
|
135
|
-
loopModeChoice = "judge";
|
|
136
|
-
promptAuthor = "clay";
|
|
137
|
-
judgeAuthor = "clay";
|
|
138
|
-
|
|
139
|
-
var el = document.getElementById("ralph-wizard");
|
|
140
|
-
if (!el) return;
|
|
141
|
-
|
|
142
|
-
// Reset inputs
|
|
143
|
-
var taskEl = document.getElementById("ralph-task");
|
|
144
|
-
if (taskEl) taskEl.value = "";
|
|
145
|
-
var promptInput = document.getElementById("ralph-prompt-input");
|
|
146
|
-
if (promptInput) promptInput.value = "";
|
|
147
|
-
var judgeInput = document.getElementById("ralph-judge-input");
|
|
148
|
-
if (judgeInput) judgeInput.value = "";
|
|
149
|
-
|
|
150
|
-
// Reset mode cards
|
|
151
|
-
var modeCards = document.querySelectorAll(".ralph-mode-card");
|
|
152
|
-
for (var mc = 0; mc < modeCards.length; mc++) {
|
|
153
|
-
if (modeCards[mc].getAttribute("data-loop-mode") === "judge") {
|
|
154
|
-
modeCards[mc].classList.add("active");
|
|
155
|
-
} else {
|
|
156
|
-
modeCards[mc].classList.remove("active");
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Reset authorship toggles
|
|
161
|
-
var authorToggles = document.querySelectorAll(".ralph-authorship-toggle");
|
|
162
|
-
for (var at = 0; at < authorToggles.length; at++) {
|
|
163
|
-
var btns = authorToggles[at].querySelectorAll(".config-segment-btn");
|
|
164
|
-
for (var b = 0; b < btns.length; b++) {
|
|
165
|
-
if (btns[b].getAttribute("data-author") === "clay") {
|
|
166
|
-
btns[b].classList.add("active");
|
|
167
|
-
} else {
|
|
168
|
-
btns[b].classList.remove("active");
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Update text based on source
|
|
174
|
-
var isTask = wizardSource === "task";
|
|
175
|
-
var headerSpan = el.querySelector(".ralph-wizard-header > span");
|
|
176
|
-
if (headerSpan) headerSpan.textContent = isTask ? "New Task" : "New Loop";
|
|
177
|
-
|
|
178
|
-
if (wizardSource === "task") {
|
|
179
|
-
// Tasks skip step 1 (loop mode), go to step 2
|
|
180
|
-
wizardStep = 2;
|
|
181
|
-
} else {
|
|
182
|
-
wizardStep = 1;
|
|
183
|
-
}
|
|
184
|
-
el.classList.remove("hidden");
|
|
185
|
-
var statusEl = document.getElementById("ralph-install-status");
|
|
186
|
-
if (statusEl) { statusEl.classList.add("hidden"); statusEl.innerHTML = ""; }
|
|
187
|
-
|
|
188
|
-
// Reset exec modal flag
|
|
189
|
-
store.set({ execModalShown: false });
|
|
190
|
-
|
|
191
|
-
updateModePreview();
|
|
192
|
-
updateWizardStep();
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function closeRalphWizard() {
|
|
197
|
-
var el = document.getElementById("ralph-wizard");
|
|
198
|
-
if (el) el.classList.add("hidden");
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// --- Internal wizard helpers ---
|
|
202
|
-
|
|
203
|
-
function updateWizardStep() {
|
|
204
|
-
var steps = document.querySelectorAll(".ralph-step");
|
|
205
|
-
for (var i = 0; i < steps.length; i++) {
|
|
206
|
-
var stepNum = parseInt(steps[i].getAttribute("data-step"), 10);
|
|
207
|
-
if (stepNum === wizardStep) {
|
|
208
|
-
steps[i].classList.add("active");
|
|
209
|
-
} else {
|
|
210
|
-
steps[i].classList.remove("active");
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
var dots = document.querySelectorAll(".ralph-dot");
|
|
214
|
-
for (var j = 0; j < dots.length; j++) {
|
|
215
|
-
var dotStep = parseInt(dots[j].getAttribute("data-step"), 10);
|
|
216
|
-
dots[j].classList.remove("active", "done");
|
|
217
|
-
if (dotStep === wizardStep) dots[j].classList.add("active");
|
|
218
|
-
else if (dotStep < wizardStep) dots[j].classList.add("done");
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Show/hide JUDGE authorship row based on loop mode
|
|
222
|
-
var judgeRow = document.getElementById("ralph-judge-authorship-row");
|
|
223
|
-
if (judgeRow) judgeRow.style.display = loopModeChoice === "simple" ? "none" : "";
|
|
224
|
-
|
|
225
|
-
// Update step 3 input visibility
|
|
226
|
-
if (wizardStep === 3) updateInputVisibility();
|
|
227
|
-
|
|
228
|
-
var backBtn = document.getElementById("ralph-wizard-back");
|
|
229
|
-
var skipBtn = document.getElementById("ralph-wizard-skip");
|
|
230
|
-
var nextBtn = document.getElementById("ralph-wizard-next");
|
|
231
|
-
if (backBtn) {
|
|
232
|
-
var firstStep = (wizardSource === "task") ? 2 : 1;
|
|
233
|
-
backBtn.style.visibility = (wizardStep === firstStep) ? "hidden" : "visible";
|
|
234
|
-
backBtn.textContent = (wizardSource === "task" && wizardStep <= 2) ? "Cancel" : "Back";
|
|
235
|
-
}
|
|
236
|
-
if (skipBtn) skipBtn.style.display = "none";
|
|
237
|
-
if (nextBtn) {
|
|
238
|
-
if (wizardStep === 3) nextBtn.textContent = "Launch";
|
|
239
|
-
else nextBtn.textContent = "Next";
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function updateInputVisibility() {
|
|
244
|
-
var taskSection = document.getElementById("ralph-input-task-section");
|
|
245
|
-
var promptSection = document.getElementById("ralph-input-prompt-section");
|
|
246
|
-
var judgeSection = document.getElementById("ralph-input-judge-section");
|
|
247
|
-
|
|
248
|
-
var needsTask = (promptAuthor === "clay");
|
|
249
|
-
var needsPrompt = (promptAuthor === "me");
|
|
250
|
-
var needsJudge = (loopModeChoice === "judge" && judgeAuthor === "me");
|
|
251
|
-
|
|
252
|
-
if (taskSection) {
|
|
253
|
-
if (needsTask) taskSection.classList.remove("hidden");
|
|
254
|
-
else taskSection.classList.add("hidden");
|
|
255
|
-
}
|
|
256
|
-
if (promptSection) {
|
|
257
|
-
if (needsPrompt) promptSection.classList.remove("hidden");
|
|
258
|
-
else promptSection.classList.add("hidden");
|
|
259
|
-
}
|
|
260
|
-
if (judgeSection) {
|
|
261
|
-
if (needsJudge) judgeSection.classList.remove("hidden");
|
|
262
|
-
else judgeSection.classList.add("hidden");
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
var heading = document.querySelector('.ralph-step[data-step="3"] h3');
|
|
266
|
-
if (heading) {
|
|
267
|
-
if (needsTask && !needsJudge) heading.textContent = "Describe your task";
|
|
268
|
-
else if (needsPrompt && !needsJudge) heading.textContent = "Provide your prompt";
|
|
269
|
-
else if (needsPrompt && needsJudge) heading.textContent = "Provide your files";
|
|
270
|
-
else if (needsTask && needsJudge) heading.textContent = "Provide details";
|
|
271
|
-
else heading.textContent = "Provide details";
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function collectWizardData() {
|
|
276
|
-
var wd = {
|
|
277
|
-
name: "",
|
|
278
|
-
maxIterations: null,
|
|
279
|
-
cron: buildWizardCron(),
|
|
280
|
-
loopMode: loopModeChoice,
|
|
281
|
-
promptAuthor: promptAuthor,
|
|
282
|
-
judgeAuthor: (loopModeChoice === "judge") ? judgeAuthor : null,
|
|
283
|
-
mode: (promptAuthor === "me") ? "own" : "draft"
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
if (promptAuthor === "clay") {
|
|
287
|
-
var taskEl = document.getElementById("ralph-task");
|
|
288
|
-
wd.task = taskEl ? taskEl.value.trim() : "";
|
|
289
|
-
wd.promptText = null;
|
|
290
|
-
} else {
|
|
291
|
-
var promptInput = document.getElementById("ralph-prompt-input");
|
|
292
|
-
wd.task = "";
|
|
293
|
-
wd.promptText = promptInput ? promptInput.value.trim() : "";
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (loopModeChoice === "judge" && judgeAuthor === "me") {
|
|
297
|
-
var judgeInput = document.getElementById("ralph-judge-input");
|
|
298
|
-
wd.judgeText = judgeInput ? judgeInput.value.trim() : "";
|
|
299
|
-
} else {
|
|
300
|
-
wd.judgeText = null;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
store.set({ wizardData: wd });
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function buildWizardCron() {
|
|
307
|
-
if (!repeatSelect) return null;
|
|
308
|
-
var preset = repeatSelect.value;
|
|
309
|
-
if (preset === "none") return null;
|
|
310
|
-
|
|
311
|
-
var timeEl = document.getElementById("ralph-time");
|
|
312
|
-
var timeVal = timeEl ? timeEl.value : "09:00";
|
|
313
|
-
var timeParts = timeVal.split(":");
|
|
314
|
-
var hour = parseInt(timeParts[0], 10) || 9;
|
|
315
|
-
var minute = parseInt(timeParts[1], 10) || 0;
|
|
316
|
-
|
|
317
|
-
if (preset === "daily") return minute + " " + hour + " * * *";
|
|
318
|
-
if (preset === "weekdays") return minute + " " + hour + " * * 1-5";
|
|
319
|
-
if (preset === "weekly") return minute + " " + hour + " * * " + new Date().getDay();
|
|
320
|
-
if (preset === "monthly") return minute + " " + hour + " " + new Date().getDate() + " * *";
|
|
321
|
-
|
|
322
|
-
if (preset === "custom") {
|
|
323
|
-
var unitEl = document.getElementById("ralph-repeat-unit");
|
|
324
|
-
var unit = unitEl ? unitEl.value : "day";
|
|
325
|
-
if (unit === "day") return minute + " " + hour + " * * *";
|
|
326
|
-
if (unit === "month") return minute + " " + hour + " " + new Date().getDate() + " * *";
|
|
327
|
-
// week: collect selected days
|
|
328
|
-
var dowBtns = document.querySelectorAll("#ralph-custom-repeat .sched-dow-btn.active");
|
|
329
|
-
var days = [];
|
|
330
|
-
for (var i = 0; i < dowBtns.length; i++) {
|
|
331
|
-
days.push(dowBtns[i].dataset.dow);
|
|
332
|
-
}
|
|
333
|
-
if (days.length === 0) days.push(String(new Date().getDay()));
|
|
334
|
-
return minute + " " + hour + " * * " + days.join(",");
|
|
335
|
-
}
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function cronToHumanText(cron) {
|
|
340
|
-
if (!cron) return "";
|
|
341
|
-
var parts = cron.trim().split(/\s+/);
|
|
342
|
-
if (parts.length !== 5) return cron;
|
|
343
|
-
var m = parts[0], h = parts[1], dom = parts[2], dow = parts[4];
|
|
344
|
-
var pad = function(n) { return (parseInt(n,10) < 10 ? "0" : "") + parseInt(n,10); };
|
|
345
|
-
var t = pad(h) + ":" + pad(m);
|
|
346
|
-
var dayNames = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
|
|
347
|
-
if (dow === "*" && dom === "*") return "Every day at " + t;
|
|
348
|
-
if (dow === "1-5" && dom === "*") return "Weekdays at " + t;
|
|
349
|
-
if (dom !== "*" && dow === "*") return "Monthly on day " + dom + " at " + t;
|
|
350
|
-
if (dow !== "*" && dom === "*") {
|
|
351
|
-
var ds = dow.split(",").map(function(d) { return dayNames[parseInt(d,10)] || d; });
|
|
352
|
-
return "Every " + ds.join(", ") + " at " + t;
|
|
353
|
-
}
|
|
354
|
-
return cron;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
var LAST_STEP = 3;
|
|
358
|
-
|
|
359
|
-
function validateLastStep() {
|
|
360
|
-
var wd = store.get('wizardData');
|
|
361
|
-
if (promptAuthor === "clay") {
|
|
362
|
-
var taskEl = document.getElementById("ralph-task");
|
|
363
|
-
if (!wd.task) {
|
|
364
|
-
if (taskEl) { taskEl.focus(); taskEl.style.borderColor = "#e74c3c"; setTimeout(function() { taskEl.style.borderColor = ""; }, 2000); }
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
} else {
|
|
368
|
-
var promptInput = document.getElementById("ralph-prompt-input");
|
|
369
|
-
if (!wd.promptText) {
|
|
370
|
-
if (promptInput) { promptInput.focus(); promptInput.style.borderColor = "#e74c3c"; setTimeout(function() { promptInput.style.borderColor = ""; }, 2000); }
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (loopModeChoice === "judge" && judgeAuthor === "me") {
|
|
375
|
-
var judgeInput = document.getElementById("ralph-judge-input");
|
|
376
|
-
if (!wd.judgeText) {
|
|
377
|
-
if (judgeInput) { judgeInput.focus(); judgeInput.style.borderColor = "#e74c3c"; setTimeout(function() { judgeInput.style.borderColor = ""; }, 2000); }
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
return true;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function wizardNext() {
|
|
385
|
-
collectWizardData();
|
|
386
|
-
if (wizardStep < LAST_STEP) {
|
|
387
|
-
wizardStep++;
|
|
388
|
-
updateWizardStep();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
if (validateLastStep()) wizardSubmit();
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function wizardBack() {
|
|
395
|
-
if (wizardSource === "task" && wizardStep <= 2) {
|
|
396
|
-
closeRalphWizard();
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
if (wizardStep > 1) {
|
|
400
|
-
collectWizardData();
|
|
401
|
-
wizardStep--;
|
|
402
|
-
updateWizardStep();
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function wizardSkip() {
|
|
407
|
-
if (wizardStep < 3) {
|
|
408
|
-
wizardStep++;
|
|
409
|
-
updateWizardStep();
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function wizardSubmit() {
|
|
414
|
-
collectWizardData();
|
|
415
|
-
var wd = Object.assign({}, store.get('wizardData'));
|
|
416
|
-
wd.source = wizardSource === "task" ? "task" : undefined;
|
|
417
|
-
store.set({ wizardData: wd });
|
|
418
|
-
closeRalphWizard();
|
|
419
|
-
var ws = getWs();
|
|
420
|
-
if (ws && ws.readyState === 1) {
|
|
421
|
-
ws.send(JSON.stringify({ type: "ralph_wizard_complete", data: wd }));
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function updateRepeatUI() {
|
|
426
|
-
if (!repeatSelect) return;
|
|
427
|
-
var val = repeatSelect.value;
|
|
428
|
-
var isScheduled = val !== "none";
|
|
429
|
-
if (repeatTimeRow) repeatTimeRow.style.display = isScheduled ? "" : "none";
|
|
430
|
-
if (repeatCustom) repeatCustom.style.display = val === "custom" ? "" : "none";
|
|
431
|
-
if (cronPreview) cronPreview.style.display = isScheduled ? "" : "none";
|
|
432
|
-
if (isScheduled) {
|
|
433
|
-
var cron = buildWizardCron();
|
|
434
|
-
var humanEl = document.getElementById("ralph-cron-human");
|
|
435
|
-
var cronEl = document.getElementById("ralph-cron-expr");
|
|
436
|
-
if (humanEl) humanEl.textContent = cronToHumanText(cron);
|
|
437
|
-
if (cronEl) cronEl.textContent = cron || "";
|
|
438
|
-
}
|
|
439
|
-
}
|