maestro-agent 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +316 -2
  2. package/bin/maestro.ts +5 -0
  3. package/dist/maestro +0 -0
  4. package/dist/web/assets/Connections-DV2Kql1Z.js +1 -0
  5. package/dist/web/assets/GanttView-CCT_rFpY.js +39 -0
  6. package/dist/web/assets/Home-BFbUIh2z.js +1 -0
  7. package/dist/web/assets/HooksCrons-ASM5-jDm.js +1 -0
  8. package/dist/web/assets/ProjectDetail-KZZi6IAd.js +1 -0
  9. package/dist/web/assets/Roles-KQ94PG3H.js +4 -0
  10. package/dist/web/assets/ScheduledTasks-CdJHJpEV.js +1 -0
  11. package/dist/web/assets/Settings-CTflMta-.js +1 -0
  12. package/dist/web/assets/Skills-D09W1mwX.js +2 -0
  13. package/dist/web/assets/Wizard-CW6B0wc3.js +1 -0
  14. package/dist/web/assets/WorkspaceChat-CthETL_A.js +1 -0
  15. package/dist/web/assets/WorkspaceDashboard-DTAesQuT.js +1 -0
  16. package/dist/web/assets/WorkspaceNew-Em4msIKn.js +1 -0
  17. package/dist/web/assets/WorkspaceProjects-Dxg2BpQy.js +1 -0
  18. package/dist/web/assets/WorkspaceTasks-C20mnnkP.js +1 -0
  19. package/dist/web/assets/index-B1k33vcR.js +11 -0
  20. package/dist/web/assets/index-Bk2hHz7P.css +1 -0
  21. package/dist/web/assets/index-Ddy5AJwx.js +61 -0
  22. package/dist/web/assets/useEventStream-DTID465I.js +1 -0
  23. package/dist/web/index.html +13 -0
  24. package/package.json +49 -6
  25. package/src/api/agents.ts +76 -0
  26. package/src/api/audit.ts +19 -0
  27. package/src/api/autopilot.ts +73 -0
  28. package/src/api/chat.ts +801 -0
  29. package/src/api/chief.ts +84 -0
  30. package/src/api/config.ts +39 -0
  31. package/src/api/gantt.ts +72 -0
  32. package/src/api/hooks.ts +54 -0
  33. package/src/api/inbox.ts +125 -0
  34. package/src/api/lark.ts +32 -0
  35. package/src/api/memory.ts +37 -0
  36. package/src/api/ops.ts +89 -0
  37. package/src/api/projects.ts +105 -0
  38. package/src/api/roles.ts +123 -0
  39. package/src/api/runtimes.ts +62 -0
  40. package/src/api/scheduled-tasks.ts +203 -0
  41. package/src/api/sessions.ts +479 -0
  42. package/src/api/skills.ts +386 -0
  43. package/src/api/tasks.ts +457 -0
  44. package/src/api/telegram.ts +94 -0
  45. package/src/api/templates.ts +36 -0
  46. package/src/api/webhooks.ts +20 -0
  47. package/src/api/workspaces.ts +150 -0
  48. package/src/bridges/lark/index.ts +213 -0
  49. package/src/bridges/telegram/index.ts +273 -0
  50. package/src/bridges/telegram/polling.ts +185 -0
  51. package/src/chat/index.ts +86 -0
  52. package/src/chief/index.ts +461 -0
  53. package/src/core/cli.ts +333 -0
  54. package/src/core/db.ts +53 -0
  55. package/src/core/event-bus.ts +33 -0
  56. package/src/core/index.ts +6 -0
  57. package/src/core/migrations.ts +303 -0
  58. package/src/core/router.ts +69 -0
  59. package/src/core/schema.sql +232 -0
  60. package/src/core/server.ts +308 -0
  61. package/src/core/validate.ts +22 -0
  62. package/src/discovery/index.ts +194 -0
  63. package/src/gateway/adapters/telegram.ts +148 -0
  64. package/src/gateway/index.ts +31 -0
  65. package/src/gateway/manager.ts +176 -0
  66. package/src/gateway/types.ts +77 -0
  67. package/src/inbox/index.ts +500 -0
  68. package/src/ops/artifact-sync.ts +65 -0
  69. package/src/ops/autopilot.ts +338 -0
  70. package/src/ops/gc.ts +252 -0
  71. package/src/ops/index.ts +226 -0
  72. package/src/ops/project-serial.ts +52 -0
  73. package/src/ops/role-dispatch.ts +111 -0
  74. package/src/ops/runtime-scheduler.ts +447 -0
  75. package/src/ops/task-blocking.ts +65 -0
  76. package/src/ops/task-deps.ts +37 -0
  77. package/src/ops/task-workspace.ts +60 -0
  78. package/src/roles/index.ts +258 -0
  79. package/src/roles/prompt-assembler.ts +85 -0
  80. package/src/roles/workspace-role.ts +155 -0
  81. package/src/scheduler/index.ts +461 -0
  82. package/src/session/output-parser.ts +75 -0
  83. package/src/session/realtime-parser.ts +40 -0
  84. package/src/skills/builtin.ts +155 -0
  85. package/src/skills/skill-extractor.ts +452 -0
  86. package/src/skills/skill-md.ts +282 -0
  87. package/src/transport/http-api.ts +75 -0
  88. package/src/transport/index.ts +4 -0
  89. package/src/transport/local-pty.ts +119 -0
  90. package/src/transport/ssh.ts +176 -0
  91. package/src/transport/types.ts +20 -0
  92. package/src/workflows/index.ts +231 -0
  93. package/index.js +0 -1
  94. package/maestro-agent-0.0.1.tgz +0 -0
