@yattalo/task-system 0.4.0 → 0.5.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.
Files changed (57) hide show
  1. package/README.md +48 -0
  2. package/dashboard-app/assets/spa-entry-CnIKatv4.js +24 -0
  3. package/dashboard-app/assets/styles-CAIFwsCh.css +1 -0
  4. package/dashboard-app/index.html +14 -0
  5. package/dist/commands/dashboard.d.ts +2 -0
  6. package/dist/commands/dashboard.d.ts.map +1 -1
  7. package/dist/commands/dashboard.js +133 -6
  8. package/dist/commands/dashboard.js.map +1 -1
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +35 -1
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/generators/mgrep-setup.d.ts +6 -0
  13. package/dist/generators/mgrep-setup.d.ts.map +1 -0
  14. package/dist/generators/mgrep-setup.js +191 -0
  15. package/dist/generators/mgrep-setup.js.map +1 -0
  16. package/dist/generators/mgrep-skill.d.ts +6 -0
  17. package/dist/generators/mgrep-skill.d.ts.map +1 -0
  18. package/dist/generators/mgrep-skill.js +173 -0
  19. package/dist/generators/mgrep-skill.js.map +1 -0
  20. package/dist/generators/uca-functions.d.ts +8 -0
  21. package/dist/generators/uca-functions.d.ts.map +1 -0
  22. package/dist/generators/uca-functions.js +57 -0
  23. package/dist/generators/uca-functions.js.map +1 -0
  24. package/dist/generators/uca-reexports.d.ts +8 -0
  25. package/dist/generators/uca-reexports.d.ts.map +1 -0
  26. package/dist/generators/uca-reexports.js +112 -0
  27. package/dist/generators/uca-reexports.js.map +1 -0
  28. package/dist/generators/uca-schema.d.ts +8 -0
  29. package/dist/generators/uca-schema.d.ts.map +1 -0
  30. package/dist/generators/uca-schema.js +650 -0
  31. package/dist/generators/uca-schema.js.map +1 -0
  32. package/dist/index.js +3 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/presets/research.d.ts.map +1 -1
  35. package/dist/presets/research.js +10 -0
  36. package/dist/presets/research.js.map +1 -1
  37. package/dist/presets/software.d.ts.map +1 -1
  38. package/dist/presets/software.js +10 -0
  39. package/dist/presets/software.js.map +1 -1
  40. package/dist/utils/detect.d.ts.map +1 -1
  41. package/dist/utils/detect.js +15 -0
  42. package/dist/utils/detect.js.map +1 -1
  43. package/dist/utils/merge.d.ts.map +1 -1
  44. package/dist/utils/merge.js +2 -0
  45. package/dist/utils/merge.js.map +1 -1
  46. package/package.json +5 -3
  47. package/templates/uca/agents.ts +59 -0
  48. package/templates/uca/contextEntries.ts +125 -0
  49. package/templates/uca/cronManager.ts +255 -0
  50. package/templates/uca/cronUtils.ts +99 -0
  51. package/templates/uca/driftEvents.ts +106 -0
  52. package/templates/uca/heartbeats.ts +167 -0
  53. package/templates/uca/hooks.ts +430 -0
  54. package/templates/uca/memory.ts +326 -0
  55. package/templates/uca/sessionBridge.ts +238 -0
  56. package/templates/uca/skills.ts +284 -0
  57. package/templates/uca/ucaTasks.ts +500 -0
