@openma/common 0.0.0-stage → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +391 -2
- package/dist/acp-artifacts/binary.d.ts +35 -0
- package/dist/acp-artifacts/binary.d.ts.map +1 -0
- package/dist/acp-artifacts/binary.js +120 -0
- package/dist/acp-artifacts/binary.js.map +1 -0
- package/dist/acp-artifacts/index.d.ts +7 -0
- package/dist/acp-artifacts/index.d.ts.map +1 -0
- package/dist/acp-artifacts/index.js +7 -0
- package/dist/acp-artifacts/index.js.map +1 -0
- package/dist/acp-artifacts/node-abi.d.ts +3 -0
- package/dist/acp-artifacts/node-abi.d.ts.map +1 -0
- package/dist/acp-artifacts/node-abi.js +17 -0
- package/dist/acp-artifacts/node-abi.js.map +1 -0
- package/dist/acp-artifacts/npm-cli.d.ts +3 -0
- package/dist/acp-artifacts/npm-cli.d.ts.map +1 -0
- package/dist/acp-artifacts/npm-cli.js +9 -0
- package/dist/acp-artifacts/npm-cli.js.map +1 -0
- package/dist/acp-artifacts/npm.d.ts +37 -0
- package/dist/acp-artifacts/npm.d.ts.map +1 -0
- package/dist/acp-artifacts/npm.js +167 -0
- package/dist/acp-artifacts/npm.js.map +1 -0
- package/dist/acp-artifacts/registry.d.ts +45 -0
- package/dist/acp-artifacts/registry.d.ts.map +1 -0
- package/dist/acp-artifacts/registry.js +206 -0
- package/dist/acp-artifacts/registry.js.map +1 -0
- package/dist/acp-artifacts/shared.d.ts +45 -0
- package/dist/acp-artifacts/shared.d.ts.map +1 -0
- package/dist/acp-artifacts/shared.js +157 -0
- package/dist/acp-artifacts/shared.js.map +1 -0
- package/dist/acp-artifacts/uvx.d.ts +32 -0
- package/dist/acp-artifacts/uvx.d.ts.map +1 -0
- package/dist/acp-artifacts/uvx.js +95 -0
- package/dist/acp-artifacts/uvx.js.map +1 -0
- package/dist/acp-fork/index.d.ts +51 -0
- package/dist/acp-fork/index.d.ts.map +1 -0
- package/dist/acp-fork/index.js +116 -0
- package/dist/acp-fork/index.js.map +1 -0
- package/dist/acp-harnesses/agent-setup.d.ts +118 -0
- package/dist/acp-harnesses/agent-setup.d.ts.map +1 -0
- package/dist/acp-harnesses/agent-setup.js +717 -0
- package/dist/acp-harnesses/agent-setup.js.map +1 -0
- package/dist/acp-harnesses/custom-agents.d.ts +81 -0
- package/dist/acp-harnesses/custom-agents.d.ts.map +1 -0
- package/dist/acp-harnesses/custom-agents.js +361 -0
- package/dist/acp-harnesses/custom-agents.js.map +1 -0
- package/dist/acp-harnesses/headless-launch.d.ts +34 -0
- package/dist/acp-harnesses/headless-launch.d.ts.map +1 -0
- package/dist/acp-harnesses/headless-launch.js +67 -0
- package/dist/acp-harnesses/headless-launch.js.map +1 -0
- package/dist/acp-harnesses/index.d.ts +18 -0
- package/dist/acp-harnesses/index.d.ts.map +1 -0
- package/dist/acp-harnesses/index.js +58 -0
- package/dist/acp-harnesses/index.js.map +1 -0
- package/dist/acp-harnesses/install-state.d.ts +86 -0
- package/dist/acp-harnesses/install-state.d.ts.map +1 -0
- package/dist/acp-harnesses/install-state.js +322 -0
- package/dist/acp-harnesses/install-state.js.map +1 -0
- package/dist/acp-harnesses/installer.d.ts +145 -0
- package/dist/acp-harnesses/installer.d.ts.map +1 -0
- package/dist/acp-harnesses/installer.js +716 -0
- package/dist/acp-harnesses/installer.js.map +1 -0
- package/dist/acp-harnesses/known-agents.d.ts +154 -0
- package/dist/acp-harnesses/known-agents.d.ts.map +1 -0
- package/dist/acp-harnesses/known-agents.js +240 -0
- package/dist/acp-harnesses/known-agents.js.map +1 -0
- package/dist/acp-harnesses/launcher.d.ts +27 -0
- package/dist/acp-harnesses/launcher.d.ts.map +1 -0
- package/dist/acp-harnesses/launcher.js +64 -0
- package/dist/acp-harnesses/launcher.js.map +1 -0
- package/dist/acp-harnesses/registry-fetch.d.ts +42 -0
- package/dist/acp-harnesses/registry-fetch.d.ts.map +1 -0
- package/dist/acp-harnesses/registry-fetch.js +132 -0
- package/dist/acp-harnesses/registry-fetch.js.map +1 -0
- package/dist/acp-harnesses/registry.d.ts +36 -0
- package/dist/acp-harnesses/registry.d.ts.map +1 -0
- package/dist/acp-harnesses/registry.js +307 -0
- package/dist/acp-harnesses/registry.js.map +1 -0
- package/dist/acp-runtime/errors.d.ts +7 -0
- package/dist/acp-runtime/errors.d.ts.map +1 -0
- package/dist/acp-runtime/errors.js +17 -0
- package/dist/acp-runtime/errors.js.map +1 -0
- package/dist/acp-runtime/fork-support.d.ts +8 -0
- package/dist/acp-runtime/fork-support.d.ts.map +1 -0
- package/dist/acp-runtime/fork-support.js +20 -0
- package/dist/acp-runtime/fork-support.js.map +1 -0
- package/dist/acp-runtime/index.d.ts +11 -0
- package/dist/acp-runtime/index.d.ts.map +1 -0
- package/dist/acp-runtime/index.js +6 -0
- package/dist/acp-runtime/index.js.map +1 -0
- package/dist/acp-runtime/probe.d.ts +103 -0
- package/dist/acp-runtime/probe.d.ts.map +1 -0
- package/dist/acp-runtime/probe.js +881 -0
- package/dist/acp-runtime/probe.js.map +1 -0
- package/dist/acp-runtime/runtime.d.ts +7 -0
- package/dist/acp-runtime/runtime.d.ts.map +1 -0
- package/dist/acp-runtime/runtime.js +26 -0
- package/dist/acp-runtime/runtime.js.map +1 -0
- package/dist/acp-runtime/session.d.ts +87 -0
- package/dist/acp-runtime/session.d.ts.map +1 -0
- package/dist/acp-runtime/session.js +1071 -0
- package/dist/acp-runtime/session.js.map +1 -0
- package/dist/acp-runtime/spawners/node.d.ts +5 -0
- package/dist/acp-runtime/spawners/node.d.ts.map +1 -0
- package/dist/acp-runtime/spawners/node.js +244 -0
- package/dist/acp-runtime/spawners/node.js.map +1 -0
- package/dist/acp-runtime/types.d.ts +180 -0
- package/dist/acp-runtime/types.d.ts.map +1 -0
- package/dist/acp-runtime/types.js +2 -0
- package/dist/acp-runtime/types.js.map +1 -0
- package/dist/agent-contract/acp.d.ts +4 -0
- package/dist/agent-contract/acp.d.ts.map +1 -0
- package/dist/agent-contract/acp.js +273 -0
- package/dist/agent-contract/acp.js.map +1 -0
- package/dist/agent-contract/index.d.ts +125 -0
- package/dist/agent-contract/index.d.ts.map +1 -0
- package/dist/agent-contract/index.js +102 -0
- package/dist/agent-contract/index.js.map +1 -0
- package/dist/agent-contract/managed.d.ts +5 -0
- package/dist/agent-contract/managed.d.ts.map +1 -0
- package/dist/agent-contract/managed.js +242 -0
- package/dist/agent-contract/managed.js.map +1 -0
- package/dist/agent-ui/index.d.ts +170 -0
- package/dist/agent-ui/index.d.ts.map +1 -0
- package/dist/agent-ui/index.js +853 -0
- package/dist/agent-ui/index.js.map +1 -0
- package/dist/agent-ui/presentation.d.ts +30 -0
- package/dist/agent-ui/presentation.d.ts.map +1 -0
- package/dist/agent-ui/presentation.js +79 -0
- package/dist/agent-ui/presentation.js.map +1 -0
- package/dist/agent-ui/react.d.ts +50 -0
- package/dist/agent-ui/react.d.ts.map +1 -0
- package/dist/agent-ui/react.js +334 -0
- package/dist/agent-ui/react.js.map +1 -0
- package/dist/brand/index.d.ts +17 -0
- package/dist/brand/index.d.ts.map +1 -0
- package/dist/brand/index.js +119 -0
- package/dist/brand/index.js.map +1 -0
- package/dist/brand/openma-logo-mark.svg +7 -0
- package/dist/brand/tokens.css +77 -0
- package/dist/brand/website.css +67 -0
- package/dist/chat-ui/acp.d.ts +26 -0
- package/dist/chat-ui/acp.d.ts.map +1 -0
- package/dist/chat-ui/acp.js +166 -0
- package/dist/chat-ui/acp.js.map +1 -0
- package/dist/chat-ui/components.d.ts +230 -0
- package/dist/chat-ui/components.d.ts.map +1 -0
- package/dist/chat-ui/components.js +561 -0
- package/dist/chat-ui/components.js.map +1 -0
- package/dist/chat-ui/composer-drafts.d.ts +21 -0
- package/dist/chat-ui/composer-drafts.d.ts.map +1 -0
- package/dist/chat-ui/composer-drafts.js +58 -0
- package/dist/chat-ui/composer-drafts.js.map +1 -0
- package/dist/chat-ui/controller.d.ts +61 -0
- package/dist/chat-ui/controller.d.ts.map +1 -0
- package/dist/chat-ui/controller.js +218 -0
- package/dist/chat-ui/controller.js.map +1 -0
- package/dist/chat-ui/index.d.ts +8 -0
- package/dist/chat-ui/index.d.ts.map +1 -0
- package/dist/chat-ui/index.js +8 -0
- package/dist/chat-ui/index.js.map +1 -0
- package/dist/chat-ui/markdown.d.ts +37 -0
- package/dist/chat-ui/markdown.d.ts.map +1 -0
- package/dist/chat-ui/markdown.js +33 -0
- package/dist/chat-ui/markdown.js.map +1 -0
- package/dist/chat-ui/presentation.d.ts +34 -0
- package/dist/chat-ui/presentation.d.ts.map +1 -0
- package/dist/chat-ui/presentation.js +191 -0
- package/dist/chat-ui/presentation.js.map +1 -0
- package/dist/chat-ui/styles.css +815 -0
- package/dist/chat-ui/utils.d.ts +14 -0
- package/dist/chat-ui/utils.d.ts.map +1 -0
- package/dist/chat-ui/utils.js +71 -0
- package/dist/chat-ui/utils.js.map +1 -0
- package/dist/local-runtime/checkpoint.d.ts +28 -0
- package/dist/local-runtime/checkpoint.d.ts.map +1 -0
- package/dist/local-runtime/checkpoint.js +2 -0
- package/dist/local-runtime/checkpoint.js.map +1 -0
- package/dist/local-runtime/daemon-connection.d.ts +27 -0
- package/dist/local-runtime/daemon-connection.d.ts.map +1 -0
- package/dist/local-runtime/daemon-connection.js +161 -0
- package/dist/local-runtime/daemon-connection.js.map +1 -0
- package/dist/local-runtime/daemon-host.d.ts +39 -0
- package/dist/local-runtime/daemon-host.d.ts.map +1 -0
- package/dist/local-runtime/daemon-host.js +88 -0
- package/dist/local-runtime/daemon-host.js.map +1 -0
- package/dist/local-runtime/index.d.ts +6 -0
- package/dist/local-runtime/index.d.ts.map +1 -0
- package/dist/local-runtime/index.js +5 -0
- package/dist/local-runtime/index.js.map +1 -0
- package/dist/local-runtime/runtime.d.ts +36 -0
- package/dist/local-runtime/runtime.d.ts.map +1 -0
- package/dist/local-runtime/runtime.js +82 -0
- package/dist/local-runtime/runtime.js.map +1 -0
- package/dist/local-runtime/session-host.d.ts +62 -0
- package/dist/local-runtime/session-host.d.ts.map +1 -0
- package/dist/local-runtime/session-host.js +477 -0
- package/dist/local-runtime/session-host.js.map +1 -0
- package/dist/managed-runtime/acp-subagents.d.ts +14 -0
- package/dist/managed-runtime/acp-subagents.d.ts.map +1 -0
- package/dist/managed-runtime/acp-subagents.js +67 -0
- package/dist/managed-runtime/acp-subagents.js.map +1 -0
- package/dist/managed-runtime/claimed-environment-work.d.ts +61 -0
- package/dist/managed-runtime/claimed-environment-work.d.ts.map +1 -0
- package/dist/managed-runtime/claimed-environment-work.js +170 -0
- package/dist/managed-runtime/claimed-environment-work.js.map +1 -0
- package/dist/managed-runtime/contracts.d.ts +31 -0
- package/dist/managed-runtime/contracts.d.ts.map +1 -0
- package/dist/managed-runtime/contracts.js +2 -0
- package/dist/managed-runtime/contracts.js.map +1 -0
- package/dist/managed-runtime/http-control.d.ts +67 -0
- package/dist/managed-runtime/http-control.d.ts.map +1 -0
- package/dist/managed-runtime/http-control.js +465 -0
- package/dist/managed-runtime/http-control.js.map +1 -0
- package/dist/managed-runtime/index.d.ts +89 -0
- package/dist/managed-runtime/index.d.ts.map +1 -0
- package/dist/managed-runtime/index.js +215 -0
- package/dist/managed-runtime/index.js.map +1 -0
- package/dist/managed-runtime/input-identity.d.ts +2 -0
- package/dist/managed-runtime/input-identity.d.ts.map +1 -0
- package/dist/managed-runtime/input-identity.js +2 -0
- package/dist/managed-runtime/input-identity.js.map +1 -0
- package/dist/managed-runtime/managed-event-projector.d.ts +24 -0
- package/dist/managed-runtime/managed-event-projector.d.ts.map +1 -0
- package/dist/managed-runtime/managed-event-projector.js +333 -0
- package/dist/managed-runtime/managed-event-projector.js.map +1 -0
- package/dist/managed-runtime/semantic-recovery.d.ts +61 -0
- package/dist/managed-runtime/semantic-recovery.d.ts.map +1 -0
- package/dist/managed-runtime/semantic-recovery.js +167 -0
- package/dist/managed-runtime/semantic-recovery.js.map +1 -0
- package/dist/project-ui/CreateProjectDialog.d.ts +15 -0
- package/dist/project-ui/CreateProjectDialog.d.ts.map +1 -0
- package/dist/project-ui/CreateProjectDialog.js +87 -0
- package/dist/project-ui/CreateProjectDialog.js.map +1 -0
- package/dist/project-ui/ProjectComposer.d.ts +13 -0
- package/dist/project-ui/ProjectComposer.d.ts.map +1 -0
- package/dist/project-ui/ProjectComposer.js +70 -0
- package/dist/project-ui/ProjectComposer.js.map +1 -0
- package/dist/project-ui/ProjectConversation.d.ts +10 -0
- package/dist/project-ui/ProjectConversation.d.ts.map +1 -0
- package/dist/project-ui/ProjectConversation.js +28 -0
- package/dist/project-ui/ProjectConversation.js.map +1 -0
- package/dist/project-ui/ProjectMessageAttachments.d.ts +4 -0
- package/dist/project-ui/ProjectMessageAttachments.d.ts.map +1 -0
- package/dist/project-ui/ProjectMessageAttachments.js +28 -0
- package/dist/project-ui/ProjectMessageAttachments.js.map +1 -0
- package/dist/project-ui/ProjectSettings.d.ts +8 -0
- package/dist/project-ui/ProjectSettings.d.ts.map +1 -0
- package/dist/project-ui/ProjectSettings.js +65 -0
- package/dist/project-ui/ProjectSettings.js.map +1 -0
- package/dist/project-ui/Projects.d.ts +18 -0
- package/dist/project-ui/Projects.d.ts.map +1 -0
- package/dist/project-ui/Projects.js +377 -0
- package/dist/project-ui/Projects.js.map +1 -0
- package/dist/project-ui/client.d.ts +234 -0
- package/dist/project-ui/client.d.ts.map +1 -0
- package/dist/project-ui/client.js +42 -0
- package/dist/project-ui/client.js.map +1 -0
- package/dist/project-ui/controls.d.ts +15 -0
- package/dist/project-ui/controls.d.ts.map +1 -0
- package/dist/project-ui/controls.js +17 -0
- package/dist/project-ui/controls.js.map +1 -0
- package/dist/project-ui/index.d.ts +20 -0
- package/dist/project-ui/index.d.ts.map +1 -0
- package/dist/project-ui/index.js +17 -0
- package/dist/project-ui/index.js.map +1 -0
- package/dist/project-ui/project-coordinator.d.ts +3 -0
- package/dist/project-ui/project-coordinator.d.ts.map +1 -0
- package/dist/project-ui/project-coordinator.js +12 -0
- package/dist/project-ui/project-coordinator.js.map +1 -0
- package/dist/project-ui/project-goals.d.ts +48 -0
- package/dist/project-ui/project-goals.d.ts.map +1 -0
- package/dist/project-ui/project-goals.js +169 -0
- package/dist/project-ui/project-goals.js.map +1 -0
- package/dist/project-ui/projects-query.d.ts +19 -0
- package/dist/project-ui/projects-query.d.ts.map +1 -0
- package/dist/project-ui/projects-query.js +132 -0
- package/dist/project-ui/projects-query.js.map +1 -0
- package/dist/project-ui/styles.css +847 -0
- package/dist/protocol/acp/index.d.ts +52 -0
- package/dist/protocol/acp/index.d.ts.map +1 -0
- package/dist/protocol/acp/index.js +1056 -0
- package/dist/protocol/acp/index.js.map +1 -0
- package/dist/protocol/cursor-cloud/index.d.ts +74 -0
- package/dist/protocol/cursor-cloud/index.d.ts.map +1 -0
- package/dist/protocol/cursor-cloud/index.js +249 -0
- package/dist/protocol/cursor-cloud/index.js.map +1 -0
- package/dist/protocol/managed/index.d.ts +32 -0
- package/dist/protocol/managed/index.d.ts.map +1 -0
- package/dist/protocol/managed/index.js +646 -0
- package/dist/protocol/managed/index.js.map +1 -0
- package/dist/protocol/managed/input-identity.d.ts +3 -0
- package/dist/protocol/managed/input-identity.d.ts.map +1 -0
- package/dist/protocol/managed/input-identity.js +6 -0
- package/dist/protocol/managed/input-identity.js.map +1 -0
- package/dist/protocol/openai-agents/index.d.ts +102 -0
- package/dist/protocol/openai-agents/index.d.ts.map +1 -0
- package/dist/protocol/openai-agents/index.js +142 -0
- package/dist/protocol/openai-agents/index.js.map +1 -0
- package/dist/session-events/acp-system-notices.d.ts +10 -0
- package/dist/session-events/acp-system-notices.d.ts.map +1 -0
- package/dist/session-events/acp-system-notices.js +46 -0
- package/dist/session-events/acp-system-notices.js.map +1 -0
- package/dist/session-events/acp.d.ts +214 -0
- package/dist/session-events/acp.d.ts.map +1 -0
- package/dist/session-events/acp.js +956 -0
- package/dist/session-events/acp.js.map +1 -0
- package/dist/session-events/managed.d.ts +141 -0
- package/dist/session-events/managed.d.ts.map +1 -0
- package/dist/session-events/managed.js +324 -0
- package/dist/session-events/managed.js.map +1 -0
- package/dist/session-events/openma.d.ts +304 -0
- package/dist/session-events/openma.d.ts.map +1 -0
- package/dist/session-events/openma.js +438 -0
- package/dist/session-events/openma.js.map +1 -0
- package/dist/session-kernel/index.d.ts +118 -0
- package/dist/session-kernel/index.d.ts.map +1 -0
- package/dist/session-kernel/index.js +215 -0
- package/dist/session-kernel/index.js.map +1 -0
- package/dist/session-orchestrator/index.d.ts +71 -0
- package/dist/session-orchestrator/index.d.ts.map +1 -0
- package/dist/session-orchestrator/index.js +177 -0
- package/dist/session-orchestrator/index.js.map +1 -0
- package/dist/session-ui/index.d.ts +96 -0
- package/dist/session-ui/index.d.ts.map +1 -0
- package/dist/session-ui/index.js +277 -0
- package/dist/session-ui/index.js.map +1 -0
- package/package.json +222 -4
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { ArrowLeftIcon } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { normalizeProjectFolders } from "./client.js";
|
|
6
|
+
import { ProjectButton, projectErrorText } from "./controls.js";
|
|
7
|
+
import { ProjectFolderList } from "./CreateProjectDialog.js";
|
|
8
|
+
import { ProjectEditor } from "./Projects.js";
|
|
9
|
+
import { useProjectView } from "./projects-query.js";
|
|
10
|
+
export function ProjectSettings({ client, projectId, onBack, onDeleted, }) {
|
|
11
|
+
const query = useProjectView(client, projectId, 0);
|
|
12
|
+
const [notice, setNotice] = useState("");
|
|
13
|
+
if (query.isPending)
|
|
14
|
+
return _jsx("p", { role: "status", className: "project-settings", children: "Loading\u2026" });
|
|
15
|
+
if (query.error || !query.data) {
|
|
16
|
+
return _jsx("p", { role: "alert", className: "project-settings", children: projectErrorText(query.error ?? "Project not found") });
|
|
17
|
+
}
|
|
18
|
+
return (_jsxs("div", { className: "project-settings", children: [notice ? _jsx("p", { role: "status", children: notice }) : null, _jsx(ProjectSettingsForm, { client: client, project: query.data.project, view: query.data, onBack: onBack, onDeleted: onDeleted, refresh: query.reload, onSaved: () => setNotice("Project settings saved.") }, `${projectId}:${query.data.project.updated_at}`)] }));
|
|
19
|
+
}
|
|
20
|
+
function ProjectSettingsForm({ client, project, view, onBack, onDeleted, refresh, onSaved, }) {
|
|
21
|
+
const [name, setName] = useState(project.name);
|
|
22
|
+
const [folders, setFolders] = useState(project.source_folders);
|
|
23
|
+
const [coordinator, setCoordinator] = useState(false);
|
|
24
|
+
const [busy, setBusy] = useState(false);
|
|
25
|
+
const [error, setError] = useState("");
|
|
26
|
+
const save = async () => {
|
|
27
|
+
setBusy(true);
|
|
28
|
+
setError("");
|
|
29
|
+
const normalized = normalizeProjectFolders({
|
|
30
|
+
source_folders: folders,
|
|
31
|
+
primary_folder: folders[0],
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
await client.save({
|
|
35
|
+
project_id: project.id,
|
|
36
|
+
name: name.trim(),
|
|
37
|
+
source_folders: [...normalized.source_folders],
|
|
38
|
+
primary_folder: normalized.primary_folder,
|
|
39
|
+
});
|
|
40
|
+
await refresh();
|
|
41
|
+
onSaved();
|
|
42
|
+
}
|
|
43
|
+
catch (cause) {
|
|
44
|
+
setError(projectErrorText(cause));
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
setBusy(false);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return (_jsxs(_Fragment, { children: [_jsxs("header", { children: [_jsx("h1", { children: "Project settings" }), onBack ? (_jsxs("button", { type: "button", onClick: onBack, children: [_jsx(ArrowLeftIcon, { className: "size-3.5", "aria-hidden": "true" }), _jsx("span", { children: project.name })] })) : null] }), _jsxs("form", { id: "project-settings-form", className: "project-form", onSubmit: (event) => {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
void save();
|
|
53
|
+
}, children: [_jsxs("section", { children: [_jsx("h2", { children: "General" }), _jsxs("label", { className: "project-field", children: ["Name", _jsx("input", { "aria-label": "Project name", required: true, value: name, onChange: (event) => setName(event.target.value) })] })] }), _jsxs("section", { children: [_jsx("h2", { children: "Folders" }), _jsx(ProjectFolderList, { folders: folders, onAdd: client.pickFolders ? () => {
|
|
54
|
+
void client.pickFolders?.().then((paths) => {
|
|
55
|
+
setFolders((current) => [...new Set([...current, ...paths])]);
|
|
56
|
+
}).catch((cause) => setError(projectErrorText(cause)));
|
|
57
|
+
} : undefined, onMakePrimary: (folder) => setFolders((current) => [folder, ...current.filter((path) => path !== folder)]), onRemove: (folder) => setFolders((current) => current.filter((path) => path !== folder)) })] }), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsx("div", { className: "project-actions", children: _jsx(ProjectButton, { type: "submit", disabled: busy || !name.trim(), children: "Save" }) })] }), _jsxs("section", { children: [_jsx("h2", { children: "Execution" }), _jsx("p", { className: "project-note", children: "Choose the coordinator, worker, and where the project runs." }), _jsx(ProjectButton, { variant: "outline", onClick: () => setCoordinator(true), children: "Configure" })] }), coordinator ? (_jsx(ProjectEditor, { client: client, project: project, config: view.config ?? undefined, close: () => setCoordinator(false), saved: async () => {
|
|
58
|
+
setCoordinator(false);
|
|
59
|
+
await refresh();
|
|
60
|
+
}, removed: async () => {
|
|
61
|
+
setCoordinator(false);
|
|
62
|
+
onDeleted?.();
|
|
63
|
+
} })) : null] }));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=ProjectSettings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectSettings.js","sourceRoot":"","sources":["../../src/project-ui/ProjectSettings.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProjectClient, ProjectInfo, ProjectWorkConfig } from "./client.js";
|
|
2
|
+
export declare function ProjectsPage({ client, projectId: controlledProjectId, onProjectIdChange, refreshIntervalMs, }: {
|
|
3
|
+
client: ProjectClient;
|
|
4
|
+
/** With `onProjectIdChange`, the host owns which project is open. */
|
|
5
|
+
projectId?: string | null;
|
|
6
|
+
onProjectIdChange?: (projectId: string | null) => void;
|
|
7
|
+
/** Refetch interval for an open project. `0` polls only after local actions. */
|
|
8
|
+
refreshIntervalMs?: number;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
10
|
+
export declare function ProjectEditor({ client, project, config, close, saved, removed, }: {
|
|
11
|
+
client: ProjectClient;
|
|
12
|
+
project?: ProjectInfo;
|
|
13
|
+
config?: ProjectWorkConfig;
|
|
14
|
+
close: () => void;
|
|
15
|
+
saved: (id: string) => Promise<void>;
|
|
16
|
+
removed: () => Promise<void>;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=Projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Projects.d.ts","sourceRoot":"","sources":["../../src/project-ui/Projects.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,aAAa,EAGb,WAAW,EAEX,iBAAiB,EAIlB,MAAM,aAAa,CAAC;AAmBrB,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EAAE,mBAAmB,EAC9B,iBAAiB,EACjB,iBAAwB,GACzB,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,+BAwHA;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,EACP,MAAM,EACN,KAAK,EACL,KAAK,EACL,OAAO,GACR,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,+BAwRA"}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { ArrowLeftIcon, CheckIcon, CirclePauseIcon, CirclePlayIcon, FileTextIcon, FolderIcon, ListTodoIcon, PencilIcon, PlusIcon, SettingsIcon, XIcon, } from "lucide-react";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import { normalizeProjectFolders } from "./client.js";
|
|
6
|
+
import { ProjectButton, ProjectDialog, projectErrorText } from "./controls.js";
|
|
7
|
+
import { CreateProjectDialog, ProjectFolderList } from "./CreateProjectDialog.js";
|
|
8
|
+
import { ProjectComposer } from "./ProjectComposer.js";
|
|
9
|
+
import { ProjectConversation } from "./ProjectConversation.js";
|
|
10
|
+
import { ProjectMessageAttachments } from "./ProjectMessageAttachments.js";
|
|
11
|
+
import { defaultCoordinatorConfig } from "./project-coordinator.js";
|
|
12
|
+
import { projectCoordinatorTurns, projectGoalPresentation, projectOutcomeLabel, projectResponseText, projectThreads, } from "./project-goals.js";
|
|
13
|
+
import { useProjectView, useProjects } from "./projects-query.js";
|
|
14
|
+
const CONTROLS = ["delegate", "steer", "cancel", "complete"];
|
|
15
|
+
export function ProjectsPage({ client, projectId: controlledProjectId, onProjectIdChange, refreshIntervalMs = 1500, }) {
|
|
16
|
+
const projects = useProjects(client);
|
|
17
|
+
const controlled = onProjectIdChange !== undefined;
|
|
18
|
+
const [uncontrolledId, setUncontrolledId] = useState(null);
|
|
19
|
+
const projectId = controlled ? controlledProjectId ?? null : uncontrolledId;
|
|
20
|
+
const setProjectId = (next) => {
|
|
21
|
+
if (!controlled)
|
|
22
|
+
setUncontrolledId(next);
|
|
23
|
+
onProjectIdChange?.(next);
|
|
24
|
+
};
|
|
25
|
+
const workspace = useProjectView(client, projectId, refreshIntervalMs);
|
|
26
|
+
const [search, setSearch] = useState("");
|
|
27
|
+
const [creating, setCreating] = useState(false);
|
|
28
|
+
const [editing, setEditing] = useState(false);
|
|
29
|
+
const project = workspace.data?.project;
|
|
30
|
+
const visible = projects.data?.filter((item) => item.name.toLowerCase().includes(search.toLowerCase()));
|
|
31
|
+
return (_jsxs("div", { className: "projects-page", children: [projectId && workspace.isPending ? (_jsx("div", { className: "project-loading", role: "status", children: "Opening project\u2026" })) : null, workspace.error && projectId ? (_jsxs("div", { role: "alert", className: "project-error", children: [projectErrorText(workspace.error), " ", _jsx("button", { type: "button", onClick: () => setProjectId(null), children: "Back to projects" })] })) : null, !projectId ? (_jsxs("div", { className: "projects-index", children: [_jsxs("header", { className: "projects-list-header", children: [_jsxs("div", { children: [_jsx("h1", { children: "Projects" }), _jsx("p", { children: "Keep your conversations, knowledge, and work together." })] }), _jsxs(ProjectButton, { onClick: () => setCreating(true), children: [_jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }), "New project"] })] }), _jsx("input", { className: "projects-search", "aria-label": "Search projects", placeholder: "Search projects", value: search, onChange: (event) => setSearch(event.target.value) }), projects.error ? _jsx("p", { role: "alert", children: projectErrorText(projects.error) }) : null, projects.isPending ? _jsx("p", { role: "status", children: "Loading projects\u2026" }) : (_jsx("div", { className: "projects-grid", children: visible?.map((item) => (_jsxs("button", { type: "button", "data-project-id": item.id, className: "project-card", onClick: () => setProjectId(item.id), children: [_jsx(FolderIcon, { className: "size-5", "aria-hidden": "true" }), _jsx("h2", { children: item.name }), _jsx("p", { children: item.primary_folder || "Conversations and project knowledge" }), _jsxs("span", { children: ["Updated ", new Date(item.updated_at).toLocaleDateString()] })] }, item.id))) })), !projects.isPending && !projects.data?.length ? (_jsxs("div", { className: "projects-empty", children: [_jsx(FolderIcon, { className: "size-9", "aria-hidden": "true" }), _jsx("h2", { children: "A place for work that continues" }), _jsx("p", { children: "Create a project, add what your agents should know, and start a conversation." }), _jsx(ProjectButton, { variant: "outline", onClick: () => setCreating(true), children: "Create your first project" })] })) : null, projects.data?.length && visible && !visible.length ? (_jsxs("p", { className: "projects-empty", children: ["No projects match \u201C", search, "\u201D."] })) : null] })) : workspace.data ? (_jsx(ProjectWorkspace, { client: client, view: workspace.data, refresh: async () => {
|
|
32
|
+
await Promise.all([projects.reload(), workspace.reload()]);
|
|
33
|
+
}, edit: () => setEditing(true) }, projectId)) : null, _jsx(CreateProjectDialog, { client: client, open: creating && !projectId, onOpenChange: setCreating, onCreated: (created) => {
|
|
34
|
+
void projects.reload();
|
|
35
|
+
setProjectId(created.id);
|
|
36
|
+
} }), editing && project ? (_jsx(ProjectEditor, { client: client, project: project, config: workspace.data?.config ?? undefined, close: () => setEditing(false), saved: async (id) => {
|
|
37
|
+
setEditing(false);
|
|
38
|
+
await projects.reload();
|
|
39
|
+
await workspace.reload();
|
|
40
|
+
setProjectId(id);
|
|
41
|
+
}, removed: async () => {
|
|
42
|
+
setEditing(false);
|
|
43
|
+
setProjectId(null);
|
|
44
|
+
await projects.reload();
|
|
45
|
+
} })) : null] }));
|
|
46
|
+
}
|
|
47
|
+
export function ProjectEditor({ client, project, config, close, saved, removed, }) {
|
|
48
|
+
const creating = !project;
|
|
49
|
+
const [draft, setDraft] = useState(() => config ?? defaultCoordinatorConfig(project?.id ?? `proj-${crypto.randomUUID()}`));
|
|
50
|
+
const [name, setName] = useState(project?.name ?? "");
|
|
51
|
+
const [folders, setFolders] = useState(() => uniqueFolders(project));
|
|
52
|
+
const [busy, setBusy] = useState(false);
|
|
53
|
+
const [error, setError] = useState("");
|
|
54
|
+
const [section, setSection] = useState("general");
|
|
55
|
+
const cloud = draft.execution?.kind === "cloud";
|
|
56
|
+
const field = (key, value) => {
|
|
57
|
+
setDraft((current) => ({ ...current, [key]: value }));
|
|
58
|
+
};
|
|
59
|
+
const addFolders = async () => {
|
|
60
|
+
if (!client.pickFolders)
|
|
61
|
+
return;
|
|
62
|
+
try {
|
|
63
|
+
const selected = await client.pickFolders();
|
|
64
|
+
setFolders((current) => [...new Set([...current, ...selected])]);
|
|
65
|
+
}
|
|
66
|
+
catch (cause) {
|
|
67
|
+
setError(projectErrorText(cause));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const save = async () => {
|
|
71
|
+
if (busy || !name.trim())
|
|
72
|
+
return;
|
|
73
|
+
setBusy(true);
|
|
74
|
+
setError("");
|
|
75
|
+
try {
|
|
76
|
+
if (!creating && (!draft.coordinatorAgent.trim() || !draft.workerAgent.trim())) {
|
|
77
|
+
setSection("agents");
|
|
78
|
+
throw new Error("Choose a coordinator and worker agent to finish setup.");
|
|
79
|
+
}
|
|
80
|
+
if (cloud && (!draft.coordinatorEnvironment?.trim() || !draft.workerEnvironment?.trim())) {
|
|
81
|
+
setSection("agents");
|
|
82
|
+
throw new Error("Choose an environment for both agents.");
|
|
83
|
+
}
|
|
84
|
+
const normalized = normalizeProjectFolders({
|
|
85
|
+
source_folders: folders,
|
|
86
|
+
primary_folder: folders[0],
|
|
87
|
+
});
|
|
88
|
+
await client.save({
|
|
89
|
+
project_id: draft.projectId,
|
|
90
|
+
name: name.trim(),
|
|
91
|
+
source_folders: [...normalized.source_folders],
|
|
92
|
+
primary_folder: normalized.primary_folder,
|
|
93
|
+
});
|
|
94
|
+
await client.saveWork(draft);
|
|
95
|
+
await saved(draft.projectId);
|
|
96
|
+
}
|
|
97
|
+
catch (cause) {
|
|
98
|
+
setError(projectErrorText(cause));
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
setBusy(false);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const folderPicker = (_jsx(ProjectFolderList, { folders: folders, onAdd: client.pickFolders ? () => void addFolders() : undefined, onMakePrimary: (folder) => setFolders((current) => [folder, ...current.filter((path) => path !== folder)]), onRemove: (folder) => setFolders((current) => current.filter((path) => path !== folder)) }));
|
|
105
|
+
return (_jsx(ProjectDialog, { open: true, wide: true, title: creating ? "New project" : "Coordinator settings", description: creating
|
|
106
|
+
? "Start with a goal. You can configure your agents later."
|
|
107
|
+
: "Manage your project’s context and execution.", onClose: close, children: _jsxs("form", { className: "project-form", onSubmit: (event) => {
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
void save();
|
|
110
|
+
}, children: [creating ? (_jsxs("div", { className: "space-y-5", children: [_jsx(Basics, { name: name, setName: setName, draft: draft, field: field }), _jsxs("details", { children: [_jsx("summary", { children: "Add context (optional)" }), _jsxs("div", { children: [folderPicker, _jsxs("label", { className: "project-field", children: ["Context", _jsx("textarea", { "aria-label": "Context", rows: 3, value: draft.context, onChange: (event) => field("context", event.target.value) })] })] })] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "project-tabs", role: "tablist", "aria-label": "Project settings sections", children: ["general", "context", "agents"].map((item) => (_jsx("button", { type: "button", role: "tab", "aria-selected": section === item, onClick: () => setSection(item), children: item === "general" ? "General" : item === "context" ? "Context" : "Agents" }, item))) }), section === "general" ? (_jsxs("div", { children: [_jsx(Basics, { name: name, setName: setName, draft: draft, field: field }), _jsxs("details", { children: [_jsx("summary", { children: "Advanced" }), _jsxs("label", { className: "project-field", children: ["Conversation continuity", _jsxs("select", { "aria-label": "Conversation continuity", value: draft.continuity, onChange: (event) => field("continuity", event.target.value), children: [_jsx("option", { value: "per-scope", children: "Continue across this project" }), _jsx("option", { value: "per-run", children: "Separate conversations for each run" })] })] }), _jsxs("fieldset", { children: [_jsx("legend", { children: "Coordinator controls" }), _jsx("div", { children: CONTROLS.map((control) => (_jsxs("label", { className: "project-check", children: [_jsx("input", { type: "checkbox", checked: draft.controls.includes(control), onChange: (event) => field("controls", toggleControl(draft.controls, control, event.target.checked)) }), control] }, control))) })] })] })] })) : null, section === "context" ? (_jsxs("div", { children: [cloud ? (_jsx(RepositoryFields, { draft: draft, field: field })) : (_jsxs("div", { children: [_jsx("p", { children: "Source folders" }), folderPicker, _jsxs("label", { className: "project-field", children: ["Base branch or commit", _jsx("input", { "aria-label": "Base branch or commit", value: draft.baseRef ?? "", onChange: (event) => field("baseRef", event.target.value) })] }), _jsx("p", { className: "project-note", children: "New threads start from committed code. Existing threads keep their workspace." })] })), _jsxs("label", { className: "project-field", children: ["Instructions", _jsx("textarea", { "aria-label": "Instructions", rows: 3, value: draft.instructions, onChange: (event) => field("instructions", event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Context", _jsx("textarea", { "aria-label": "Context", rows: 3, value: draft.context, onChange: (event) => field("context", event.target.value) })] })] })) : null, section === "agents" ? (_jsxs("div", { children: [_jsxs("label", { className: "project-field", children: ["Execution location", _jsxs("select", { "aria-label": "Execution location", value: cloud ? "cloud" : "local", disabled: Boolean(config?.coordinatorAgent), onChange: (event) => {
|
|
111
|
+
const execution = event.target.value === "cloud"
|
|
112
|
+
? { kind: "cloud", ...(draft.execution?.kind === "cloud" ? draft.execution : {}) }
|
|
113
|
+
: { kind: "local" };
|
|
114
|
+
setDraft((current) => ({ ...current, execution }));
|
|
115
|
+
}, children: [_jsx("option", { value: "local", children: "This computer" }), _jsx("option", { value: "cloud", children: "Cloud" })] })] }), _jsx("p", { className: "project-note", children: cloud
|
|
116
|
+
? "Runs through the host’s Projects worker."
|
|
117
|
+
: "The host needs to stay available while agents work." }), _jsxs("label", { className: "project-field", children: ["Coordinator agent", _jsx("input", { "aria-label": "Coordinator agent", value: draft.coordinatorAgent, onChange: (event) => field("coordinatorAgent", event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Worker agent", _jsx("input", { "aria-label": "Worker agent", value: draft.workerAgent, onChange: (event) => field("workerAgent", event.target.value) })] }), cloud ? (_jsxs(_Fragment, { children: [_jsxs("label", { className: "project-field", children: ["Coordinator environment", _jsx("input", { "aria-label": "Coordinator environment", value: draft.coordinatorEnvironment ?? "", onChange: (event) => field("coordinatorEnvironment", event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Worker environment", _jsx("input", { "aria-label": "Worker environment", value: draft.workerEnvironment ?? "", onChange: (event) => field("workerEnvironment", event.target.value) })] })] })) : null] })) : null] })), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsxs("div", { className: "project-actions", children: [!creating && project ? (_jsx(ProjectButton, { variant: "ghost", disabled: busy, style: { marginRight: "auto" }, onClick: () => {
|
|
118
|
+
setBusy(true);
|
|
119
|
+
setError("");
|
|
120
|
+
void client.delete(project.id).then(removed).catch((cause) => {
|
|
121
|
+
setError(projectErrorText(cause));
|
|
122
|
+
}).finally(() => setBusy(false));
|
|
123
|
+
}, children: "Delete project" })) : null, _jsx(ProjectButton, { variant: "ghost", disabled: busy, onClick: close, children: "Cancel" }), _jsx(ProjectButton, { type: "submit", disabled: busy || !name.trim(), children: creating ? "Create project" : "Save project" })] })] }) }));
|
|
124
|
+
}
|
|
125
|
+
function Basics({ name, setName, draft, field, }) {
|
|
126
|
+
return (_jsxs("div", { children: [_jsxs("label", { className: "project-field", children: ["Project name", _jsx("input", { required: true, value: name, onChange: (event) => setName(event.target.value), placeholder: "e.g. Improve checkout" })] }), _jsxs("label", { className: "project-field", children: ["Goal ", _jsx("span", { className: "project-note", children: "(optional)" }), _jsx("textarea", { "aria-label": "Goal", rows: 3, value: draft.description, onChange: (event) => field("description", event.target.value) })] })] }));
|
|
127
|
+
}
|
|
128
|
+
function RepositoryFields({ draft, field, }) {
|
|
129
|
+
const repositories = draft.repositories ?? [];
|
|
130
|
+
return (_jsxs("div", { children: [_jsx("p", { children: "Repositories" }), repositories.map((repo, index) => (_jsxs("div", { children: [_jsx("input", { "aria-label": `Repository ${index + 1}`, value: repo.url, placeholder: "https://github.com/owner/repo", onChange: (event) => field("repositories", repositories.map((item, itemIndex) => itemIndex === index ? { ...item, url: event.target.value } : item)) }), _jsx("input", { "aria-label": `Base reference ${index + 1}`, value: repo.baseRef ?? "", placeholder: "Default branch", onChange: (event) => field("repositories", repositories.map((item, itemIndex) => itemIndex === index ? { ...item, baseRef: event.target.value } : item)) }), _jsx(ProjectButton, { variant: "ghost", onClick: () => field("repositories", repositories.filter((_, itemIndex) => itemIndex !== index)), children: "Remove" })] }, index))), _jsxs(ProjectButton, { variant: "outline", disabled: repositories.length >= 8, onClick: () => field("repositories", [...repositories, { url: "" }]), children: [_jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }), "Add repository"] })] }));
|
|
131
|
+
}
|
|
132
|
+
function ProjectOutcomeBar({ goal, busy, onPause, onResume, }) {
|
|
133
|
+
const presentation = projectGoalPresentation(goal);
|
|
134
|
+
return (_jsxs("section", { className: `project-outcome project-outcome-${presentation.tone}`, "aria-label": "Project outcome", children: [_jsxs("div", { className: "project-outcome-copy", children: [_jsx("span", { className: "project-outcome-label", children: "Outcome" }), _jsx("strong", { title: presentation.title, children: presentation.title }), _jsxs("span", { className: "project-outcome-status", children: [projectOutcomeLabel(goal.status), presentation.budgetLabel ? ` · ${presentation.budgetLabel} tokens` : ""] })] }), _jsxs("div", { className: "project-outcome-actions", children: [presentation.actions.pause ? (_jsxs(ProjectButton, { variant: "outline", disabled: busy, onClick: onPause, children: [_jsx(CirclePauseIcon, { className: "size-3.5", "aria-hidden": "true" }), "Pause"] })) : null, presentation.actions.resume ? (_jsxs(ProjectButton, { variant: "outline", disabled: busy, onClick: onResume, children: [_jsx(CirclePlayIcon, { className: "size-3.5", "aria-hidden": "true" }), "Resume"] })) : null] })] }));
|
|
135
|
+
}
|
|
136
|
+
function ProjectWorkspace({ client, view, refresh, edit, }) {
|
|
137
|
+
const { project, config, facts } = view;
|
|
138
|
+
const [tab, setTab] = useState("conversation");
|
|
139
|
+
const [busy, setBusy] = useState(false);
|
|
140
|
+
const [error, setError] = useState("");
|
|
141
|
+
const [action, setAction] = useState(null);
|
|
142
|
+
const [resource, setResource] = useState(false);
|
|
143
|
+
const [selectedWorker, setSelectedWorker] = useState(null);
|
|
144
|
+
const [runId, setRunId] = useState(() => {
|
|
145
|
+
const last = facts.events.at(-1)?.payload;
|
|
146
|
+
const saved = payloadRecord(last).runId;
|
|
147
|
+
return typeof saved === "string" ? saved : crypto.randomUUID();
|
|
148
|
+
});
|
|
149
|
+
const uncertainSubmission = useRef(null);
|
|
150
|
+
const runScoped = config?.continuity === "per-run";
|
|
151
|
+
const sessions = facts.sessions.filter((session) => !runScoped || session.workThreadId.includes(`:run:${runId}:`));
|
|
152
|
+
const coordinator = sessions.filter((session) => session.agentId === "coordinator");
|
|
153
|
+
const workers = sessions.filter((session) => session.agentId === "worker");
|
|
154
|
+
const threads = projectThreads(view, runScoped ? runId : undefined);
|
|
155
|
+
const coordinatorOutcome = threads.find((thread) => thread.role === "coordinator")?.goal;
|
|
156
|
+
const coordinatorTurns = projectCoordinatorTurns(view, runScoped ? runId : undefined);
|
|
157
|
+
const promptPayloads = new Map(coordinatorTurns.map((turn) => {
|
|
158
|
+
const source = facts.turns.find((item) => item.id === turn.id);
|
|
159
|
+
const payload = facts.events.find((event) => event.id === source?.triggerEventId)?.payload;
|
|
160
|
+
return [turn.id, payload];
|
|
161
|
+
}));
|
|
162
|
+
const runs = [...new Set(facts.events.map((event) => {
|
|
163
|
+
const id = payloadRecord(event.payload).runId;
|
|
164
|
+
return typeof id === "string" ? id : "";
|
|
165
|
+
}).filter(Boolean))];
|
|
166
|
+
const setCoordinatorOutcome = async (status) => {
|
|
167
|
+
if (!coordinatorOutcome)
|
|
168
|
+
return;
|
|
169
|
+
setBusy(true);
|
|
170
|
+
setError("");
|
|
171
|
+
try {
|
|
172
|
+
await client.goal({
|
|
173
|
+
projectId: project.id,
|
|
174
|
+
workThreadId: coordinatorOutcome.workThreadId,
|
|
175
|
+
status,
|
|
176
|
+
});
|
|
177
|
+
await refresh();
|
|
178
|
+
}
|
|
179
|
+
catch (cause) {
|
|
180
|
+
setError(projectErrorText(cause));
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
setBusy(false);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const submit = async (type, message, workerId, attachments) => {
|
|
187
|
+
setBusy(true);
|
|
188
|
+
setError("");
|
|
189
|
+
const fingerprint = JSON.stringify([type, message, workerId, runId, attachments]);
|
|
190
|
+
const pending = uncertainSubmission.current?.fingerprint === fingerprint
|
|
191
|
+
? uncertainSubmission.current
|
|
192
|
+
: { fingerprint, id: crypto.randomUUID() };
|
|
193
|
+
uncertainSubmission.current = pending;
|
|
194
|
+
try {
|
|
195
|
+
await client.submit({
|
|
196
|
+
projectId: project.id,
|
|
197
|
+
commandId: pending.id,
|
|
198
|
+
type,
|
|
199
|
+
text: message,
|
|
200
|
+
...(attachments?.length ? { attachments } : {}),
|
|
201
|
+
...(workerId ? { workerId } : {}),
|
|
202
|
+
...(runScoped ? { runId } : {}),
|
|
203
|
+
});
|
|
204
|
+
uncertainSubmission.current = null;
|
|
205
|
+
await refresh();
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
catch (cause) {
|
|
209
|
+
setError(projectErrorText(cause));
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
setBusy(false);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const ready = Boolean(config?.coordinatorAgent && config.workerAgent);
|
|
217
|
+
return (_jsxs(_Fragment, { children: [_jsxs("header", { className: "project-topbar", children: [_jsx("button", { type: "button", className: "project-title", title: project.name, onClick: edit, children: project.name }), _jsxs(ProjectButton, { variant: tab !== "conversation" ? "outline" : "ghost", "aria-pressed": tab !== "conversation", onClick: () => {
|
|
218
|
+
setSelectedWorker(null);
|
|
219
|
+
setTab(tab === "conversation" ? "workers" : "conversation");
|
|
220
|
+
}, children: [_jsx(ListTodoIcon, { className: "size-3.5", "aria-hidden": "true" }), "Tasks"] }), _jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Project settings", onClick: edit, children: _jsx(SettingsIcon, { className: "size-4", "aria-hidden": "true" }) })] }), _jsxs("div", { className: `project-columns${tab !== "conversation" ? " project-panel-open" : ""}`, children: [_jsxs("section", { className: "project-main", children: [runScoped ? (_jsxs("div", { className: "project-runs", children: [_jsx("select", { "aria-label": "Select run", value: runId, onChange: (event) => setRunId(event.target.value), children: [...new Set([...runs, runId])].map((id, index) => (_jsxs("option", { value: id, children: ["Run ", index + 1, " \u00B7 ", id.slice(0, 8)] }, id))) }), _jsxs(ProjectButton, { variant: "ghost", onClick: () => setRunId(crypto.randomUUID()), children: [_jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }), "New run"] })] })) : null, coordinatorOutcome ? (_jsx(ProjectOutcomeBar, { goal: coordinatorOutcome, busy: busy, onPause: () => void setCoordinatorOutcome("paused"), onResume: () => void setCoordinatorOutcome("active") })) : null, ready && config ? (_jsx(ProjectConversation, { turns: coordinatorTurns, cwd: project.primary_folder || null, promptPayloads: promptPayloads, composer: _jsx(ProjectComposer, { agentId: config.coordinatorAgent, placeholder: `Message ${project.name}…`, busy: busy, onSubmit: (message, attachments) => submit("message", message, undefined, attachments), onEditAgents: edit }, `${project.id}:${runId}`) })) : (_jsxs("div", { className: "projects-empty", children: [_jsx("h2", { children: "Make this project your own" }), _jsx("p", { children: "Choose your agents and add instructions to begin." }), _jsx(ProjectButton, { onClick: edit, children: "Set up coordinator" })] })), error || view.error ? _jsx("p", { role: "alert", className: "project-error", children: error || view.error }) : null] }), tab !== "conversation" ? (_jsxs("aside", { className: "project-side-panel", "aria-label": tab === "overview" ? "Project overview" : tab === "workers" ? "Project workers" : "Project activity", children: [_jsxs("div", { className: "project-side-heading", children: [selectedWorker && tab === "workers" ? (_jsxs(ProjectButton, { variant: "ghost", onClick: () => setSelectedWorker(null), children: [_jsx(ArrowLeftIcon, { className: "size-4", "aria-hidden": "true" }), "Threads"] })) : (_jsx("div", { className: "project-tabs", role: "tablist", "aria-label": "Project views", children: ["workers", "overview", "activity"].map((item) => (_jsx("button", { type: "button", role: "tab", "aria-selected": tab === item, onClick: () => {
|
|
221
|
+
setSelectedWorker(null);
|
|
222
|
+
setTab(item);
|
|
223
|
+
}, children: item === "workers" ? "Threads" : item === "overview" ? "Library" : "Activity" }, item))) })), _jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Close panel", onClick: () => setTab("conversation"), children: _jsx(XIcon, { className: "size-4", "aria-hidden": "true" }) })] }), _jsxs("div", { className: "project-panel-content", children: [selectedWorker && tab === "workers" ? (_jsx(ProjectWorkerDetail, { view: view, workerId: selectedWorker, busy: busy, submit: (message, attachments) => submit("steer", message, selectedWorker, attachments), edit: edit })) : null, tab === "overview" && !selectedWorker ? (_jsx(ProjectLibrary, { client: client, view: view, edit: edit, refresh: refresh, onError: setError, onAddResource: () => setResource(true) })) : null, tab === "workers" && !selectedWorker ? (_jsx(ProjectWorkers, { view: view, workers: workers, threads: threads, config: config, onOpen: setSelectedWorker, onDelegate: () => setAction({ type: "delegate" }), onSteer: (workerId) => setAction({ type: "steer", workerId }), onCancel: (workerId) => void submit("cancel", "Cancelled by user", workerId) })) : null, tab === "activity" ? (_jsx(ProjectActivity, { view: view, canComplete: Boolean(config?.controls.includes("complete")), onComplete: () => setAction({ type: "complete" }) })) : null] })] })) : null, action ? (_jsx(ProjectAction, { error: error, action: action, close: () => setAction(null), submit: async (message, id) => {
|
|
224
|
+
if (await submit(action.type, message, id))
|
|
225
|
+
setAction(null);
|
|
226
|
+
} })) : null, resource && config ? (_jsx(ResourceEditor, { close: () => setResource(false), save: async (item) => {
|
|
227
|
+
await client.saveWork({ ...config, resources: [...config.resources, item] });
|
|
228
|
+
setResource(false);
|
|
229
|
+
await refresh();
|
|
230
|
+
} })) : null] })] }));
|
|
231
|
+
}
|
|
232
|
+
function ProjectLibrary({ client, view, edit, refresh, onError, onAddResource, }) {
|
|
233
|
+
const config = view.config;
|
|
234
|
+
return (_jsxs("div", { className: "project-knowledge", "aria-label": "Project knowledge", children: [_jsxs("div", { className: "project-knowledge-heading", children: [_jsx("h2", { children: "Project knowledge" }), _jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Edit knowledge", onClick: edit, children: _jsx(PencilIcon, { className: "size-4", "aria-hidden": "true" }) })] }), _jsxs("section", { children: [_jsx("h3", { children: "Instructions" }), _jsx("p", { children: config?.instructions || "No instructions yet." }), !config?.instructions ? _jsx("button", { type: "button", onClick: edit, children: "Add instructions" }) : null] }), _jsxs("section", { children: [_jsx("h3", { children: "Context" }), config?.description ? _jsx("p", { children: config.description }) : null, _jsx("p", { children: config?.context || "No additional context." })] }), _jsxs("section", { children: [_jsxs("div", { className: "project-knowledge-heading", children: [_jsx("h3", { children: "Resources" }), config ? (_jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Add resource", onClick: onAddResource, children: _jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }) })) : null] }), config?.resources.map((resource) => (_jsxs("details", { className: "project-resource", children: [_jsxs("summary", { children: [_jsx(FileTextIcon, { className: "size-4", "aria-hidden": "true" }), resource.name] }), _jsx("p", { children: resource.text }), _jsxs(ProjectButton, { variant: "ghost", onClick: () => {
|
|
235
|
+
void client.saveWork({
|
|
236
|
+
...config,
|
|
237
|
+
resources: config.resources.filter((item) => item.id !== resource.id),
|
|
238
|
+
}).then(refresh).catch((cause) => onError(projectErrorText(cause)));
|
|
239
|
+
}, children: [_jsx(XIcon, { className: "size-4", "aria-hidden": "true" }), "Remove"] })] }, resource.id))), !config?.resources.length ? _jsx("p", { children: "No resources yet." }) : null] }), _jsxs("section", { className: "project-runtime-summary", children: [_jsx("h3", { children: "Agents" }), _jsxs("dl", { children: [_jsx("dt", { children: "Coordinator" }), _jsx("dd", { children: config?.coordinatorAgent || "Not configured" }), _jsx("dt", { children: "Workers" }), _jsx("dd", { children: config?.workerAgent || "Not configured" })] })] }), _jsx(Worktrees, { client: client, projectId: view.project.id, onError: onError })] }));
|
|
240
|
+
}
|
|
241
|
+
function Worktrees({ client, projectId, onError, }) {
|
|
242
|
+
const [trees, setTrees] = useState(null);
|
|
243
|
+
const [name, setName] = useState("");
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
if (!client.listWorktrees)
|
|
246
|
+
return;
|
|
247
|
+
let active = true;
|
|
248
|
+
void client.listWorktrees(projectId).then((next) => {
|
|
249
|
+
if (active)
|
|
250
|
+
setTrees(next);
|
|
251
|
+
}, (cause) => {
|
|
252
|
+
if (active)
|
|
253
|
+
onError(projectErrorText(cause));
|
|
254
|
+
});
|
|
255
|
+
return () => {
|
|
256
|
+
active = false;
|
|
257
|
+
};
|
|
258
|
+
}, [client, onError, projectId]);
|
|
259
|
+
if (!client.listWorktrees)
|
|
260
|
+
return null;
|
|
261
|
+
return (_jsxs("section", { "aria-label": "Worktrees", children: [_jsx("h3", { children: "Worktrees" }), trees?.map((tree) => (_jsxs("article", { className: "project-worker", children: [_jsxs("div", { children: [_jsx("strong", { children: tree.name }), _jsxs("p", { children: [tree.branch ?? "Detached", " \u00B7 ", tree.paths.join(", ") || "No checkout path"] })] }), client.deleteWorktree ? (_jsx(ProjectButton, { variant: "ghost", onClick: () => {
|
|
262
|
+
void client.deleteWorktree?.(tree.id).then(async () => {
|
|
263
|
+
setTrees(await client.listWorktrees?.(projectId) ?? []);
|
|
264
|
+
}).catch((cause) => onError(projectErrorText(cause)));
|
|
265
|
+
}, children: "Remove worktree" })) : null] }, tree.id))), !trees?.length ? _jsx("p", { children: "No worktrees yet." }) : null, client.createWorktree ? (_jsxs("form", { className: "project-form", onSubmit: (event) => {
|
|
266
|
+
event.preventDefault();
|
|
267
|
+
const trimmed = name.trim();
|
|
268
|
+
if (!trimmed)
|
|
269
|
+
return;
|
|
270
|
+
void client.createWorktree?.({ projectId, name: trimmed }).then(async () => {
|
|
271
|
+
setName("");
|
|
272
|
+
setTrees(await client.listWorktrees?.(projectId) ?? []);
|
|
273
|
+
}).catch((cause) => onError(projectErrorText(cause)));
|
|
274
|
+
}, children: [_jsxs("label", { className: "project-field", children: ["New worktree", _jsx("input", { "aria-label": "New worktree", value: name, onChange: (event) => setName(event.target.value) })] }), _jsx(ProjectButton, { type: "submit", variant: "outline", disabled: !name.trim(), children: "Create worktree" })] })) : null] }));
|
|
275
|
+
}
|
|
276
|
+
function ProjectWorkers({ view, workers, threads, config, onOpen, onDelegate, onSteer, onCancel, }) {
|
|
277
|
+
const count = workers.length + (view.external_tasks?.length ?? 0);
|
|
278
|
+
return (_jsxs("div", { className: "project-work-list", children: [_jsxs("div", { className: "project-panel-summary", children: [_jsx("span", { children: count ? `${count} threads` : "No tasks yet" }), config?.controls.includes("delegate") ? (_jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Delegate task", title: "Delegate task", onClick: onDelegate, children: _jsx(PlusIcon, { className: "size-3.5", "aria-hidden": "true" }) })) : null] }), !workers.length && !view.external_tasks?.length ? (_jsxs("div", { className: "project-workers-empty", children: [_jsx("h3", { children: "Tasks appear here" }), _jsx("p", { children: "Delegated work shows up as its own thread." })] })) : null, ["running", "queued", "failed", "completed", "cancelled", "other"].map((state) => {
|
|
279
|
+
const group = workers.filter((worker) => {
|
|
280
|
+
const status = view.facts.turns.filter((turn) => turn.sessionId === worker.id).at(-1)?.state ?? "other";
|
|
281
|
+
return status === state;
|
|
282
|
+
});
|
|
283
|
+
if (!group.length)
|
|
284
|
+
return null;
|
|
285
|
+
const labels = {
|
|
286
|
+
running: "Working",
|
|
287
|
+
queued: "Queued",
|
|
288
|
+
failed: "Failed",
|
|
289
|
+
completed: "Completed",
|
|
290
|
+
cancelled: "Cancelled",
|
|
291
|
+
other: "No turns yet",
|
|
292
|
+
};
|
|
293
|
+
return (_jsxs("section", { className: "project-worker-group", children: [_jsxs("h3", { children: [labels[state], " ", _jsx("span", { children: group.length })] }), group.map((session) => {
|
|
294
|
+
const workerId = workerIdFromThread(session.workThreadId);
|
|
295
|
+
const turns = view.facts.turns.filter((turn) => turn.sessionId === session.id);
|
|
296
|
+
const last = turns.at(-1);
|
|
297
|
+
const workspace = view.workspaces?.find((item) => item.workThreadId === session.workThreadId);
|
|
298
|
+
const outcome = threads.find((thread) => thread.workThreadId === session.workThreadId)?.goal;
|
|
299
|
+
const preview = projectResponseText(view.facts.agentEvents.filter((event) => event.turn_id === last?.id)).slice(0, 160);
|
|
300
|
+
return (_jsxs("article", { className: "project-worker", children: [_jsxs("div", { children: [_jsx("button", { type: "button", className: "project-worker-title", onClick: () => onOpen(workerId), children: workerId }), _jsx("p", { className: "project-worker-attribution", children: "Built-in coordinator" }), _jsx("p", { className: "project-worker-preview", children: preview || "Waiting for output…" }), workspace?.location ? (_jsxs("p", { children: [workspace.location.branch ? `${workspace.location.branch} · ` : "", workspace.location.cwd ?? `OpenMA session ${workspace.location.remoteSessionId ?? ""}`] })) : null, _jsxs("span", { children: [last?.state ?? session.state ?? "open", " \u00B7 ", config?.workerAgent] }), outcome ? _jsxs("span", { className: "project-worker-outcome", children: ["Outcome: ", projectOutcomeLabel(outcome.status)] }) : null] }), _jsxs("div", { className: "project-worker-actions", children: [config?.controls.includes("steer") ? (_jsx(ProjectButton, { variant: "outline", onClick: () => onSteer(workerId), children: "Steer" })) : null, config?.controls.includes("cancel") && last && ["queued", "running"].includes(last.state) ? (_jsx(ProjectButton, { variant: "ghost", onClick: () => onCancel(workerId), children: "Cancel" })) : null, _jsx(ProjectButton, { variant: "ghost", onClick: () => onOpen(workerId), children: "View thread" })] })] }, session.id));
|
|
301
|
+
})] }, state));
|
|
302
|
+
}), view.external_tasks?.map((task) => (_jsxs("article", { className: "project-worker", "data-external-task": "true", children: [_jsx("p", { className: "project-worker-title", children: task.text }), task.status === "cancelled" ? _jsx("span", { children: "Cancelled" }) : null, task.coordinator_name ? _jsx("span", { children: task.coordinator_name }) : null] }, task.id)))] }));
|
|
303
|
+
}
|
|
304
|
+
function ProjectActivity({ view, canComplete, onComplete, }) {
|
|
305
|
+
return (_jsxs("div", { className: "project-work-list", children: [_jsxs("div", { className: "project-section-heading", children: [_jsx("h2", { children: "Activity history" }), canComplete ? (_jsxs(ProjectButton, { variant: "outline", onClick: onComplete, children: [_jsx(CheckIcon, { className: "size-4", "aria-hidden": "true" }), "Complete project"] })) : null] }), !view.facts.events.length ? (_jsx("p", { className: "project-help", children: "Activity appears when you send a message or delegate work." })) : null, [...view.facts.events].reverse().map((event) => {
|
|
306
|
+
const reaction = view.facts.reactions.find((item) => item.eventId === event.id);
|
|
307
|
+
return (_jsxs("details", { className: "project-activity", children: [_jsxs("summary", { children: [_jsx("span", { children: event.type.replace("backchat.project.", "").replace("project.", "").replaceAll(".", " ") }), _jsx("span", { children: reaction?.status ?? "Processing" }), _jsx("time", { children: new Date(event.occurredAt).toLocaleTimeString() })] }), _jsx("pre", { children: JSON.stringify(event.payload, null, 2) }), reaction?.reason ? _jsx("p", { children: reaction.reason }) : null] }, event.id));
|
|
308
|
+
})] }));
|
|
309
|
+
}
|
|
310
|
+
function ProjectWorkerDetail({ view, workerId, busy, submit, edit, }) {
|
|
311
|
+
const sessions = view.facts.sessions.filter((session) => session.agentId === "worker" && session.workThreadId.endsWith(`:worker:${workerId}`));
|
|
312
|
+
const turns = view.facts.turns.filter((turn) => sessions.some((session) => session.id === turn.sessionId));
|
|
313
|
+
return (_jsxs("div", { className: "project-thread-detail", children: [_jsxs("div", { className: "project-thread-transcript", children: [_jsx("h2", { children: workerId }), turns.map((turn) => {
|
|
314
|
+
const trigger = view.facts.events.find((event) => event.id === turn.triggerEventId);
|
|
315
|
+
const payload = payloadRecord(trigger?.payload);
|
|
316
|
+
const prompt = stringField(payload, "text") || stringField(payload, "task") || stringField(payload, "instruction");
|
|
317
|
+
const text = projectResponseText(view.facts.agentEvents.filter((event) => event.turn_id === turn.id));
|
|
318
|
+
return (_jsxs("article", { className: "project-turn", children: [prompt ? _jsx("div", { className: "project-user-message", children: prompt }) : null, _jsx(ProjectMessageAttachments, { payload: trigger?.payload }), _jsx("p", { className: "project-answer", children: text || (turn.state === "running" ? "Working…" : "No output yet.") }), _jsx("p", { className: "project-turn-state", children: turn.state })] }, turn.id));
|
|
319
|
+
})] }), view.config?.controls.includes("steer") ? (_jsx(ProjectComposer, { agentId: view.config.workerAgent, role: "Worker", label: "Message worker", placeholder: "Follow up with this worker\u2026", busy: busy, onSubmit: (message, attachments) => submit(message, attachments), onEditAgents: edit })) : null] }));
|
|
320
|
+
}
|
|
321
|
+
function ProjectAction({ action, close, submit, error, }) {
|
|
322
|
+
const [text, setText] = useState("");
|
|
323
|
+
const [workerId, setWorkerId] = useState(action.workerId ?? "");
|
|
324
|
+
const [busy, setBusy] = useState(false);
|
|
325
|
+
const label = action.type === "delegate" ? "Delegate" : action.type === "steer" ? "Steer" : "Complete";
|
|
326
|
+
return (_jsx(ProjectDialog, { open: true, title: `${label}${action.type === "complete" ? " project" : " task"}`, description: action.type === "steer"
|
|
327
|
+
? "Queue a follow-up instruction for this worker."
|
|
328
|
+
: action.type === "complete"
|
|
329
|
+
? "Record a reviewed summary of this project’s work."
|
|
330
|
+
: "Give this independent task a stable name and a clear brief.", onClose: close, children: _jsxs("form", { className: "project-form", onSubmit: (event) => {
|
|
331
|
+
event.preventDefault();
|
|
332
|
+
setBusy(true);
|
|
333
|
+
void submit(text, workerId).finally(() => setBusy(false));
|
|
334
|
+
}, children: [action.type !== "complete" ? (_jsxs("label", { className: "project-field", children: ["Worker ID", _jsx("input", { required: true, value: workerId, readOnly: Boolean(action.workerId), onChange: (event) => setWorkerId(event.target.value) })] })) : null, _jsxs("label", { className: "project-field", children: [action.type === "complete" ? "Summary" : action.type === "steer" ? "Instruction" : "Task", _jsx("textarea", { required: true, rows: 5, value: text, onChange: (event) => setText(event.target.value) })] }), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsxs("div", { className: "project-actions", children: [_jsx(ProjectButton, { variant: "ghost", onClick: close, children: "Cancel" }), _jsx(ProjectButton, { type: "submit", disabled: busy, children: label })] })] }) }));
|
|
335
|
+
}
|
|
336
|
+
function ResourceEditor({ close, save, }) {
|
|
337
|
+
const [text, setText] = useState("");
|
|
338
|
+
const [name, setName] = useState("");
|
|
339
|
+
const [error, setError] = useState("");
|
|
340
|
+
const [busy, setBusy] = useState(false);
|
|
341
|
+
return (_jsx(ProjectDialog, { open: true, title: "Add project resource", description: "Add a note or a text file. It is included in project context.", onClose: close, children: _jsxs("form", { className: "project-form", onSubmit: (event) => {
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
setBusy(true);
|
|
344
|
+
void save({ id: crypto.randomUUID(), name, text })
|
|
345
|
+
.catch((cause) => setError(projectErrorText(cause)))
|
|
346
|
+
.finally(() => setBusy(false));
|
|
347
|
+
}, children: [_jsxs("label", { className: "project-field", children: ["Text file", _jsx("input", { type: "file", accept: ".txt,.md,.csv,.json,text/plain", onChange: (event) => {
|
|
348
|
+
const file = event.target.files?.[0];
|
|
349
|
+
if (!file)
|
|
350
|
+
return;
|
|
351
|
+
if (file.size > 200_000) {
|
|
352
|
+
setError("Choose a text file under 200 KB.");
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
setName(file.name);
|
|
356
|
+
void file.text().then(setText);
|
|
357
|
+
} })] }), _jsxs("label", { className: "project-field", children: ["Resource name", _jsx("input", { required: true, value: name, onChange: (event) => setName(event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Content", _jsx("textarea", { required: true, rows: 7, value: text, onChange: (event) => setText(event.target.value) })] }), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsxs("div", { className: "project-actions", children: [_jsx(ProjectButton, { variant: "ghost", onClick: close, children: "Cancel" }), _jsx(ProjectButton, { type: "submit", disabled: busy, children: "Add resource" })] })] }) }));
|
|
358
|
+
}
|
|
359
|
+
function uniqueFolders(project) {
|
|
360
|
+
return [...new Set([project?.primary_folder, ...(project?.source_folders ?? [])].filter((path) => Boolean(path)))];
|
|
361
|
+
}
|
|
362
|
+
function toggleControl(controls, control, checked) {
|
|
363
|
+
return checked
|
|
364
|
+
? [...new Set([...controls, control])]
|
|
365
|
+
: controls.filter((item) => item !== control);
|
|
366
|
+
}
|
|
367
|
+
function workerIdFromThread(workThreadId) {
|
|
368
|
+
return workThreadId.split(":worker:").slice(1).join(":worker:");
|
|
369
|
+
}
|
|
370
|
+
function payloadRecord(payload) {
|
|
371
|
+
return payload && typeof payload === "object" ? payload : {};
|
|
372
|
+
}
|
|
373
|
+
function stringField(record, key) {
|
|
374
|
+
const value = record[key];
|
|
375
|
+
return typeof value === "string" ? value : "";
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=Projects.js.map
|