@@ -0,0 +1,231 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import type { HubContext } from "../core/server";
3
+ import { generateId, now } from "../core/db";
4
+ import { executeHooksForEvent } from "../scheduler";
5
+ import { unlockDependents } from "../ops/task-deps";
6
+
7
+ export interface WorkflowStatus {
8
+ id: string;
9
+ label: string;
10
+ terminal?: boolean;
11
+ }
12
+
13
+ export interface WorkflowAction {
14
+ id: string;
15
+ label: string;
16
+ from: string[];
17
+ to: string;
18
+ requires?: string[];
19
+ clears_assignee?: boolean;
20
+ terminal?: boolean;
21
+ }
22
+
23
+ export interface WorkflowDefinition {
24
+ id: string;
25
+ name: string;
26
+ initial_status: string;
27
+ blocked_status: string;
28
+ done_status: string;
29
+ statuses: WorkflowStatus[];
30
+ actions: WorkflowAction[];
31
+ }
32
+
33
+ export const DEFAULT_WORKFLOW: WorkflowDefinition = {
34
+ id: "workflow_default",
35
+ name: "Default Task Workflow",
36
+ initial_status: "open",
37
+ blocked_status: "blocked",
38
+ done_status: "done",
39
+ statuses: [
40
+ { id: "open", label: "Open" },
41
+ { id: "claimed", label: "In Progress" },
42
+ { id: "review", label: "Review" },
43
+ { id: "blocked", label: "Blocked" },
44
+ { id: "done", label: "Done", terminal: true },
45
+ { id: "abandoned", label: "Abandoned", terminal: true },
46
+ ],
47
+ actions: [
48
+ { id: "claim", label: "Claim", from: ["open"], to: "claimed" },
49
+ { id: "submit", label: "Submit for Review", from: ["claimed"], to: "review", requires: ["summary"] },
50
+ { id: "complete", label: "Complete", from: ["claimed", "review"], to: "done", requires: ["summary"], terminal: true },
51
+ { id: "block", label: "Block", from: ["open", "claimed", "review"], to: "blocked", requires: ["reason"] },
52
+ { id: "return", label: "Return", from: ["claimed", "review", "blocked"], to: "open", requires: ["reason"], clears_assignee: true },
53
+ { id: "abandon", label: "Abandon", from: ["open", "claimed", "review", "blocked"], to: "abandoned", requires: ["reason"], clears_assignee: true, terminal: true },
54
+ ],
55
+ };
56
+
57
+ export function ensureDefaultWorkflow(db: Database) {
58
+ const ts = now();
59
+ db.run(
60
+ `INSERT INTO workflow_definition (id, scope, scope_id, name, definition_json, created_at, updated_at)
61
+ VALUES (?, 'global', NULL, ?, ?, ?, ?)
62
+ ON CONFLICT(id) DO UPDATE SET
63
+ name = excluded.name,
64
+ definition_json = excluded.definition_json,
65
+ updated_at = excluded.updated_at`,
66
+ [DEFAULT_WORKFLOW.id, DEFAULT_WORKFLOW.name, JSON.stringify(DEFAULT_WORKFLOW), ts, ts],
67
+ );
68
+ }
69
+
70
+ export function getWorkflowForTask(db: Database, taskId: string): WorkflowDefinition {
71
+ const row = db.query(`
72
+ SELECT wf.*
73
+ FROM task
74
+ JOIN project ON project.id = task.project_id
75
+ LEFT JOIN workflow_definition wf ON wf.id = project.workflow_id
76
+ WHERE task.id = ?
77
+ `).get(taskId) as any | null;
78
+
79
+ if (row?.definition_json) return parseWorkflow(row.definition_json);
80
+
81
+ const fallback = db.query("SELECT * FROM workflow_definition WHERE id = ?").get(DEFAULT_WORKFLOW.id) as any | null;
82
+ if (fallback?.definition_json) return parseWorkflow(fallback.definition_json);
83
+ return DEFAULT_WORKFLOW;
84
+ }
85
+
86
+ export function listTaskActions(db: Database, taskId: string) {
87
+ const task = db.query("SELECT * FROM task WHERE id = ?").get(taskId) as any | null;
88
+ if (!task) throw new Error(`Task not found: ${taskId}`);
89
+ const workflow = getWorkflowForTask(db, taskId);
90
+ const actions = workflow.actions.filter((action) => action.from.includes(task.status));
91
+ return {
92
+ task_id: taskId,
93
+ status: task.status,
94
+ workflow: {
95
+ id: workflow.id,
96
+ name: workflow.name,
97
+ statuses: workflow.statuses,
98
+ },
99
+ actions,
100
+ };
101
+ }
102
+
103
+ export function transitionTask(
104
+ ctx: Pick<HubContext, "db" | "bus">,
105
+ taskId: string,
106
+ actionId: string,
107
+ input: Record<string, any> = {},
108
+ opts: { actorId?: string } = {},
109
+ ): { ok: true; task: any; action: WorkflowAction; workflow: WorkflowDefinition } | { ok: false; error: string; status: number } {
110
+ const task = ctx.db.query("SELECT * FROM task WHERE id = ?").get(taskId) as any | null;
111
+ if (!task) return { ok: false, error: "Task not found", status: 404 };
112
+
113
+ const workflow = getWorkflowForTask(ctx.db, taskId);
114
+ const action = workflow.actions.find((candidate) => candidate.id === actionId);
115
+ if (!action) return { ok: false, error: `Workflow action not found: ${actionId}`, status: 404 };
116
+ if (!action.from.includes(task.status)) {
117
+ return { ok: false, error: `Action "${actionId}" is not available from status "${task.status}"`, status: 409 };
118
+ }
119
+
120
+ const missing = (action.requires || []).filter((field) => !isPresent(input[field]));
121
+ if (missing.length > 0) {
122
+ return { ok: false, error: `Missing required field(s): ${missing.join(", ")}`, status: 400 };
123
+ }
124
+
125
+ const ts = now();
126
+ const updates = ["status = ?", "updated_at = ?"];
127
+ const values: any[] = [action.to, ts];
128
+ if (action.clears_assignee) {
129
+ updates.push("assignee_agent_id = NULL", "claim_token = NULL");
130
+ }
131
+ values.push(taskId);
132
+ ctx.db.run(`UPDATE task SET ${updates.join(", ")} WHERE id = ?`, values);
133
+
134
+ const actor = opts.actorId || "system";
135
+ const summary = input.summary || input.reason || input.note || "";
136
+ const content = summary ? `${action.id}: ${summary}` : action.id;
137
+ ctx.db.run(
138
+ "INSERT INTO task_thread_item (id, task_id, kind, author, content, created_at) VALUES (?, ?, 'workflow_transition', ?, ?, ?)",
139
+ [generateId("ti"), taskId, actor, content, ts],
140
+ );
141
+
142
+ const updated = ctx.db.query("SELECT * FROM task WHERE id = ?").get(taskId) as any;
143
+ const eventPayload = {
144
+ id: taskId,
145
+ action_id: action.id,
146
+ from_status: task.status,
147
+ to_status: action.to,
148
+ actor_id: actor,
149
+ };
150
+ ctx.bus.publish("task.transitioned", eventPayload);
151
+ ctx.bus.publish(`task.${action.id}`, eventPayload);
152
+
153
+ if (isTerminal(workflow, action.to) || action.terminal) {
154
+ executeHooksForEvent(ctx.db, `task.${action.id}`, { task_id: taskId, project_id: task.project_id });
155
+ }
156
+ if (action.to === workflow.done_status) {
157
+ unlockDependents(ctx as HubContext, taskId, {
158
+ doneStatus: workflow.done_status,
159
+ blockedStatus: workflow.blocked_status,
160
+ openStatus: workflow.initial_status,
161
+ });
162
+ // Auto-archive completed scheduled task instances
163
+ if (task.created_by === "scheduled_task") {
164
+ ctx.db.run("UPDATE task SET archived_at = ? WHERE id = ?", [now(), taskId]);
165
+ }
166
+ }
167
+
168
+ return { ok: true, task: updated, action, workflow };
169
+ }
170
+
171
+ export function workflowStatusesForProject(db: Database, projectId?: string | null): WorkflowStatus[] {
172
+ let workflow: WorkflowDefinition = DEFAULT_WORKFLOW;
173
+ if (projectId) {
174
+ const task = db.query("SELECT id FROM task WHERE project_id = ? LIMIT 1").get(projectId) as any | null;
175
+ if (task) workflow = getWorkflowForTask(db, task.id);
176
+ else {
177
+ const row = db.query(`
178
+ SELECT wf.definition_json
179
+ FROM project
180
+ LEFT JOIN workflow_definition wf ON wf.id = project.workflow_id
181
+ WHERE project.id = ?
182
+ `).get(projectId) as any | null;
183
+ workflow = row?.definition_json ? parseWorkflow(row.definition_json) : defaultWorkflowFromDb(db);
184
+ }
185
+ } else {
186
+ workflow = defaultWorkflowFromDb(db);
187
+ }
188
+ return workflow.statuses;
189
+ }
190
+
191
+ export function isInitialTaskStatus(db: Database, task: any): boolean {
192
+ const workflow = getWorkflowForTask(db, task.id);
193
+ return task.status === workflow.initial_status;
194
+ }
195
+
196
+ export function isBlockedTaskStatus(db: Database, task: any): boolean {
197
+ const workflow = getWorkflowForTask(db, task.id);
198
+ return task.status === workflow.blocked_status;
199
+ }
200
+
201
+ export function isActiveTaskStatus(db: Database, task: any): boolean {
202
+ const workflow = getWorkflowForTask(db, task.id);
203
+ return !workflow.statuses.find((status) => status.id === task.status)?.terminal;
204
+ }
205
+
206
+ export function countTasksByPredicate(db: Database, predicate: (task: any) => boolean): number {
207
+ const tasks = db.query("SELECT * FROM task").all() as any[];
208
+ return tasks.filter(predicate).length;
209
+ }
210
+
211
+ function defaultWorkflowFromDb(db: Database) {
212
+ const row = db.query("SELECT definition_json FROM workflow_definition WHERE id = ?").get(DEFAULT_WORKFLOW.id) as any | null;
213
+ return row?.definition_json ? parseWorkflow(row.definition_json) : DEFAULT_WORKFLOW;
214
+ }
215
+
216
+ function parseWorkflow(json: string): WorkflowDefinition {
217
+ const workflow = JSON.parse(json);
218
+ return {
219
+ ...workflow,
220
+ statuses: Array.isArray(workflow.statuses) ? workflow.statuses : [],
221
+ actions: Array.isArray(workflow.actions) ? workflow.actions : [],
222
+ };
223
+ }
224
+
225
+ function isTerminal(workflow: WorkflowDefinition, status: string): boolean {
226
+ return Boolean(workflow.statuses.find((candidate) => candidate.id === status)?.terminal);
227
+ }
228
+
229
+ function isPresent(value: unknown): boolean {
230
+ return value !== undefined && value !== null && value !== "";
231
+ }
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = {};
Binary file