@automagik/genie 4.260324.9 → 4.260324.10
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/.claude-plugin/marketplace.json +1 -1
- package/dist/genie.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/genie/.claude-plugin/plugin.json +1 -1
- package/plugins/genie/package.json +1 -1
- package/src/lib/task-service.test.ts +78 -0
- package/src/lib/task-service.ts +14 -4
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "genie",
|
|
13
|
-
"version": "4.260324.
|
|
13
|
+
"version": "4.260324.10",
|
|
14
14
|
"source": "./plugins/genie",
|
|
15
15
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
|
|
16
16
|
}
|
package/dist/genie.js
CHANGED
|
@@ -839,7 +839,7 @@ ${gitLog}`:"","","Pick up where you left off. Read the wish file for full contex
|
|
|
839
839
|
WHERE actor_type = ${actor.actorType}
|
|
840
840
|
AND actor_id = ${actor.actorId}
|
|
841
841
|
AND channel = ${channel}
|
|
842
|
-
`).count>0}async function listTasksForActor(actor,filters={}){let sql=await getConnection(),
|
|
842
|
+
`).count>0}async function listTasksForActor(actor,filters={}){let sql=await getConnection(),conditions=[],values2=[],paramIdx=1;if(filters.allProjects);else if(filters.projectName)conditions.push(`t.project_id = (SELECT id FROM projects WHERE name = $${paramIdx++})`),values2.push(filters.projectName);else conditions.push(`t.repo_path = $${paramIdx++}`),values2.push(filters.repoPath??getRepoPath());if(conditions.push(`ta.actor_type = $${paramIdx++}`),values2.push(actor.actorType),conditions.push(`ta.actor_id = $${paramIdx++}`),values2.push(actor.actorId),filters.stage)conditions.push(`t.stage = $${paramIdx++}`),values2.push(filters.stage);if(filters.status)conditions.push(`t.status = $${paramIdx++}`),values2.push(filters.status);if(filters.priority)conditions.push(`t.priority = $${paramIdx++}`),values2.push(filters.priority);let limit=filters.limit??100,offset=filters.offset??0;values2.push(limit,offset);let query=`SELECT DISTINCT t.* FROM tasks t JOIN task_actors ta ON ta.task_id = t.id WHERE ${conditions.join(" AND ")} ORDER BY t.created_at DESC LIMIT $${paramIdx++} OFFSET $${paramIdx++}`;return(await sql.unsafe(query,values2)).map(mapTask)}var init_task_service=__esm(()=>{init_db()});import{writeFileSync as writeFileSync7}from"fs";import{join as join33}from"path";function scaffoldAgentFiles(targetDir){writeFileSync7(join33(targetDir,"SOUL.md"),SOUL_TEMPLATE),writeFileSync7(join33(targetDir,"HEARTBEAT.md"),HEARTBEAT_TEMPLATE),writeFileSync7(join33(targetDir,"AGENTS.md"),AGENTS_TEMPLATE)}var SOUL_TEMPLATE=`# Soul
|
|
843
843
|
|
|
844
844
|
You are an AI assistant. Define your role, personality, and approach here.
|
|
845
845
|
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260324.
|
|
3
|
+
"version": "4.260324.10",
|
|
4
4
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Namastex Labs"
|
|
@@ -1020,4 +1020,82 @@ describe('Projects', () => {
|
|
|
1020
1020
|
expect(t.projectId).toBe(proj!.id);
|
|
1021
1021
|
}
|
|
1022
1022
|
});
|
|
1023
|
+
|
|
1024
|
+
it('should round-trip: create virtual project → create task with explicit projectId → list by projectName', async () => {
|
|
1025
|
+
const projName = `test-virtual-roundtrip-${Date.now()}`;
|
|
1026
|
+
const taskRepo = `${REPO}-roundtrip`;
|
|
1027
|
+
|
|
1028
|
+
// 1. Create virtual project (no repoPath) — mimics handleTaskCreate --project flow
|
|
1029
|
+
const project = await createProject({ name: projName });
|
|
1030
|
+
expect(project.id).toMatch(/^proj-/);
|
|
1031
|
+
expect(project.repoPath).toBeNull();
|
|
1032
|
+
|
|
1033
|
+
// 2. Create task with explicit projectId — mimics createTask(input, repoPath, projectId)
|
|
1034
|
+
const task = await createTask({ title: 'Round-trip test task' }, taskRepo, project.id);
|
|
1035
|
+
expect(task.projectId).toBe(project.id);
|
|
1036
|
+
expect(task.repoPath).toBe(taskRepo);
|
|
1037
|
+
|
|
1038
|
+
// 3. List by projectName — mimics genie task list --project <name>
|
|
1039
|
+
const tasks = await listTasks({ projectName: projName });
|
|
1040
|
+
expect(tasks.length).toBeGreaterThanOrEqual(1);
|
|
1041
|
+
const found = tasks.find((t) => t.id === task.id);
|
|
1042
|
+
expect(found).not.toBeUndefined();
|
|
1043
|
+
expect(found!.projectId).toBe(project.id);
|
|
1044
|
+
|
|
1045
|
+
// 4. Verify getProjectByName returns same project
|
|
1046
|
+
const lookedUp = await getProjectByName(projName);
|
|
1047
|
+
expect(lookedUp).not.toBeNull();
|
|
1048
|
+
expect(lookedUp!.id).toBe(project.id);
|
|
1049
|
+
|
|
1050
|
+
// Cleanup
|
|
1051
|
+
await sql`DELETE FROM tasks WHERE repo_path = ${taskRepo}`;
|
|
1052
|
+
await sql`DELETE FROM projects WHERE name = ${projName}`;
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
it('should round-trip with listTasksForActor and --project filter', async () => {
|
|
1056
|
+
const projName = `test-virtual-actor-${Date.now()}`;
|
|
1057
|
+
const taskRepo = `${REPO}-actor-proj`;
|
|
1058
|
+
|
|
1059
|
+
// Create virtual project and task
|
|
1060
|
+
const project = await createProject({ name: projName });
|
|
1061
|
+
const task = await createTask({ title: 'Actor project task' }, taskRepo, project.id);
|
|
1062
|
+
await assignTask(task.id, actor, 'assignee', {}, taskRepo);
|
|
1063
|
+
|
|
1064
|
+
// List via listTasksForActor with projectName filter
|
|
1065
|
+
const tasks = await listTasksForActor(actor, { projectName: projName });
|
|
1066
|
+
expect(tasks.length).toBeGreaterThanOrEqual(1);
|
|
1067
|
+
const found = tasks.find((t) => t.id === task.id);
|
|
1068
|
+
expect(found).not.toBeUndefined();
|
|
1069
|
+
expect(found!.projectId).toBe(project.id);
|
|
1070
|
+
|
|
1071
|
+
// Cleanup
|
|
1072
|
+
await sql`DELETE FROM task_actors WHERE task_id = ${task.id}`;
|
|
1073
|
+
await sql`DELETE FROM tasks WHERE repo_path = ${taskRepo}`;
|
|
1074
|
+
await sql`DELETE FROM projects WHERE name = ${projName}`;
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
it('should find auto-created projects by name in subsequent commands', async () => {
|
|
1078
|
+
const autoRepo = `${REPO}-auto-find`;
|
|
1079
|
+
|
|
1080
|
+
// ensureProject auto-creates with basename
|
|
1081
|
+
const projId = await ensureProject(autoRepo);
|
|
1082
|
+
|
|
1083
|
+
// The auto-created project should be findable by its name (basename of path)
|
|
1084
|
+
const parts = autoRepo.split('/');
|
|
1085
|
+
const expectedName = parts[parts.length - 1];
|
|
1086
|
+
const found = await getProjectByName(expectedName);
|
|
1087
|
+
expect(found).not.toBeNull();
|
|
1088
|
+
expect(found!.id).toBe(projId);
|
|
1089
|
+
|
|
1090
|
+
// Create task and list by project name
|
|
1091
|
+
const task = await createTask({ title: 'Auto-find task' }, autoRepo);
|
|
1092
|
+
expect(task.projectId).toBe(projId);
|
|
1093
|
+
|
|
1094
|
+
const tasks = await listTasks({ projectName: expectedName });
|
|
1095
|
+
expect(tasks.some((t) => t.id === task.id)).toBe(true);
|
|
1096
|
+
|
|
1097
|
+
// Cleanup
|
|
1098
|
+
await sql`DELETE FROM tasks WHERE repo_path = ${autoRepo}`;
|
|
1099
|
+
await sql`DELETE FROM projects WHERE repo_path = ${autoRepo}`;
|
|
1100
|
+
});
|
|
1023
1101
|
});
|
package/src/lib/task-service.ts
CHANGED
|
@@ -1489,11 +1489,21 @@ export async function deletePreference(actor: Actor, channel: string): Promise<b
|
|
|
1489
1489
|
/** List tasks assigned to a specific actor. */
|
|
1490
1490
|
export async function listTasksForActor(actor: Actor, filters: TaskFilters = {}): Promise<TaskRow[]> {
|
|
1491
1491
|
const sql = await getConnection();
|
|
1492
|
-
const repo = filters.repoPath ?? getRepoPath();
|
|
1493
1492
|
|
|
1494
|
-
const conditions: string[] = [
|
|
1495
|
-
const values: unknown[] = [
|
|
1496
|
-
let paramIdx =
|
|
1493
|
+
const conditions: string[] = [];
|
|
1494
|
+
const values: unknown[] = [];
|
|
1495
|
+
let paramIdx = 1;
|
|
1496
|
+
|
|
1497
|
+
// Scope conditions (project/repo/all) — mirrors buildScopeConditions with t. prefix
|
|
1498
|
+
if (filters.allProjects) {
|
|
1499
|
+
// No repo scoping — show all projects
|
|
1500
|
+
} else if (filters.projectName) {
|
|
1501
|
+
conditions.push(`t.project_id = (SELECT id FROM projects WHERE name = $${paramIdx++})`);
|
|
1502
|
+
values.push(filters.projectName);
|
|
1503
|
+
} else {
|
|
1504
|
+
conditions.push(`t.repo_path = $${paramIdx++}`);
|
|
1505
|
+
values.push(filters.repoPath ?? getRepoPath());
|
|
1506
|
+
}
|
|
1497
1507
|
|
|
1498
1508
|
conditions.push(`ta.actor_type = $${paramIdx++}`);
|
|
1499
1509
|
values.push(actor.actorType);
|