@@ -0,0 +1,284 @@
1
+ import { mutation, query } from "../_generated/server";
2
+ import { v } from "convex/values";
3
+
4
+ function makeId(prefix: string): string {
5
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
6
+ }
7
+
8
+ async function getSkillById(ctx: any, skillId: string): Promise<any | null> {
9
+ return await ctx.db
10
+ .query("skillRegistry")
11
+ .withIndex("by_skillId", (q: any) => q.eq("skillId", skillId))
12
+ .first();
13
+ }
14
+
15
+ async function getAgentById(ctx: any, agentId: string): Promise<any | null> {
16
+ return await ctx.db
17
+ .query("agentRegistry")
18
+ .withIndex("by_agentId", (q: any) => q.eq("agentId", agentId))
19
+ .first();
20
+ }
21
+
22
+ export const listSkills = query({
23
+ args: {
24
+ status: v.optional(v.union(v.literal("active"), v.literal("deprecated"))),
25
+ owner: v.optional(v.string()),
26
+ },
27
+ handler: async (ctx, args) => {
28
+ let skills = await ctx.db.query("skillRegistry").collect();
29
+ if (args.status) skills = skills.filter((skill) => skill.status === args.status);
30
+ if (args.owner) skills = skills.filter((skill) => skill.owner === args.owner);
31
+ return skills.sort((a, b) => b.updatedAt - a.updatedAt);
32
+ },
33
+ });
34
+
35
+ export const upsertSkill = mutation({
36
+ args: {
37
+ skillId: v.string(),
38
+ name: v.string(),
39
+ version: v.optional(v.string()),
40
+ description: v.optional(v.string()),
41
+ promptTemplate: v.string(),
42
+ tags: v.optional(v.array(v.string())),
43
+ owner: v.string(),
44
+ status: v.optional(v.union(v.literal("active"), v.literal("deprecated"))),
45
+ },
46
+ handler: async (ctx, args) => {
47
+ const now = Date.now();
48
+ const existing = await getSkillById(ctx, args.skillId);
49
+
50
+ if (existing) {
51
+ await ctx.db.patch(existing._id, {
52
+ name: args.name,
53
+ version: args.version ?? existing.version,
54
+ description: args.description,
55
+ promptTemplate: args.promptTemplate,
56
+ tags: args.tags ?? existing.tags,
57
+ owner: args.owner,
58
+ status: args.status ?? existing.status,
59
+ updatedAt: now,
60
+ });
61
+ return { skillId: args.skillId, updated: true };
62
+ }
63
+
64
+ await ctx.db.insert("skillRegistry", {
65
+ skillId: args.skillId,
66
+ name: args.name,
67
+ version: args.version ?? "1.0.0",
68
+ description: args.description,
69
+ promptTemplate: args.promptTemplate,
70
+ tags: args.tags ?? [],
71
+ owner: args.owner,
72
+ status: args.status ?? "active",
73
+ createdAt: now,
74
+ updatedAt: now,
75
+ });
76
+
77
+ return { skillId: args.skillId, created: true };
78
+ },
79
+ });
80
+
81
+ export const removeSkill = mutation({
82
+ args: {
83
+ skillId: v.string(),
84
+ hardDelete: v.optional(v.boolean()),
85
+ },
86
+ handler: async (ctx, { skillId, hardDelete }) => {
87
+ const existing = await getSkillById(ctx, skillId);
88
+ if (!existing) return { skillId, removed: false };
89
+
90
+ if (hardDelete) {
91
+ await ctx.db.delete(existing._id);
92
+ const bindings = await ctx.db
93
+ .query("agentSkills")
94
+ .withIndex("by_skillId", (q: any) => q.eq("skillId", skillId))
95
+ .collect();
96
+ for (const binding of bindings) {
97
+ await ctx.db.delete(binding._id);
98
+ }
99
+ return { skillId, removed: true, hardDelete: true, detached: bindings.length };
100
+ }
101
+
102
+ await ctx.db.patch(existing._id, { status: "deprecated", updatedAt: Date.now() });
103
+ return { skillId, removed: true, hardDelete: false };
104
+ },
105
+ });
106
+
107
+ export const listAgentSkills = query({
108
+ args: {
109
+ agentId: v.string(),
110
+ enabledOnly: v.optional(v.boolean()),
111
+ },
112
+ handler: async (ctx, { agentId, enabledOnly }) => {
113
+ const bindings = await ctx.db
114
+ .query("agentSkills")
115
+ .withIndex("by_agentId", (q: any) => q.eq("agentId", agentId))
116
+ .collect();
117
+
118
+ const filtered = enabledOnly ? bindings.filter((binding) => binding.enabled) : bindings;
119
+
120
+ const results = [] as any[];
121
+ for (const binding of filtered) {
122
+ const skill = await getSkillById(ctx, binding.skillId);
123
+ if (!skill) continue;
124
+ results.push({ binding, skill });
125
+ }
126
+
127
+ return results;
128
+ },
129
+ });
130
+
131
+ export const assignSkillToAgent = mutation({
132
+ args: {
133
+ agentId: v.string(),
134
+ skillId: v.string(),
135
+ enabled: v.optional(v.boolean()),
136
+ proficiency: v.optional(v.number()),
137
+ config: v.optional(v.any()),
138
+ },
139
+ handler: async (ctx, args) => {
140
+ const agent = await getAgentById(ctx, args.agentId);
141
+ if (!agent) throw new Error(`Agent ${args.agentId} not found`);
142
+
143
+ const skill = await getSkillById(ctx, args.skillId);
144
+ if (!skill) throw new Error(`Skill ${args.skillId} not found`);
145
+
146
+ const existing = await ctx.db
147
+ .query("agentSkills")
148
+ .withIndex("by_agent_skill", (q: any) => q.eq("agentId", args.agentId).eq("skillId", args.skillId))
149
+ .first();
150
+
151
+ const now = Date.now();
152
+ if (existing) {
153
+ await ctx.db.patch(existing._id, {
154
+ enabled: args.enabled ?? existing.enabled,
155
+ proficiency: args.proficiency ?? existing.proficiency,
156
+ config: args.config ?? existing.config,
157
+ updatedAt: now,
158
+ });
159
+ return { bindingId: existing.bindingId, updated: true };
160
+ }
161
+
162
+ const bindingId = makeId("as");
163
+ await ctx.db.insert("agentSkills", {
164
+ bindingId,
165
+ agentId: args.agentId,
166
+ skillId: args.skillId,
167
+ enabled: args.enabled ?? true,
168
+ proficiency: args.proficiency,
169
+ config: args.config,
170
+ assignedAt: now,
171
+ updatedAt: now,
172
+ });
173
+
174
+ return { bindingId, created: true };
175
+ },
176
+ });
177
+
178
+ export const toggleAgentSkill = mutation({
179
+ args: {
180
+ agentId: v.string(),
181
+ skillId: v.string(),
182
+ enabled: v.boolean(),
183
+ },
184
+ handler: async (ctx, { agentId, skillId, enabled }) => {
185
+ const binding = await ctx.db
186
+ .query("agentSkills")
187
+ .withIndex("by_agent_skill", (q: any) => q.eq("agentId", agentId).eq("skillId", skillId))
188
+ .first();
189
+ if (!binding) throw new Error(`Binding not found (${agentId}, ${skillId})`);
190
+
191
+ await ctx.db.patch(binding._id, {
192
+ enabled,
193
+ updatedAt: Date.now(),
194
+ });
195
+
196
+ return { bindingId: binding.bindingId, enabled };
197
+ },
198
+ });
199
+
200
+ export const buildPromptForTask = query({
201
+ args: {
202
+ taskId: v.string(),
203
+ agentId: v.optional(v.string()),
204
+ contextLimit: v.optional(v.number()),
205
+ },
206
+ handler: async (ctx, { taskId, agentId, contextLimit }) => {
207
+ const task = await ctx.db
208
+ .query("tasks")
209
+ .withIndex("by_taskId", (q: any) => q.eq("taskId", taskId))
210
+ .first();
211
+ if (!task) throw new Error(`Task ${taskId} not found`);
212
+
213
+ const targetAgent = agentId ?? task.agent;
214
+ const bindings = await ctx.db
215
+ .query("agentSkills")
216
+ .withIndex("by_agentId", (q: any) => q.eq("agentId", targetAgent))
217
+ .collect();
218
+
219
+ const enabledBindings = bindings.filter((binding) => binding.enabled);
220
+ const skills = [] as any[];
221
+ for (const binding of enabledBindings) {
222
+ const skill = await getSkillById(ctx, binding.skillId);
223
+ if (!skill || skill.status !== "active") continue;
224
+ skills.push({ skill, binding });
225
+ }
226
+
227
+ const curatedContext = await ctx.db
228
+ .query("contextEntries")
229
+ .withIndex("by_tier", (q: any) => q.eq("tier", "curated"))
230
+ .collect();
231
+
232
+ const relatedContext = curatedContext
233
+ .filter((entry) => !entry.taskId || entry.taskId === taskId)
234
+ .sort((a, b) => b.updatedAt - a.updatedAt)
235
+ .slice(0, contextLimit ?? 5);
236
+
237
+ const header = [
238
+ `Task ${task.taskId} (${task.priority})`,
239
+ task.title,
240
+ "",
241
+ task.description,
242
+ ].join("\n");
243
+
244
+ const contextSection = relatedContext.length
245
+ ? [
246
+ "Relevant curated context:",
247
+ ...relatedContext.map((entry, index) => `${index + 1}. ${entry.summary ?? entry.content}`),
248
+ ].join("\n")
249
+ : "Relevant curated context:\n- none";
250
+
251
+ const skillsSection = skills.length
252
+ ? [
253
+ "Enabled skills:",
254
+ ...skills.map(({ skill }) => `- ${skill.skillId}: ${skill.promptTemplate}`),
255
+ ].join("\n")
256
+ : "Enabled skills:\n- none";
257
+
258
+ const prompt = [
259
+ header,
260
+ "",
261
+ contextSection,
262
+ "",
263
+ skillsSection,
264
+ "",
265
+ "Execution contract:",
266
+ "- Respect task dependencies and acceptance criteria.",
267
+ "- Report blockers explicitly.",
268
+ "- If code changes are made, include commit traceability.",
269
+ ].join("\n");
270
+
271
+ return {
272
+ taskId,
273
+ agentId: targetAgent,
274
+ skillCount: skills.length,
275
+ contextCount: relatedContext.length,
276
+ prompt,
277
+ skills: skills.map(({ skill, binding }) => ({
278
+ skillId: skill.skillId,
279
+ version: skill.version,
280
+ enabled: binding.enabled,
281
+ })),
282
+ };
283
+ },
284
+ });