@agentprojectcontext/apx 1.56.2 → 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/apc/paths.js +7 -0
- package/src/core/stores/conversations.js +10 -0
- package/src/core/stores/messages.js +37 -6
- package/src/core/stores/organization.js +152 -0
- package/src/core/stores/project-files.js +199 -0
- package/src/core/stores/tasks.js +36 -3
- package/src/host/daemon/api/agents.js +22 -2
- package/src/host/daemon/api/conversations.js +20 -2
- package/src/host/daemon/api/files-project.js +99 -0
- package/src/host/daemon/api/organization.js +88 -0
- package/src/host/daemon/api/shared.js +7 -0
- package/src/host/daemon/api/tasks.js +14 -0
- package/src/host/daemon/api.js +4 -0
- package/src/interfaces/cli/commands/org.js +77 -0
- package/src/interfaces/cli/index.js +48 -0
- package/src/interfaces/web/dist/assets/index-Cl0WXtxF.css +1 -0
- package/src/interfaces/web/dist/assets/index-DPAuXATr.js +705 -0
- package/src/interfaces/web/dist/assets/index-DPAuXATr.js.map +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/package-lock.json +6 -6
- package/src/interfaces/web/src/App.tsx +1 -1
- package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +123 -0
- package/src/interfaces/web/src/components/chat/ChatList.tsx +86 -65
- package/src/interfaces/web/src/components/common/ConfirmDialog.tsx +51 -0
- package/src/interfaces/web/src/components/common/TabNav.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileBrowser.tsx +138 -0
- package/src/interfaces/web/src/components/files/FileTree.tsx +133 -0
- package/src/interfaces/web/src/components/files/FileViewer.tsx +167 -0
- package/src/interfaces/web/src/components/files/MarkdownEditor.tsx +48 -0
- package/src/interfaces/web/src/components/files/MarkdownPreview.tsx +146 -0
- package/src/interfaces/web/src/components/files/NewFileDialog.tsx +66 -0
- package/src/interfaces/web/src/components/structure/StructureDialogs.tsx +172 -0
- package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +142 -0
- package/src/interfaces/web/src/components/tasks/taskStatus.tsx +57 -0
- package/src/interfaces/web/src/hooks/useChat.ts +39 -7
- package/src/interfaces/web/src/i18n/en.ts +113 -3
- package/src/interfaces/web/src/i18n/es.ts +113 -3
- package/src/interfaces/web/src/lib/api/conversations.ts +6 -0
- package/src/interfaces/web/src/lib/api/organization.ts +18 -0
- package/src/interfaces/web/src/lib/api/projectFiles.ts +19 -0
- package/src/interfaces/web/src/lib/api/tasks.ts +16 -1
- package/src/interfaces/web/src/lib/api.ts +2 -0
- package/src/interfaces/web/src/lib/slug.ts +11 -0
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +22 -3
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +31 -11
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +24 -7
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +136 -36
- package/src/interfaces/web/src/screens/project/DocsTab.tsx +13 -0
- package/src/interfaces/web/src/screens/project/FilesTab.tsx +12 -0
- package/src/interfaces/web/src/screens/project/Overview.tsx +122 -10
- package/src/interfaces/web/src/screens/project/StructureTab.tsx +147 -0
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +101 -62
- package/src/interfaces/web/src/types/daemon.ts +68 -0
- package/src/interfaces/web/dist/assets/index-CAUezTBY.css +0 -1
- package/src/interfaces/web/dist/assets/index-DaE_memX.js +0 -651
- package/src/interfaces/web/dist/assets/index-DaE_memX.js.map +0 -1
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useSearchParams } from "react-router-dom";
|
|
3
|
+
import { Plus, ChevronDown, ChevronUp, Check, Trash2, RotateCcw } from "lucide-react";
|
|
3
4
|
import { Tasks } from "../../lib/api";
|
|
4
5
|
import { Section } from "../../components/Section";
|
|
5
6
|
import { PagedList, usePagedQuery } from "../../components/Pager";
|
|
6
|
-
import { Badge, Button, Empty, Field, Input, Loading } from "../../components/ui";
|
|
7
|
+
import { Badge, Button, Empty, Field, Input, Loading, Textarea } from "../../components/ui";
|
|
7
8
|
import { useToast } from "../../components/Toast";
|
|
9
|
+
import { StatusIcon, StatusBadge, effectiveStatus } from "../../components/tasks/taskStatus";
|
|
10
|
+
import { TaskDetailPanel } from "../../components/tasks/TaskDetailPanel";
|
|
8
11
|
import { t } from "../../i18n";
|
|
9
12
|
|
|
10
13
|
export function TasksTab({ pid }: { pid: string }) {
|
|
11
14
|
const [state, setState] = useState<"open" | "done" | "dropped">("open");
|
|
15
|
+
const [params, setParams] = useSearchParams();
|
|
16
|
+
const selected = params.get("task");
|
|
12
17
|
const toast = useToast();
|
|
13
18
|
// dedupingInterval:0 so switching the state filter always revalidates the
|
|
14
19
|
// target page instead of showing the stale cached one from a prior switch.
|
|
@@ -19,14 +24,22 @@ export function TasksTab({ pid }: { pid: string }) {
|
|
|
19
24
|
swr: { dedupingInterval: 0, revalidateOnFocus: true },
|
|
20
25
|
});
|
|
21
26
|
const [draft, setDraft] = useState("");
|
|
27
|
+
const [body, setBody] = useState("");
|
|
28
|
+
const [showBody, setShowBody] = useState(false);
|
|
22
29
|
const [busy, setBusy] = useState(false);
|
|
23
30
|
|
|
31
|
+
const select = (id: string | null) => {
|
|
32
|
+
const next = new URLSearchParams(params);
|
|
33
|
+
if (id) next.set("task", id); else next.delete("task");
|
|
34
|
+
setParams(next, { replace: true });
|
|
35
|
+
};
|
|
36
|
+
|
|
24
37
|
const add = async () => {
|
|
25
38
|
if (!draft.trim()) return;
|
|
26
39
|
setBusy(true);
|
|
27
40
|
try {
|
|
28
|
-
await Tasks.add(pid, { title: draft.trim() });
|
|
29
|
-
setDraft("");
|
|
41
|
+
await Tasks.add(pid, { title: draft.trim(), body: body.trim() || null, source: "web" });
|
|
42
|
+
setDraft(""); setBody(""); setShowBody(false);
|
|
30
43
|
toast.success(t("project.tasks.created"));
|
|
31
44
|
paged.mutate();
|
|
32
45
|
} catch (e: any) {
|
|
@@ -49,72 +62,98 @@ export function TasksTab({ pid }: { pid: string }) {
|
|
|
49
62
|
<div className="flex gap-1">
|
|
50
63
|
{(["open", "done", "dropped"] as const).map((s) => (
|
|
51
64
|
<Button key={s} size="sm" data-testid={`task-filter-${s}`} variant={state === s ? "primary" : "ghost"} onClick={() => setState(s)}>
|
|
52
|
-
{s}
|
|
65
|
+
{t(`tasks.state_${s}` as never)}
|
|
53
66
|
</Button>
|
|
54
67
|
))}
|
|
55
68
|
</div>
|
|
56
69
|
}
|
|
57
70
|
>
|
|
58
|
-
<div className="mb-4
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
+
<div className="mb-4 shrink-0 space-y-2">
|
|
72
|
+
<div className="flex items-end gap-2">
|
|
73
|
+
<Field label={t("project.tasks.add_label")}>
|
|
74
|
+
<Input
|
|
75
|
+
data-testid="task-input"
|
|
76
|
+
placeholder={t("project.tasks.add_placeholder")}
|
|
77
|
+
value={draft}
|
|
78
|
+
onChange={(e) => setDraft(e.target.value)}
|
|
79
|
+
onKeyDown={(e) => { if (e.key === "Enter" && !showBody) add(); }}
|
|
80
|
+
/>
|
|
81
|
+
</Field>
|
|
82
|
+
<Button variant="ghost" size="sm" onClick={() => setShowBody((v) => !v)} aria-label={t("tasks.toggle_prompt")}>
|
|
83
|
+
{showBody ? <ChevronUp size={14} /> : <ChevronDown size={14} />} {t("tasks.field_prompt")}
|
|
84
|
+
</Button>
|
|
85
|
+
<Button variant="primary" data-testid="task-add" onClick={add} loading={busy}>
|
|
86
|
+
<Plus size={14} /> {t("project.tasks.add")}
|
|
87
|
+
</Button>
|
|
88
|
+
</div>
|
|
89
|
+
{showBody && (
|
|
90
|
+
<Textarea rows={3} value={body} onChange={(e) => setBody(e.target.value)} placeholder={t("tasks.prompt_ph")} className="text-xs" />
|
|
91
|
+
)}
|
|
71
92
|
</div>
|
|
72
93
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
<div className="flex min-h-0 flex-1 gap-4">
|
|
95
|
+
<div className="flex min-w-0 flex-1 flex-col">
|
|
96
|
+
{paged.isLoading && <Loading />}
|
|
97
|
+
{!paged.isLoading && paged.total === 0 && (
|
|
98
|
+
<Empty>
|
|
99
|
+
{state === "open" ? t("project.tasks.empty_open") : t("project.tasks.empty", { state })}
|
|
100
|
+
{" "}<code>apx task add "…"</code>
|
|
101
|
+
</Empty>
|
|
102
|
+
)}
|
|
82
103
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
104
|
+
<PagedList paged={paged} fullHeight>
|
|
105
|
+
<ul className="space-y-2 text-sm" data-testid="task-list">
|
|
106
|
+
{paged.items.map((task) => {
|
|
107
|
+
const eff = effectiveStatus(task);
|
|
108
|
+
return (
|
|
109
|
+
<li
|
|
110
|
+
key={task.id}
|
|
111
|
+
data-testid={`task-${task.id}`}
|
|
112
|
+
onClick={() => select(task.id)}
|
|
113
|
+
className={`flex cursor-pointer items-start gap-3 rounded-md border px-3 py-2 hover:border-muted-fg/50 ${selected === task.id ? "border-primary/50 bg-primary/5" : "border-border bg-muted/30"}`}
|
|
114
|
+
>
|
|
115
|
+
<StatusIcon status={eff} className="mt-0.5 shrink-0" />
|
|
116
|
+
<div className="min-w-0 flex-1">
|
|
117
|
+
<div className="truncate font-medium">{task.title}</div>
|
|
118
|
+
<div className="mt-0.5 flex flex-wrap items-center gap-2 text-xs text-muted-fg">
|
|
119
|
+
{task.state === "open" && <StatusBadge status={eff} />}
|
|
120
|
+
{task.tags?.map((tag) => <Badge key={tag}>#{tag}</Badge>)}
|
|
121
|
+
{task.agent && <Badge tone="info">@{task.agent}</Badge>}
|
|
122
|
+
{task.due && <span>{t("project.tasks.due")} {task.due}</span>}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
<div className="flex shrink-0 gap-1" onClick={(e) => e.stopPropagation()}>
|
|
126
|
+
{task.state === "open" ? (
|
|
127
|
+
<>
|
|
128
|
+
<Button size="sm" variant="secondary" aria-label={t("project.tasks.aria_done")} data-testid={`task-done-${task.id}`} onClick={() => mark(() => Tasks.done(pid, task.id), t("project.tasks.done"))}>
|
|
129
|
+
<Check size={13} />
|
|
130
|
+
</Button>
|
|
131
|
+
<Button size="sm" variant="destructive" aria-label={t("project.tasks.aria_drop")} data-testid={`task-drop-${task.id}`} onClick={() => mark(() => Tasks.drop(pid, task.id), t("project.tasks.drop"))}>
|
|
132
|
+
<Trash2 size={13} />
|
|
133
|
+
</Button>
|
|
134
|
+
</>
|
|
135
|
+
) : (
|
|
136
|
+
<Button size="sm" variant="ghost" aria-label={t("project.tasks.aria_reopen")} data-testid={`task-reopen-${task.id}`} onClick={() => mark(() => Tasks.reopen(pid, task.id), t("project.tasks.reopen"))}>
|
|
137
|
+
<RotateCcw size={13} />
|
|
138
|
+
</Button>
|
|
139
|
+
)}
|
|
140
|
+
</div>
|
|
141
|
+
</li>
|
|
142
|
+
);
|
|
143
|
+
})}
|
|
144
|
+
</ul>
|
|
145
|
+
</PagedList>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
{selected && (
|
|
149
|
+
<TaskDetailPanel
|
|
150
|
+
pid={pid}
|
|
151
|
+
taskId={selected}
|
|
152
|
+
onClose={() => select(null)}
|
|
153
|
+
onChanged={() => paged.mutate()}
|
|
154
|
+
/>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
118
157
|
</Section>
|
|
119
158
|
);
|
|
120
159
|
}
|
|
@@ -18,6 +18,9 @@ export interface ProjectEntry {
|
|
|
18
18
|
storagePath?: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// Autonomy mirrors the super-agent permission modes.
|
|
22
|
+
export type AgentAutonomy = "total" | "automatico" | "permiso";
|
|
23
|
+
|
|
21
24
|
export interface AgentEntry {
|
|
22
25
|
slug: string;
|
|
23
26
|
role: string | null;
|
|
@@ -28,6 +31,8 @@ export interface AgentEntry {
|
|
|
28
31
|
parent?: string | null;
|
|
29
32
|
type?: string | null;
|
|
30
33
|
area?: string | null;
|
|
34
|
+
emoji?: string | null;
|
|
35
|
+
autonomy?: AgentAutonomy | null;
|
|
31
36
|
skills: string[];
|
|
32
37
|
tools: string[];
|
|
33
38
|
}
|
|
@@ -52,19 +57,77 @@ export interface RoutineEntry {
|
|
|
52
57
|
post_commands?: string[];
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
// Workflow sub-status for an open task (orthogonal to `state`).
|
|
61
|
+
export type TaskStatus = "pending" | "running" | "in_review" | "blocked";
|
|
62
|
+
|
|
55
63
|
export interface TaskEntry {
|
|
56
64
|
id: string;
|
|
57
65
|
state: "open" | "done" | "dropped";
|
|
66
|
+
status?: TaskStatus;
|
|
58
67
|
title: string;
|
|
59
68
|
body: string | null;
|
|
60
69
|
tags: string[];
|
|
61
70
|
due: string | null;
|
|
62
71
|
agent: string | null;
|
|
63
72
|
source: string | null;
|
|
73
|
+
created_by?: string | null;
|
|
74
|
+
thread?: string | null;
|
|
75
|
+
done_at?: string | null;
|
|
76
|
+
done_by?: string | null;
|
|
77
|
+
dropped_at?: string | null;
|
|
64
78
|
created_at: string;
|
|
65
79
|
updated_at: string;
|
|
66
80
|
}
|
|
67
81
|
|
|
82
|
+
export interface OrgArea {
|
|
83
|
+
slug: string;
|
|
84
|
+
name: string;
|
|
85
|
+
goal: string | null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface OrgRole {
|
|
89
|
+
slug: string;
|
|
90
|
+
name: string;
|
|
91
|
+
area: string | null;
|
|
92
|
+
description: string | null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface Organization {
|
|
96
|
+
areas: OrgArea[];
|
|
97
|
+
roles: OrgRole[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Project file browser (core/stores/project-files.js).
|
|
101
|
+
export type FileKind = "markdown" | "text" | "image" | "binary";
|
|
102
|
+
|
|
103
|
+
export interface FileNode {
|
|
104
|
+
name: string;
|
|
105
|
+
path: string;
|
|
106
|
+
type: "dir" | "file";
|
|
107
|
+
kind?: FileKind;
|
|
108
|
+
children?: FileNode[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface FileTreeResponse {
|
|
112
|
+
scope: "project" | "docs";
|
|
113
|
+
root: string;
|
|
114
|
+
subdir: string;
|
|
115
|
+
tree: FileNode[];
|
|
116
|
+
truncated: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface FileContent {
|
|
120
|
+
path: string;
|
|
121
|
+
name: string;
|
|
122
|
+
kind: FileKind;
|
|
123
|
+
size: number;
|
|
124
|
+
modified: string;
|
|
125
|
+
encoding: "utf8" | "base64" | "binary";
|
|
126
|
+
mime?: string;
|
|
127
|
+
content: string | null;
|
|
128
|
+
too_large?: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
68
131
|
export interface McpEntry {
|
|
69
132
|
name: string;
|
|
70
133
|
source: "apc" | "runtime" | "global" | string;
|
|
@@ -143,6 +206,11 @@ export interface ConversationMessage {
|
|
|
143
206
|
content: string;
|
|
144
207
|
ts?: string;
|
|
145
208
|
name?: string;
|
|
209
|
+
/** Present on role:"tool" rows from the global ledger — the tool name and its
|
|
210
|
+
* structured args/result, so the viewer can render a ToolCall part. */
|
|
211
|
+
tool?: string;
|
|
212
|
+
args?: Record<string, unknown>;
|
|
213
|
+
result?: unknown;
|
|
146
214
|
}
|
|
147
215
|
|
|
148
216
|
export interface ConversationDetail {
|