hydra-os-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +274 -0
- package/dist/app.d.ts +12 -0
- package/dist/app.js +127 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +177 -0
- package/dist/clients/api.d.ts +115 -0
- package/dist/clients/api.js +123 -0
- package/dist/clients/qdrant.d.ts +39 -0
- package/dist/clients/qdrant.js +34 -0
- package/dist/clients/temporal.d.ts +37 -0
- package/dist/clients/temporal.js +32 -0
- package/dist/commands/agent.d.ts +4 -0
- package/dist/commands/agent.js +103 -0
- package/dist/commands/artifact.d.ts +4 -0
- package/dist/commands/artifact.js +42 -0
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.js +80 -0
- package/dist/commands/core.d.ts +4 -0
- package/dist/commands/core.js +79 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.js +20 -0
- package/dist/commands/memory.d.ts +4 -0
- package/dist/commands/memory.js +24 -0
- package/dist/commands/registry.d.ts +23 -0
- package/dist/commands/registry.js +23 -0
- package/dist/commands/session.d.ts +4 -0
- package/dist/commands/session.js +15 -0
- package/dist/commands/workflow.d.ts +5 -0
- package/dist/commands/workflow.js +301 -0
- package/dist/config.d.ts +152 -0
- package/dist/config.js +91 -0
- package/dist/screens/help.d.ts +5 -0
- package/dist/screens/help.js +14 -0
- package/dist/screens/main.d.ts +5 -0
- package/dist/screens/main.js +5 -0
- package/dist/screens/workflow-detail.d.ts +9 -0
- package/dist/screens/workflow-detail.js +11 -0
- package/dist/screens/workflow-list.d.ts +5 -0
- package/dist/screens/workflow-list.js +10 -0
- package/dist/sse.d.ts +16 -0
- package/dist/sse.js +197 -0
- package/dist/store.d.ts +100 -0
- package/dist/store.js +64 -0
- package/dist/widgets/agent-panel.d.ts +15 -0
- package/dist/widgets/agent-panel.js +23 -0
- package/dist/widgets/approval-modal.d.ts +16 -0
- package/dist/widgets/approval-modal.js +24 -0
- package/dist/widgets/artifact-tree.d.ts +14 -0
- package/dist/widgets/artifact-tree.js +9 -0
- package/dist/widgets/chat-panel.d.ts +10 -0
- package/dist/widgets/chat-panel.js +29 -0
- package/dist/widgets/header.d.ts +11 -0
- package/dist/widgets/header.js +14 -0
- package/dist/widgets/health-check.d.ts +15 -0
- package/dist/widgets/health-check.js +19 -0
- package/dist/widgets/input-bar.d.ts +9 -0
- package/dist/widgets/input-bar.js +37 -0
- package/dist/widgets/memory-panel.d.ts +11 -0
- package/dist/widgets/memory-panel.js +9 -0
- package/dist/widgets/status-bar.d.ts +13 -0
- package/dist/widgets/status-bar.js +24 -0
- package/dist/widgets/timeline.d.ts +26 -0
- package/dist/widgets/timeline.js +19 -0
- package/package.json +64 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hydra API client.
|
|
3
|
+
* REST calls to the hydra-api service on :7070.
|
|
4
|
+
*/
|
|
5
|
+
export interface WorkflowStartResponse {
|
|
6
|
+
workflow_id: string;
|
|
7
|
+
run_id: string;
|
|
8
|
+
status: string;
|
|
9
|
+
}
|
|
10
|
+
export interface WorkflowStatusResponse {
|
|
11
|
+
workflow_id: string;
|
|
12
|
+
status: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface WorkflowResponse {
|
|
15
|
+
id: string;
|
|
16
|
+
workflow_type: string;
|
|
17
|
+
status: string;
|
|
18
|
+
current_step: string | null;
|
|
19
|
+
steps: Array<Record<string, unknown>>;
|
|
20
|
+
input: Record<string, unknown>;
|
|
21
|
+
output: Record<string, unknown> | null;
|
|
22
|
+
artifacts: Array<Record<string, unknown>>;
|
|
23
|
+
created_at: string;
|
|
24
|
+
updated_at: string;
|
|
25
|
+
workspace_id: string;
|
|
26
|
+
project: string | null;
|
|
27
|
+
metrics: Record<string, unknown> | null;
|
|
28
|
+
}
|
|
29
|
+
export interface TaskSummary {
|
|
30
|
+
workflow_id: string;
|
|
31
|
+
workflow_type: string;
|
|
32
|
+
task_description: string | null;
|
|
33
|
+
status: string;
|
|
34
|
+
domain: string | null;
|
|
35
|
+
technologies: string[] | null;
|
|
36
|
+
complexity: string | null;
|
|
37
|
+
created_at: string;
|
|
38
|
+
completed_at: string | null;
|
|
39
|
+
duration_minutes: number | null;
|
|
40
|
+
current_step: string | null;
|
|
41
|
+
completed_steps: string[] | null;
|
|
42
|
+
}
|
|
43
|
+
export interface InboxItemResponse {
|
|
44
|
+
id: string;
|
|
45
|
+
type: string;
|
|
46
|
+
workflow_id: string;
|
|
47
|
+
workflow_type: string;
|
|
48
|
+
title: string;
|
|
49
|
+
summary: string;
|
|
50
|
+
priority: string;
|
|
51
|
+
created_at: string;
|
|
52
|
+
agent_role: string | null;
|
|
53
|
+
agent_recommendation: string | null;
|
|
54
|
+
approval_type: string;
|
|
55
|
+
artifact_path: string | null;
|
|
56
|
+
status: string;
|
|
57
|
+
}
|
|
58
|
+
export interface AgentResponse {
|
|
59
|
+
id: string;
|
|
60
|
+
role_id: string;
|
|
61
|
+
queue: string;
|
|
62
|
+
status: string;
|
|
63
|
+
model: string;
|
|
64
|
+
active_sessions: number;
|
|
65
|
+
total_tokens_used: number;
|
|
66
|
+
current_workflow: string | null;
|
|
67
|
+
skill_packs: string[];
|
|
68
|
+
allowed_tools: string[];
|
|
69
|
+
}
|
|
70
|
+
export interface WorkflowControlResponse {
|
|
71
|
+
workflow_id: string;
|
|
72
|
+
action: string;
|
|
73
|
+
status: string;
|
|
74
|
+
temporal_status: string | null;
|
|
75
|
+
message: string | null;
|
|
76
|
+
}
|
|
77
|
+
export interface MemorySearchResult {
|
|
78
|
+
results: Array<Record<string, unknown>>;
|
|
79
|
+
total: number;
|
|
80
|
+
has_more: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface HealthResponse {
|
|
83
|
+
status: string;
|
|
84
|
+
version?: string;
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
}
|
|
87
|
+
export declare class HydraApiClient {
|
|
88
|
+
private baseUrl;
|
|
89
|
+
constructor(baseUrl?: string);
|
|
90
|
+
private request;
|
|
91
|
+
startWorkflow(workflowType: string, workflowId: string, input: Record<string, unknown>): Promise<WorkflowStartResponse>;
|
|
92
|
+
getWorkflow(workflowId: string): Promise<WorkflowResponse>;
|
|
93
|
+
getWorkflowStatus(workflowId: string): Promise<WorkflowStatusResponse>;
|
|
94
|
+
listTasks(filters?: {
|
|
95
|
+
status?: string;
|
|
96
|
+
workflow_type?: string;
|
|
97
|
+
domain?: string;
|
|
98
|
+
limit?: number;
|
|
99
|
+
}): Promise<TaskSummary[]>;
|
|
100
|
+
approveWorkflow(workflowId: string, decision: string, feedback?: string): Promise<Record<string, unknown>>;
|
|
101
|
+
cancelWorkflow(workflowId: string, reason?: string): Promise<WorkflowControlResponse>;
|
|
102
|
+
pauseWorkflow(workflowId: string, reason?: string): Promise<WorkflowControlResponse>;
|
|
103
|
+
resumeWorkflow(workflowId: string, reason?: string): Promise<WorkflowControlResponse>;
|
|
104
|
+
getInbox(): Promise<InboxItemResponse[]>;
|
|
105
|
+
approveInboxItem(itemId: string, body?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
106
|
+
rejectInboxItem(itemId: string, body?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
107
|
+
getAgents(): Promise<{
|
|
108
|
+
agents: AgentResponse[];
|
|
109
|
+
}>;
|
|
110
|
+
searchMemory(query: string, collections?: string[], limit?: number): Promise<MemorySearchResult>;
|
|
111
|
+
getRoles(): Promise<Record<string, unknown>>;
|
|
112
|
+
getArtifactContent(workflowId: string, filePath: string): Promise<string>;
|
|
113
|
+
healthCheck(): Promise<HealthResponse>;
|
|
114
|
+
}
|
|
115
|
+
export declare function getApiClient(baseUrl?: string): HydraApiClient;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hydra API client.
|
|
3
|
+
* REST calls to the hydra-api service on :7070.
|
|
4
|
+
*/
|
|
5
|
+
class ApiError extends Error {
|
|
6
|
+
statusCode;
|
|
7
|
+
constructor(statusCode, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
this.name = "ApiError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class HydraApiClient {
|
|
14
|
+
baseUrl;
|
|
15
|
+
constructor(baseUrl = "http://localhost:7070") {
|
|
16
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
17
|
+
}
|
|
18
|
+
async request(method, path, body, params) {
|
|
19
|
+
let url = `${this.baseUrl}${path}`;
|
|
20
|
+
if (params) {
|
|
21
|
+
const qs = new URLSearchParams(params).toString();
|
|
22
|
+
if (qs)
|
|
23
|
+
url += `?${qs}`;
|
|
24
|
+
}
|
|
25
|
+
const headers = {};
|
|
26
|
+
if (body !== undefined) {
|
|
27
|
+
headers["Content-Type"] = "application/json";
|
|
28
|
+
}
|
|
29
|
+
const res = await fetch(url, {
|
|
30
|
+
method,
|
|
31
|
+
headers,
|
|
32
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const text = await res.text().catch(() => "");
|
|
36
|
+
let detail = text;
|
|
37
|
+
try {
|
|
38
|
+
const json = JSON.parse(text);
|
|
39
|
+
detail = json.detail || text;
|
|
40
|
+
}
|
|
41
|
+
catch { /* use raw text */ }
|
|
42
|
+
throw new ApiError(res.status, `${method} ${path}: ${res.status} ${detail}`);
|
|
43
|
+
}
|
|
44
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
45
|
+
if (contentType.includes("application/json")) {
|
|
46
|
+
return (await res.json());
|
|
47
|
+
}
|
|
48
|
+
return (await res.text());
|
|
49
|
+
}
|
|
50
|
+
async startWorkflow(workflowType, workflowId, input) {
|
|
51
|
+
return this.request("POST", "/workflows/start", {
|
|
52
|
+
workflow_type: workflowType,
|
|
53
|
+
workflow_id: workflowId,
|
|
54
|
+
input,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async getWorkflow(workflowId) {
|
|
58
|
+
return this.request("GET", `/workflows/${workflowId}`);
|
|
59
|
+
}
|
|
60
|
+
async getWorkflowStatus(workflowId) {
|
|
61
|
+
return this.request("GET", `/workflows/${workflowId}/status`);
|
|
62
|
+
}
|
|
63
|
+
async listTasks(filters) {
|
|
64
|
+
const params = {};
|
|
65
|
+
if (filters?.status)
|
|
66
|
+
params.status = filters.status;
|
|
67
|
+
if (filters?.workflow_type)
|
|
68
|
+
params.workflow_type = filters.workflow_type;
|
|
69
|
+
if (filters?.domain)
|
|
70
|
+
params.domain = filters.domain;
|
|
71
|
+
if (filters?.limit)
|
|
72
|
+
params.limit = String(filters.limit);
|
|
73
|
+
return this.request("GET", "/tasks", undefined, params);
|
|
74
|
+
}
|
|
75
|
+
async approveWorkflow(workflowId, decision, feedback) {
|
|
76
|
+
return this.request("POST", `/workflows/${workflowId}/approve`, { decision, feedback });
|
|
77
|
+
}
|
|
78
|
+
async cancelWorkflow(workflowId, reason) {
|
|
79
|
+
return this.request("POST", `/workflows/${workflowId}/cancel`, reason ? { reason } : undefined);
|
|
80
|
+
}
|
|
81
|
+
async pauseWorkflow(workflowId, reason) {
|
|
82
|
+
return this.request("POST", `/workflows/${workflowId}/pause`, reason ? { reason } : undefined);
|
|
83
|
+
}
|
|
84
|
+
async resumeWorkflow(workflowId, reason) {
|
|
85
|
+
return this.request("POST", `/workflows/${workflowId}/resume`, reason ? { reason } : undefined);
|
|
86
|
+
}
|
|
87
|
+
async getInbox() {
|
|
88
|
+
return this.request("GET", "/inbox");
|
|
89
|
+
}
|
|
90
|
+
async approveInboxItem(itemId, body) {
|
|
91
|
+
return this.request("POST", `/inbox/${itemId}/approve`, body);
|
|
92
|
+
}
|
|
93
|
+
async rejectInboxItem(itemId, body) {
|
|
94
|
+
return this.request("POST", `/inbox/${itemId}/reject`, body);
|
|
95
|
+
}
|
|
96
|
+
async getAgents() {
|
|
97
|
+
return this.request("GET", "/agents");
|
|
98
|
+
}
|
|
99
|
+
async searchMemory(query, collections, limit) {
|
|
100
|
+
return this.request("POST", "/memory/search", {
|
|
101
|
+
query,
|
|
102
|
+
collections,
|
|
103
|
+
limit: limit ?? 10,
|
|
104
|
+
offset: 0,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async getRoles() {
|
|
108
|
+
return this.request("GET", "/config/roles");
|
|
109
|
+
}
|
|
110
|
+
async getArtifactContent(workflowId, filePath) {
|
|
111
|
+
return this.request("GET", `/artifacts/${workflowId}/${filePath}`);
|
|
112
|
+
}
|
|
113
|
+
async healthCheck() {
|
|
114
|
+
return this.request("GET", "/");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
let _client = null;
|
|
118
|
+
export function getApiClient(baseUrl) {
|
|
119
|
+
if (!_client || (baseUrl && baseUrl !== _client["baseUrl"])) {
|
|
120
|
+
_client = new HydraApiClient(baseUrl);
|
|
121
|
+
}
|
|
122
|
+
return _client;
|
|
123
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qdrant client wrapper.
|
|
3
|
+
* Memory search and artifact lookup via Qdrant vector DB.
|
|
4
|
+
*/
|
|
5
|
+
export interface MemoryResult {
|
|
6
|
+
id: string;
|
|
7
|
+
content: string;
|
|
8
|
+
role?: string;
|
|
9
|
+
workflowId?: string;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
score: number;
|
|
12
|
+
pinned: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface DecisionResult {
|
|
15
|
+
id: string;
|
|
16
|
+
decision: string;
|
|
17
|
+
alternatives: string[];
|
|
18
|
+
rationale: string;
|
|
19
|
+
outcome?: string;
|
|
20
|
+
workflowId?: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class QdrantClient {
|
|
24
|
+
private url;
|
|
25
|
+
constructor(url?: string);
|
|
26
|
+
searchMemories(_query: string, _limit?: number): Promise<MemoryResult[]>;
|
|
27
|
+
addMemory(_content: string, _options?: {
|
|
28
|
+
pin?: boolean;
|
|
29
|
+
role?: string;
|
|
30
|
+
workflowId?: string;
|
|
31
|
+
}): Promise<string>;
|
|
32
|
+
pinMemory(_id: string): Promise<void>;
|
|
33
|
+
deleteMemory(_id: string): Promise<void>;
|
|
34
|
+
getDecisions(_workflowId?: string): Promise<DecisionResult[]>;
|
|
35
|
+
getMemoryStats(): Promise<{
|
|
36
|
+
decisions: number;
|
|
37
|
+
facts: number;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qdrant client wrapper.
|
|
3
|
+
* Memory search and artifact lookup via Qdrant vector DB.
|
|
4
|
+
*/
|
|
5
|
+
export class QdrantClient {
|
|
6
|
+
url;
|
|
7
|
+
constructor(url = "http://localhost:6333") {
|
|
8
|
+
this.url = url;
|
|
9
|
+
}
|
|
10
|
+
async searchMemories(_query, _limit) {
|
|
11
|
+
// TODO: search `memories` collection
|
|
12
|
+
throw new Error("Not implemented");
|
|
13
|
+
}
|
|
14
|
+
async addMemory(_content, _options) {
|
|
15
|
+
// TODO: upsert to `memories` collection
|
|
16
|
+
throw new Error("Not implemented");
|
|
17
|
+
}
|
|
18
|
+
async pinMemory(_id) {
|
|
19
|
+
// TODO: update payload.pinned = true
|
|
20
|
+
throw new Error("Not implemented");
|
|
21
|
+
}
|
|
22
|
+
async deleteMemory(_id) {
|
|
23
|
+
// TODO: delete from `memories` collection
|
|
24
|
+
throw new Error("Not implemented");
|
|
25
|
+
}
|
|
26
|
+
async getDecisions(_workflowId) {
|
|
27
|
+
// TODO: search `decisions` collection
|
|
28
|
+
throw new Error("Not implemented");
|
|
29
|
+
}
|
|
30
|
+
async getMemoryStats() {
|
|
31
|
+
// TODO: count from collections
|
|
32
|
+
throw new Error("Not implemented");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal client wrapper.
|
|
3
|
+
* Connects to Temporal to start workflows, send signals, query state, and list workflows.
|
|
4
|
+
*/
|
|
5
|
+
export interface WorkflowInfo {
|
|
6
|
+
workflowId: string;
|
|
7
|
+
runId: string;
|
|
8
|
+
status: string;
|
|
9
|
+
taskQueue: string;
|
|
10
|
+
startTime: Date;
|
|
11
|
+
}
|
|
12
|
+
export interface WorkflowState {
|
|
13
|
+
phase: string;
|
|
14
|
+
currentAgent?: string;
|
|
15
|
+
approvalPending: boolean;
|
|
16
|
+
steps: StepState[];
|
|
17
|
+
totalCost: number;
|
|
18
|
+
totalTokens: number;
|
|
19
|
+
}
|
|
20
|
+
export interface StepState {
|
|
21
|
+
role: string;
|
|
22
|
+
status: "done" | "running" | "waiting" | "pending" | "failed";
|
|
23
|
+
startTime?: Date;
|
|
24
|
+
endTime?: Date;
|
|
25
|
+
score?: number;
|
|
26
|
+
cost?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare class TemporalClient {
|
|
29
|
+
private address;
|
|
30
|
+
private namespace;
|
|
31
|
+
constructor(address?: string, namespace?: string);
|
|
32
|
+
startWorkflow(_description: string): Promise<string>;
|
|
33
|
+
getWorkflowStatus(_workflowId: string): Promise<WorkflowState>;
|
|
34
|
+
listWorkflows(): Promise<WorkflowInfo[]>;
|
|
35
|
+
signalWorkflow(_workflowId: string, _signalName: string, _payload: unknown): Promise<void>;
|
|
36
|
+
cancelWorkflow(_workflowId: string): Promise<void>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal client wrapper.
|
|
3
|
+
* Connects to Temporal to start workflows, send signals, query state, and list workflows.
|
|
4
|
+
*/
|
|
5
|
+
export class TemporalClient {
|
|
6
|
+
address;
|
|
7
|
+
namespace;
|
|
8
|
+
constructor(address = "localhost:7233", namespace = "default") {
|
|
9
|
+
this.address = address;
|
|
10
|
+
this.namespace = namespace;
|
|
11
|
+
}
|
|
12
|
+
async startWorkflow(_description) {
|
|
13
|
+
// TODO: implement via Temporal SDK or API proxy
|
|
14
|
+
throw new Error("Not implemented");
|
|
15
|
+
}
|
|
16
|
+
async getWorkflowStatus(_workflowId) {
|
|
17
|
+
// TODO: implement via Temporal query
|
|
18
|
+
throw new Error("Not implemented");
|
|
19
|
+
}
|
|
20
|
+
async listWorkflows() {
|
|
21
|
+
// TODO: implement via Temporal visibility
|
|
22
|
+
throw new Error("Not implemented");
|
|
23
|
+
}
|
|
24
|
+
async signalWorkflow(_workflowId, _signalName, _payload) {
|
|
25
|
+
// TODO: implement via Temporal signal
|
|
26
|
+
throw new Error("Not implemented");
|
|
27
|
+
}
|
|
28
|
+
async cancelWorkflow(_workflowId) {
|
|
29
|
+
// TODO: implement via Temporal cancel
|
|
30
|
+
throw new Error("Not implemented");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent commands: /agents, /agent, /logs, /signal
|
|
3
|
+
*/
|
|
4
|
+
import { registerCommand } from "./registry.js";
|
|
5
|
+
export function registerAgentCommands() {
|
|
6
|
+
registerCommand({
|
|
7
|
+
name: "agents",
|
|
8
|
+
description: "List all agent roles and their status",
|
|
9
|
+
usage: "/agents",
|
|
10
|
+
category: "agent",
|
|
11
|
+
handler: async ({ store, api }) => {
|
|
12
|
+
try {
|
|
13
|
+
const resp = await api.getAgents();
|
|
14
|
+
const agents = resp.agents;
|
|
15
|
+
if (agents.length === 0) {
|
|
16
|
+
store.addMessage({ role: "system", content: "No agents registered." });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// Update store
|
|
20
|
+
store.setAgents(agents.map((a) => ({
|
|
21
|
+
id: a.id,
|
|
22
|
+
role_id: a.role_id,
|
|
23
|
+
queue: a.queue,
|
|
24
|
+
status: a.status,
|
|
25
|
+
model: a.model,
|
|
26
|
+
active_sessions: a.active_sessions,
|
|
27
|
+
total_tokens_used: a.total_tokens_used,
|
|
28
|
+
current_workflow: a.current_workflow,
|
|
29
|
+
skill_packs: a.skill_packs,
|
|
30
|
+
})));
|
|
31
|
+
const lines = ["Agents:\n"];
|
|
32
|
+
lines.push(" Role | Status | Model | Workflow");
|
|
33
|
+
lines.push(" " + "-".repeat(80));
|
|
34
|
+
for (const a of agents) {
|
|
35
|
+
const role = a.role_id.padEnd(17);
|
|
36
|
+
const status = a.status.padEnd(7);
|
|
37
|
+
const model = (a.model ?? "").slice(0, 26).padEnd(26);
|
|
38
|
+
const wf = a.current_workflow ?? "-";
|
|
39
|
+
lines.push(` ${role} | ${status} | ${model} | ${wf}`);
|
|
40
|
+
}
|
|
41
|
+
store.addMessage({ role: "system", content: lines.join("\n") });
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
45
|
+
store.addMessage({ role: "error", content: `Failed to get agents: ${msg}` });
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
registerCommand({
|
|
50
|
+
name: "agent",
|
|
51
|
+
description: "Show details for a specific agent role",
|
|
52
|
+
usage: "/agent <role>",
|
|
53
|
+
category: "agent",
|
|
54
|
+
handler: async ({ store, api, args }) => {
|
|
55
|
+
const role = args[0];
|
|
56
|
+
if (!role) {
|
|
57
|
+
store.addMessage({ role: "error", content: "Usage: /agent <role>" });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const resp = await api.getAgents();
|
|
62
|
+
const agent = resp.agents.find((a) => a.role_id === role || a.id === role);
|
|
63
|
+
if (!agent) {
|
|
64
|
+
store.addMessage({ role: "error", content: `Agent not found: ${role}` });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const lines = [
|
|
68
|
+
`Agent: ${agent.role_id}`,
|
|
69
|
+
` Status: ${agent.status}`,
|
|
70
|
+
` Model: ${agent.model}`,
|
|
71
|
+
` Queue: ${agent.queue}`,
|
|
72
|
+
` Active sessions: ${agent.active_sessions}`,
|
|
73
|
+
` Total tokens: ${agent.total_tokens_used}`,
|
|
74
|
+
` Current workflow: ${agent.current_workflow ?? "none"}`,
|
|
75
|
+
` Skills: ${agent.skill_packs.join(", ") || "none"}`,
|
|
76
|
+
];
|
|
77
|
+
store.addMessage({ role: "system", content: lines.join("\n") });
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
81
|
+
store.addMessage({ role: "error", content: `Failed to get agent: ${msg}` });
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
registerCommand({
|
|
86
|
+
name: "logs",
|
|
87
|
+
description: "Stream logs from a specific agent",
|
|
88
|
+
usage: "/logs <role>",
|
|
89
|
+
category: "agent",
|
|
90
|
+
handler: async ({ store }) => {
|
|
91
|
+
store.addMessage({ role: "system", content: "Log streaming is not yet available (Phase 2)." });
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
registerCommand({
|
|
95
|
+
name: "signal",
|
|
96
|
+
description: "Send a signal to a specific agent",
|
|
97
|
+
usage: "/signal <role> <message>",
|
|
98
|
+
category: "agent",
|
|
99
|
+
handler: async ({ store }) => {
|
|
100
|
+
store.addMessage({ role: "system", content: "Signal is not yet available (Phase 2)." });
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact commands: /artifacts, /artifact, /diff, /export
|
|
3
|
+
*/
|
|
4
|
+
import { registerCommand } from "./registry.js";
|
|
5
|
+
export function registerArtifactCommands() {
|
|
6
|
+
registerCommand({
|
|
7
|
+
name: "artifacts",
|
|
8
|
+
description: "List artifacts for a workflow",
|
|
9
|
+
usage: "/artifacts [workflow-id]",
|
|
10
|
+
category: "artifact",
|
|
11
|
+
handler: async ({ store }) => {
|
|
12
|
+
store.addMessage({ role: "system", content: "Artifact listing is not yet available (Phase 3)." });
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
registerCommand({
|
|
16
|
+
name: "artifact",
|
|
17
|
+
description: "Display artifact content",
|
|
18
|
+
usage: "/artifact <path>",
|
|
19
|
+
category: "artifact",
|
|
20
|
+
handler: async ({ store }) => {
|
|
21
|
+
store.addMessage({ role: "system", content: "Artifact display is not yet available (Phase 3)." });
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
registerCommand({
|
|
25
|
+
name: "diff",
|
|
26
|
+
description: "Show diff for a file artifact",
|
|
27
|
+
usage: "/diff <artifact>",
|
|
28
|
+
category: "artifact",
|
|
29
|
+
handler: async ({ store }) => {
|
|
30
|
+
store.addMessage({ role: "system", content: "Diff is not yet available (Phase 3)." });
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
registerCommand({
|
|
34
|
+
name: "export",
|
|
35
|
+
description: "Export all artifacts to a directory",
|
|
36
|
+
usage: "/export <workflow-id> <dir>",
|
|
37
|
+
category: "artifact",
|
|
38
|
+
handler: async ({ store }) => {
|
|
39
|
+
store.addMessage({ role: "system", content: "Export is not yet available (Phase 3)." });
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration commands: /config, /roles, /skills, /model, /cost, /theme
|
|
3
|
+
*/
|
|
4
|
+
import { registerCommand } from "./registry.js";
|
|
5
|
+
export function registerConfigCommands() {
|
|
6
|
+
registerCommand({
|
|
7
|
+
name: "config",
|
|
8
|
+
description: "Open settings",
|
|
9
|
+
usage: "/config",
|
|
10
|
+
category: "config",
|
|
11
|
+
handler: async ({ store }) => {
|
|
12
|
+
store.addMessage({ role: "system", content: "Config editor is not yet available (Phase 2)." });
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
registerCommand({
|
|
16
|
+
name: "roles",
|
|
17
|
+
description: "Show role catalog from config/roles.yaml",
|
|
18
|
+
usage: "/roles",
|
|
19
|
+
category: "config",
|
|
20
|
+
handler: async ({ store, api }) => {
|
|
21
|
+
try {
|
|
22
|
+
const data = await api.getRoles();
|
|
23
|
+
const roles = data.roles;
|
|
24
|
+
if (!Array.isArray(roles) || roles.length === 0) {
|
|
25
|
+
store.addMessage({ role: "system", content: "No roles configured." });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const lines = ["Role catalog:\n"];
|
|
29
|
+
for (const r of roles) {
|
|
30
|
+
const role = r;
|
|
31
|
+
const id = String(role.id ?? "unknown");
|
|
32
|
+
const queue = String(role.queue ?? id);
|
|
33
|
+
const skills = Array.isArray(role.skill_packs) ? role.skill_packs.join(", ") : "";
|
|
34
|
+
lines.push(` ${id.padEnd(18)} queue=${queue.padEnd(18)} skills=[${skills}]`);
|
|
35
|
+
}
|
|
36
|
+
store.addMessage({ role: "system", content: lines.join("\n") });
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
40
|
+
store.addMessage({ role: "error", content: `Failed to get roles: ${msg}` });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
registerCommand({
|
|
45
|
+
name: "skills",
|
|
46
|
+
description: "List available skills",
|
|
47
|
+
usage: "/skills",
|
|
48
|
+
category: "config",
|
|
49
|
+
handler: async ({ store }) => {
|
|
50
|
+
store.addMessage({ role: "system", content: "Skills listing is not yet available (Phase 2)." });
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
registerCommand({
|
|
54
|
+
name: "model",
|
|
55
|
+
description: "Set model for new agent sessions",
|
|
56
|
+
usage: "/model <model-name>",
|
|
57
|
+
category: "config",
|
|
58
|
+
handler: async ({ store }) => {
|
|
59
|
+
store.addMessage({ role: "system", content: "Model selection is not yet available (Phase 2)." });
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
registerCommand({
|
|
63
|
+
name: "cost",
|
|
64
|
+
description: "Show cumulative cost across all workflows",
|
|
65
|
+
usage: "/cost",
|
|
66
|
+
category: "config",
|
|
67
|
+
handler: async ({ store }) => {
|
|
68
|
+
store.addMessage({ role: "system", content: "Cost tracking is not yet available (Phase 2)." });
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
registerCommand({
|
|
72
|
+
name: "theme",
|
|
73
|
+
description: "Switch theme",
|
|
74
|
+
usage: "/theme <name>",
|
|
75
|
+
category: "config",
|
|
76
|
+
handler: async ({ store }) => {
|
|
77
|
+
store.addMessage({ role: "system", content: "Theme switching is not yet available (Phase 2)." });
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|