@rubytech/create-maxy-code 0.1.75 → 0.1.79
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/dist/__tests__/plugin-install.test.js +2 -2
- package/dist/lib/plugin-install.js +1 -1
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +1 -1
- package/payload/platform/package.json +1 -1
- package/payload/platform/plugins/.claude-plugin/marketplace.json +101 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/admin/skills/commitment-followthrough/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/session-management/SKILL.md +1 -1
- package/payload/platform/plugins/business-assistant/PLUGIN.md +1 -1
- package/payload/platform/plugins/business-assistant/references/task-management.md +13 -13
- package/payload/platform/plugins/docs/references/admin-session.md +7 -6
- package/payload/platform/plugins/docs/references/internals.md +2 -2
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.js +57 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +9 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
- package/payload/platform/plugins/projects/PLUGIN.md +3 -3
- package/payload/platform/plugins/projects/references/sprint.md +2 -2
- package/payload/platform/plugins/scheduling/skills/briefing/SKILL.md +2 -2
- package/payload/platform/plugins/tasks/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/work/.claude-plugin/plugin.json +17 -0
- package/payload/platform/plugins/{tasks → work}/.mcp.json +2 -2
- package/payload/platform/plugins/work/PLUGIN.md +120 -0
- package/payload/platform/plugins/work/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/index.js +543 -0
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts +7 -0
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js +24 -0
- package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/work/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/lib/neo4j.js +40 -0
- package/payload/platform/plugins/work/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-complete.d.ts +17 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-complete.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-complete.js +76 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-complete.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-create.d.ts +29 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-create.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-create.js +235 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-create.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-get.d.ts +40 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-get.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-get.js +125 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-get.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-list.d.ts +26 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-list.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-list.js +81 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-list.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-update.d.ts +19 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-update.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-update.js +102 -0
- package/payload/platform/plugins/work/mcp/dist/tools/project-update.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts +20 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.js +37 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-name.d.ts +12 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-name.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-name.js +28 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-name.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-complete.d.ts +16 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-complete.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-complete.js +33 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-complete.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +63 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +141 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-get.d.ts +19 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-get.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-get.js +51 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-get.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts +18 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.js +66 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-ready.d.ts +21 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-ready.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-ready.js +54 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-ready.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-relate.d.ts +12 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-relate.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-relate.js +59 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-relate.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts +32 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.js +112 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.js.map +1 -0
- package/payload/platform/plugins/{tasks → work}/mcp/package.json +1 -1
- package/payload/platform/scripts/conversation-id-allowlist.txt +4 -4
- package/payload/platform/scripts/seed-neo4j.sh +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +34 -5
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +32 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +33 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +170 -39
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +10 -4
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +21 -37
- package/payload/platform/templates/specialists/agents/database-operator.md +1 -1
- package/payload/platform/templates/specialists/agents/librarian.md +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/platform/templates/specialists/agents/project-manager.md +3 -3
- package/payload/premium-plugins/real-agent/plugins/leads/PLUGIN.md +1 -1
- package/payload/server/{chunk-ITQ55PCQ.js → chunk-TFEIFU7F.js} +1 -1
- package/payload/server/{chunk-HZ77KMTV.js → chunk-W33UUYYR.js} +1 -4
- package/payload/server/{cloudflare-task-tracker-PZBX7X3D.js → cloudflare-task-tracker-7P355PSD.js} +1 -1
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +50 -18
- package/payload/platform/plugins/tasks/PLUGIN.md +0 -120
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import neo4j from "neo4j-driver";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
let driver = null;
|
|
5
|
+
function readPassword() {
|
|
6
|
+
if (process.env.NEO4J_PASSWORD)
|
|
7
|
+
return process.env.NEO4J_PASSWORD;
|
|
8
|
+
const passwordFile = resolve(process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."), "config/.neo4j-password");
|
|
9
|
+
try {
|
|
10
|
+
return readFileSync(passwordFile, "utf-8").trim();
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error(`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function getDriver() {
|
|
17
|
+
if (!driver) {
|
|
18
|
+
// NEO4J_URI must be explicit. Silent default to:7687 was the
|
|
19
|
+
// vector for the orphan data in Maxy's DB from a realagent install.
|
|
20
|
+
const uri = process.env.NEO4J_URI;
|
|
21
|
+
if (!uri) {
|
|
22
|
+
throw new Error("[tasks] NEO4J_URI unset — refusing to default to bolt://localhost:7687");
|
|
23
|
+
}
|
|
24
|
+
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
25
|
+
const password = readPassword();
|
|
26
|
+
console.error(`[tasks] resolved neo4j_uri=${uri}`);
|
|
27
|
+
driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
|
|
28
|
+
}
|
|
29
|
+
return driver;
|
|
30
|
+
}
|
|
31
|
+
export function getSession() {
|
|
32
|
+
return getDriver().session();
|
|
33
|
+
}
|
|
34
|
+
export async function closeDriver() {
|
|
35
|
+
if (driver) {
|
|
36
|
+
await driver.close();
|
|
37
|
+
driver = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=neo4j.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neo4j.js","sourceRoot":"","sources":["../../src/lib/neo4j.ts"],"names":[],"mappings":"AAAA,OAAO,KAA0B,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAElE,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACxE,wBAAwB,CACzB,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,yCAAyC,YAAY,gCAAgC,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,6DAA6D;QAC7D,oEAAoE;QACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,wEAAwE,CACzE,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,8BAA8B,GAAG,EAAE,CAAC,CAAC;QACnD,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ProjectCompleteParams {
|
|
2
|
+
projectId: string;
|
|
3
|
+
accountId: string;
|
|
4
|
+
note?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ProjectCompleteResult {
|
|
7
|
+
projectId: string;
|
|
8
|
+
completedTasks: number;
|
|
9
|
+
totalTasks: number;
|
|
10
|
+
incompleteChildren: Array<{
|
|
11
|
+
taskId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
status: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export declare function projectComplete(params: ProjectCompleteParams): Promise<ProjectCompleteResult>;
|
|
17
|
+
//# sourceMappingURL=project-complete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-complete.d.ts","sourceRoot":"","sources":["../../src/tools/project-complete.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7E;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAwFnG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getSession } from "../lib/neo4j.js";
|
|
2
|
+
import { computeEmbedding } from "../lib/embeddings.js";
|
|
3
|
+
export async function projectComplete(params) {
|
|
4
|
+
const { projectId, accountId, note } = params;
|
|
5
|
+
const session = getSession();
|
|
6
|
+
try {
|
|
7
|
+
// Fetch the project and its children
|
|
8
|
+
const projectResult = await session.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId})
|
|
9
|
+
OPTIONAL MATCH (p)-[:HAS_TASK]->(child:Task)
|
|
10
|
+
RETURN p,
|
|
11
|
+
collect({taskId: child.taskId, name: child.name, status: child.status}) AS children`, { projectId, accountId });
|
|
12
|
+
if (projectResult.records.length === 0) {
|
|
13
|
+
throw new Error(`ProjectNotFound: ${projectId}`);
|
|
14
|
+
}
|
|
15
|
+
const rec = projectResult.records[0];
|
|
16
|
+
const p = rec.get("p").properties;
|
|
17
|
+
const children = rec.get("children")
|
|
18
|
+
.filter((c) => c.taskId !== null);
|
|
19
|
+
const totalTasks = children.length;
|
|
20
|
+
const completedTasks = children.filter((c) => c.status === "completed" || c.status === "cancelled").length;
|
|
21
|
+
const incompleteChildren = children
|
|
22
|
+
.filter((c) => c.status !== "completed" && c.status !== "cancelled")
|
|
23
|
+
.map((c) => ({ taskId: c.taskId, name: c.name, status: c.status }));
|
|
24
|
+
// Build completion note
|
|
25
|
+
const now = new Date().toISOString();
|
|
26
|
+
const timestamp = now.slice(0, 16).replace("T", " ");
|
|
27
|
+
const deferred = incompleteChildren.length;
|
|
28
|
+
const completionNote = `[${timestamp}] [PROJECT:COMPLETE] ${p.name} — ${completedTasks}/${totalTasks} tasks, ${deferred} deferred`;
|
|
29
|
+
const userNote = note ? `\n[${timestamp}] ${note}` : "";
|
|
30
|
+
const currentNotes = p.notes ?? "";
|
|
31
|
+
const newNotes = currentNotes
|
|
32
|
+
? `${currentNotes}\n${completionNote}${userNote}`
|
|
33
|
+
: `${completionNote}${userNote}`;
|
|
34
|
+
// Re-embed
|
|
35
|
+
const embeddingText = `Project: ${p.name} — ${p.description} tier: ${p.tier} status: completed ${newNotes}`;
|
|
36
|
+
const embedding = await computeEmbedding(embeddingText);
|
|
37
|
+
const setClauses = [
|
|
38
|
+
"p.status = 'completed'",
|
|
39
|
+
"p.phase = 'complete'",
|
|
40
|
+
"p.notes = $notes",
|
|
41
|
+
"p.updatedAt = $updatedAt",
|
|
42
|
+
];
|
|
43
|
+
const queryParams = {
|
|
44
|
+
projectId,
|
|
45
|
+
accountId,
|
|
46
|
+
notes: newNotes,
|
|
47
|
+
updatedAt: now,
|
|
48
|
+
};
|
|
49
|
+
if (embedding.length > 0) {
|
|
50
|
+
setClauses.push("p.embedding = $embedding");
|
|
51
|
+
queryParams.embedding = embedding;
|
|
52
|
+
}
|
|
53
|
+
await session.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId})
|
|
54
|
+
SET ${setClauses.join(", ")}`, queryParams);
|
|
55
|
+
console.error(`project-complete: ${projectId} completed, ${completedTasks}/${totalTasks} done, ${deferred} incomplete`);
|
|
56
|
+
return {
|
|
57
|
+
projectId,
|
|
58
|
+
completedTasks,
|
|
59
|
+
totalTasks,
|
|
60
|
+
incompleteChildren,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (err instanceof Error && err.message.startsWith("ProjectNotFound:")) {
|
|
65
|
+
console.error(`project-complete: failed — ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.error(`project-complete: failed — ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
await session.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=project-complete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-complete.js","sourceRoot":"","sources":["../../src/tools/project-complete.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type CreatedBy } from "../../../../../lib/graph-write/dist/index.js";
|
|
2
|
+
export interface WorkItem {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
priority?: "low" | "normal" | "high" | "urgent";
|
|
6
|
+
dueDate?: string;
|
|
7
|
+
/** Indices of other workItems this item blocks */
|
|
8
|
+
blocks?: number[];
|
|
9
|
+
}
|
|
10
|
+
export interface ProjectCreateParams {
|
|
11
|
+
accountId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
tier: "quick" | "standard" | "full";
|
|
15
|
+
clientRef?: string;
|
|
16
|
+
targetDate?: string;
|
|
17
|
+
dueDate?: string;
|
|
18
|
+
raisedBy?: string;
|
|
19
|
+
affects?: string[];
|
|
20
|
+
workItems?: WorkItem[];
|
|
21
|
+
sessionKey?: string;
|
|
22
|
+
createdBy: CreatedBy;
|
|
23
|
+
}
|
|
24
|
+
export interface ProjectCreateResult {
|
|
25
|
+
projectId: string;
|
|
26
|
+
childTaskIds: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function projectCreate(params: ProjectCreateParams): Promise<ProjectCreateResult>;
|
|
29
|
+
//# sourceMappingURL=project-create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-create.d.ts","sourceRoot":"","sources":["../../src/tools/project-create.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,8CAA8C,CAAC;AAEtD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAkDD,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA6O7F"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { getDriver } from "../lib/neo4j.js";
|
|
3
|
+
import { computeEmbedding } from "../lib/embeddings.js";
|
|
4
|
+
import { stampCreatedBy, } from "../../../../../lib/graph-write/dist/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* Validates that blocks references form a DAG (no cycles).
|
|
7
|
+
* Uses Kahn's algorithm (topological sort) on the workItems array.
|
|
8
|
+
* Throws ValidationError if cycles detected or indices out of range.
|
|
9
|
+
*/
|
|
10
|
+
function validateBlocks(workItems) {
|
|
11
|
+
const n = workItems.length;
|
|
12
|
+
// Build adjacency list and in-degree array
|
|
13
|
+
const adj = Array.from({ length: n }, () => []);
|
|
14
|
+
const inDegree = new Array(n).fill(0);
|
|
15
|
+
for (let i = 0; i < n; i++) {
|
|
16
|
+
const blocks = workItems[i].blocks;
|
|
17
|
+
if (!blocks)
|
|
18
|
+
continue;
|
|
19
|
+
for (const target of blocks) {
|
|
20
|
+
if (target < 0 || target >= n || !Number.isInteger(target)) {
|
|
21
|
+
throw new Error(`ValidationError: blocks index ${target} out of range (0-${n - 1})`);
|
|
22
|
+
}
|
|
23
|
+
if (target === i) {
|
|
24
|
+
throw new Error(`ValidationError: work item ${i} cannot block itself`);
|
|
25
|
+
}
|
|
26
|
+
// i blocks target → edge from i to target
|
|
27
|
+
adj[i].push(target);
|
|
28
|
+
inDegree[target]++;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Kahn's algorithm — process nodes with in-degree 0
|
|
32
|
+
const queue = [];
|
|
33
|
+
for (let i = 0; i < n; i++) {
|
|
34
|
+
if (inDegree[i] === 0)
|
|
35
|
+
queue.push(i);
|
|
36
|
+
}
|
|
37
|
+
let processed = 0;
|
|
38
|
+
while (queue.length > 0) {
|
|
39
|
+
const node = queue.shift();
|
|
40
|
+
processed++;
|
|
41
|
+
for (const neighbor of adj[node]) {
|
|
42
|
+
inDegree[neighbor]--;
|
|
43
|
+
if (inDegree[neighbor] === 0)
|
|
44
|
+
queue.push(neighbor);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (processed < n) {
|
|
48
|
+
throw new Error("ValidationError: circular dependency detected in work item blocks");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function projectCreate(params) {
|
|
52
|
+
const { accountId, name, description, tier, clientRef, targetDate, dueDate, raisedBy, affects, workItems = [], sessionKey, createdBy, } = params;
|
|
53
|
+
// --- Validation ---
|
|
54
|
+
if (workItems.length > 50) {
|
|
55
|
+
throw new Error("ValidationError: workItems exceeds maximum of 50");
|
|
56
|
+
}
|
|
57
|
+
if (workItems.length > 0) {
|
|
58
|
+
validateBlocks(workItems);
|
|
59
|
+
}
|
|
60
|
+
// --- Pre-compute embeddings (outside transaction) ---
|
|
61
|
+
const parentText = `Project: ${name} — ${description} tier: ${tier}`;
|
|
62
|
+
const parentEmbedding = await computeEmbedding(parentText);
|
|
63
|
+
const childEmbeddings = [];
|
|
64
|
+
for (const item of workItems) {
|
|
65
|
+
const text = `Task: ${item.name} — ${item.description} status: pending priority: ${item.priority ?? "normal"}`;
|
|
66
|
+
childEmbeddings.push(await computeEmbedding(text));
|
|
67
|
+
}
|
|
68
|
+
// --- Build node properties ---
|
|
69
|
+
const projectId = randomUUID();
|
|
70
|
+
const now = new Date().toISOString();
|
|
71
|
+
const timestamp = now.slice(0, 16).replace("T", " ");
|
|
72
|
+
const startNote = `[${timestamp}] [PROJECT:START] ${name} — ${tier} tier, ${workItems.length} tasks planned`;
|
|
73
|
+
const rawProjectProps = {
|
|
74
|
+
taskId: projectId,
|
|
75
|
+
accountId,
|
|
76
|
+
name,
|
|
77
|
+
description,
|
|
78
|
+
status: "pending",
|
|
79
|
+
priority: "normal",
|
|
80
|
+
tier,
|
|
81
|
+
phase: "planning",
|
|
82
|
+
notes: startNote,
|
|
83
|
+
createdAt: now,
|
|
84
|
+
updatedAt: now,
|
|
85
|
+
};
|
|
86
|
+
if (clientRef)
|
|
87
|
+
rawProjectProps.clientRef = clientRef;
|
|
88
|
+
if (targetDate)
|
|
89
|
+
rawProjectProps.targetDate = targetDate;
|
|
90
|
+
if (dueDate)
|
|
91
|
+
rawProjectProps.dueDate = dueDate;
|
|
92
|
+
if (parentEmbedding.length > 0)
|
|
93
|
+
rawProjectProps.embedding = parentEmbedding;
|
|
94
|
+
// Write doctrine: flatten provenance onto the node
|
|
95
|
+
// so forensic queries (WHERE n.createdByTool = 'project-create') work.
|
|
96
|
+
// project-create inlines the doctrine instead of routing through
|
|
97
|
+
// writeNodeWithEdges because the outer transaction must encompass
|
|
98
|
+
// child-Task and BLOCKS/RAISED_BY/AFFECTS creation — nested
|
|
99
|
+
// executeWrite is not permitted on a session that already has a
|
|
100
|
+
// managed tx open.
|
|
101
|
+
const projectProps = stampCreatedBy(rawProjectProps, createdBy);
|
|
102
|
+
const childIds = [];
|
|
103
|
+
const childPropsList = [];
|
|
104
|
+
for (let i = 0; i < workItems.length; i++) {
|
|
105
|
+
const item = workItems[i];
|
|
106
|
+
const childId = randomUUID();
|
|
107
|
+
childIds.push(childId);
|
|
108
|
+
const rawChildProps = {
|
|
109
|
+
taskId: childId,
|
|
110
|
+
accountId,
|
|
111
|
+
name: item.name,
|
|
112
|
+
description: item.description,
|
|
113
|
+
status: "pending",
|
|
114
|
+
priority: item.priority ?? "normal",
|
|
115
|
+
createdAt: now,
|
|
116
|
+
updatedAt: now,
|
|
117
|
+
};
|
|
118
|
+
if (item.dueDate)
|
|
119
|
+
rawChildProps.dueDate = item.dueDate;
|
|
120
|
+
if (childEmbeddings[i].length > 0)
|
|
121
|
+
rawChildProps.embedding = childEmbeddings[i];
|
|
122
|
+
// Stamp the same provenance on children. Each child has its own
|
|
123
|
+
// adjacency (HAS_TASK back to the Project) so no per-child
|
|
124
|
+
// pre-resolve is needed — the edge is co-created below.
|
|
125
|
+
childPropsList.push(stampCreatedBy(rawChildProps, createdBy));
|
|
126
|
+
}
|
|
127
|
+
// --- Single transaction: create all nodes and relationships ---
|
|
128
|
+
const driver = getDriver();
|
|
129
|
+
const session = driver.session();
|
|
130
|
+
const tx = session.beginTransaction();
|
|
131
|
+
try {
|
|
132
|
+
// Write doctrine pre-validation: resolve every
|
|
133
|
+
// adjacency source in one UNWIND round-trip BEFORE the Project is
|
|
134
|
+
// created. A Project that has no workItems, no raisedBy, no affects,
|
|
135
|
+
// and no admin-session Conversation is noise — reject loudly per
|
|
136
|
+
// doctrine. This mirrors writeNodeWithEdges' pre-check idiom but
|
|
137
|
+
// stays inside the outer tx so child-Task failures still roll the
|
|
138
|
+
// Project back atomically.
|
|
139
|
+
const candidateIds = [];
|
|
140
|
+
if (raisedBy)
|
|
141
|
+
candidateIds.push(raisedBy);
|
|
142
|
+
if (affects && affects.length > 0)
|
|
143
|
+
candidateIds.push(...affects);
|
|
144
|
+
let resolvedConversationId = null;
|
|
145
|
+
if (sessionKey) {
|
|
146
|
+
const convRes = await tx.run(`MATCH (c:Conversation {sessionKey: $sessionKey, accountId: $accountId})
|
|
147
|
+
RETURN elementId(c) AS id LIMIT 1`, { sessionKey, accountId });
|
|
148
|
+
if (convRes.records.length > 0) {
|
|
149
|
+
resolvedConversationId = convRes.records[0].get("id");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (candidateIds.length > 0) {
|
|
153
|
+
const check = await tx.run(`UNWIND $ids AS id MATCH (t) WHERE elementId(t) = id RETURN collect(id) AS found`, { ids: candidateIds });
|
|
154
|
+
const found = check.records[0].get("found");
|
|
155
|
+
const missing = candidateIds.filter((id) => !found.includes(id));
|
|
156
|
+
if (missing.length > 0) {
|
|
157
|
+
throw new Error(`TargetNotFound: ${missing.length} of ${candidateIds.length} relationship target(s) did not resolve (elementId mismatch): ${missing.join(", ")}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const hasAdjacency = workItems.length > 0 ||
|
|
161
|
+
!!raisedBy ||
|
|
162
|
+
(affects && affects.length > 0) ||
|
|
163
|
+
!!resolvedConversationId;
|
|
164
|
+
if (!hasAdjacency) {
|
|
165
|
+
throw new Error("Write doctrine violated: project-create requires at least one adjacency — pass workItems (≥1), raisedBy, affects, or invoke inside an admin session with an existing Conversation.");
|
|
166
|
+
}
|
|
167
|
+
// Doctrine-satisfying CREATE: adjacency is guaranteed by the
|
|
168
|
+
// pre-validation above. The Project is linked either via HAS_TASK
|
|
169
|
+
// (children below), RAISED_BY/AFFECTS (explicit params), or PART_OF
|
|
170
|
+
// Conversation (session). Within this single tx, intermediate
|
|
171
|
+
// state is not externally observable, so creating the Project
|
|
172
|
+
// first and edges in subsequent statements is safe — the
|
|
173
|
+
// [graph-health] sweep only sees committed state.
|
|
174
|
+
// See .docs/neo4j.md § Write doctrine.
|
|
175
|
+
await tx.run(`CREATE (p:Project:Task $props)`, { props: projectProps });
|
|
176
|
+
// Link to session if the Conversation was resolved above. MATCH not
|
|
177
|
+
// MERGE — a missing Conversation must not spawn an orphan
|
|
178
|
+
// Conversation just to satisfy PART_OF.
|
|
179
|
+
if (resolvedConversationId) {
|
|
180
|
+
await tx.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId})
|
|
181
|
+
MATCH (c) WHERE elementId(c) = $conversationId
|
|
182
|
+
CREATE (p)-[:PART_OF]->(c)`, { projectId, accountId, conversationId: resolvedConversationId });
|
|
183
|
+
}
|
|
184
|
+
// Create child :Task nodes and HAS_TASK relationships
|
|
185
|
+
for (const childProps of childPropsList) {
|
|
186
|
+
await tx.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId})
|
|
187
|
+
CREATE (t:Task $childProps)
|
|
188
|
+
CREATE (p)-[:HAS_TASK]->(t)`, { projectId, accountId, childProps });
|
|
189
|
+
}
|
|
190
|
+
// Create BLOCKS relationships between children
|
|
191
|
+
for (let i = 0; i < workItems.length; i++) {
|
|
192
|
+
const blocks = workItems[i].blocks;
|
|
193
|
+
if (!blocks)
|
|
194
|
+
continue;
|
|
195
|
+
for (const target of blocks) {
|
|
196
|
+
await tx.run(`MATCH (blocker:Task {taskId: $blockerId, accountId: $accountId})
|
|
197
|
+
MATCH (blocked:Task {taskId: $blockedId, accountId: $accountId})
|
|
198
|
+
CREATE (blocker)-[:BLOCKS]->(blocked)`, { blockerId: childIds[i], blockedId: childIds[target], accountId });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Create RAISED_BY relationship
|
|
202
|
+
if (raisedBy) {
|
|
203
|
+
const result = await tx.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId})
|
|
204
|
+
MATCH (person) WHERE elementId(person) = $raisedBy
|
|
205
|
+
CREATE (p)-[:RAISED_BY]->(person)
|
|
206
|
+
RETURN person`, { projectId, accountId, raisedBy });
|
|
207
|
+
if (result.records.length === 0) {
|
|
208
|
+
throw new Error(`TargetNotFound: raisedBy person not found (${raisedBy})`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Create AFFECTS relationships
|
|
212
|
+
if (affects && affects.length > 0) {
|
|
213
|
+
for (const entityId of affects) {
|
|
214
|
+
const result = await tx.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId})
|
|
215
|
+
MATCH (e) WHERE elementId(e) = $entityId
|
|
216
|
+
CREATE (p)-[:AFFECTS]->(e)
|
|
217
|
+
RETURN e`, { projectId, accountId, entityId });
|
|
218
|
+
if (result.records.length === 0) {
|
|
219
|
+
throw new Error(`TargetNotFound: affects entity not found (${entityId})`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
await tx.commit();
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
await tx.rollback();
|
|
227
|
+
throw err;
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
await session.close();
|
|
231
|
+
}
|
|
232
|
+
console.error(`project-create: created ${projectId} with ${childIds.length} children, tier=${tier}`);
|
|
233
|
+
return { projectId, childTaskIds: childIds };
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=project-create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-create.js","sourceRoot":"","sources":["../../src/tools/project-create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ChildTaskSummary {
|
|
2
|
+
taskId: string;
|
|
3
|
+
name: string;
|
|
4
|
+
status: string;
|
|
5
|
+
priority: string;
|
|
6
|
+
dueDate?: string;
|
|
7
|
+
blockedBy: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface ProjectHealth {
|
|
10
|
+
signal: "green" | "amber" | "red" | "grey";
|
|
11
|
+
totalTasks: number;
|
|
12
|
+
completedTasks: number;
|
|
13
|
+
overdueTasks: number;
|
|
14
|
+
blockedTasks: number;
|
|
15
|
+
daysSinceLastProgress: number | null;
|
|
16
|
+
}
|
|
17
|
+
export interface ProjectDetail {
|
|
18
|
+
projectId: string;
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
tier: string;
|
|
22
|
+
phase: string;
|
|
23
|
+
status: string;
|
|
24
|
+
clientRef?: string;
|
|
25
|
+
targetDate?: string;
|
|
26
|
+
dueDate?: string;
|
|
27
|
+
notes?: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
updatedAt: string;
|
|
30
|
+
health: ProjectHealth;
|
|
31
|
+
children: ChildTaskSummary[];
|
|
32
|
+
relationships: Array<{
|
|
33
|
+
type: string;
|
|
34
|
+
targetLabel: string;
|
|
35
|
+
targetId: string;
|
|
36
|
+
targetName?: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
export declare function projectGet(projectId: string, accountId: string): Promise<ProjectDetail>;
|
|
40
|
+
//# sourceMappingURL=project-get.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-get.d.ts","sourceRoot":"","sources":["../../src/tools/project-get.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,aAAa,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0I7F"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { getSession } from "../lib/neo4j.js";
|
|
2
|
+
export async function projectGet(projectId, accountId) {
|
|
3
|
+
const session = getSession();
|
|
4
|
+
try {
|
|
5
|
+
// Fetch the project node (must have :Project label)
|
|
6
|
+
const projectResult = await session.run(`MATCH (p:Project {taskId: $projectId, accountId: $accountId}) RETURN p`, { projectId, accountId });
|
|
7
|
+
if (projectResult.records.length === 0) {
|
|
8
|
+
throw new Error(`ProjectNotFound: ${projectId}`);
|
|
9
|
+
}
|
|
10
|
+
const p = projectResult.records[0].get("p").properties;
|
|
11
|
+
// Fetch children with their blockers
|
|
12
|
+
const childrenResult = await session.run(`MATCH (proj:Project {taskId: $projectId, accountId: $accountId})-[:HAS_TASK]->(child:Task)
|
|
13
|
+
OPTIONAL MATCH (blocker:Task)-[:BLOCKS]->(child)
|
|
14
|
+
WHERE blocker.status IN ['pending', 'active']
|
|
15
|
+
RETURN child,
|
|
16
|
+
collect(DISTINCT blocker.taskId) AS blockedByIds
|
|
17
|
+
ORDER BY
|
|
18
|
+
CASE child.priority
|
|
19
|
+
WHEN 'urgent' THEN 0
|
|
20
|
+
WHEN 'high' THEN 1
|
|
21
|
+
WHEN 'normal' THEN 2
|
|
22
|
+
WHEN 'low' THEN 3
|
|
23
|
+
ELSE 4
|
|
24
|
+
END,
|
|
25
|
+
child.createdAt`, { projectId, accountId });
|
|
26
|
+
const children = childrenResult.records.map((rec) => {
|
|
27
|
+
const c = rec.get("child").properties;
|
|
28
|
+
const blockedByIds = rec.get("blockedByIds").filter((id) => id !== null);
|
|
29
|
+
const child = {
|
|
30
|
+
taskId: c.taskId,
|
|
31
|
+
name: c.name,
|
|
32
|
+
status: c.status,
|
|
33
|
+
priority: c.priority,
|
|
34
|
+
blockedBy: blockedByIds,
|
|
35
|
+
};
|
|
36
|
+
if (c.dueDate)
|
|
37
|
+
child.dueDate = c.dueDate;
|
|
38
|
+
return child;
|
|
39
|
+
});
|
|
40
|
+
// Compute health
|
|
41
|
+
const totalTasks = children.length;
|
|
42
|
+
const completedTasks = children.filter((c) => c.status === "completed").length;
|
|
43
|
+
const overdueTasks = children.filter((c) => {
|
|
44
|
+
if (!c.dueDate || c.status === "completed")
|
|
45
|
+
return false;
|
|
46
|
+
return new Date(c.dueDate) < new Date();
|
|
47
|
+
}).length;
|
|
48
|
+
const blockedTasks = children.filter((c) => c.blockedBy.length > 0).length;
|
|
49
|
+
let daysSinceLastProgress = null;
|
|
50
|
+
const completedChildren = children.filter((c) => c.status === "completed");
|
|
51
|
+
if (completedChildren.length > 0) {
|
|
52
|
+
// Approximate: use project's updatedAt as proxy for last progress
|
|
53
|
+
// (full computation would need child updatedAt, not returned in this query)
|
|
54
|
+
daysSinceLastProgress = null;
|
|
55
|
+
}
|
|
56
|
+
let signal = "green";
|
|
57
|
+
if (totalTasks === 0) {
|
|
58
|
+
signal = "grey";
|
|
59
|
+
}
|
|
60
|
+
else if (overdueTasks > 1 || (daysSinceLastProgress !== null && daysSinceLastProgress >= 7)) {
|
|
61
|
+
signal = "red";
|
|
62
|
+
}
|
|
63
|
+
else if (overdueTasks > 0 || blockedTasks > 0) {
|
|
64
|
+
signal = "amber";
|
|
65
|
+
}
|
|
66
|
+
const health = {
|
|
67
|
+
signal,
|
|
68
|
+
totalTasks,
|
|
69
|
+
completedTasks,
|
|
70
|
+
overdueTasks,
|
|
71
|
+
blockedTasks,
|
|
72
|
+
daysSinceLastProgress,
|
|
73
|
+
};
|
|
74
|
+
// Fetch non-HAS_TASK relationships (RAISED_BY, AFFECTS, PART_OF)
|
|
75
|
+
const relResult = await session.run(`MATCH (proj:Project {taskId: $projectId, accountId: $accountId})-[r]->(target)
|
|
76
|
+
WHERE type(r) <> 'HAS_TASK'
|
|
77
|
+
RETURN type(r) AS relType, labels(target) AS targetLabels, elementId(target) AS targetId,
|
|
78
|
+
target.name AS targetName, target.givenName AS targetGivenName`, { projectId, accountId });
|
|
79
|
+
const relationships = relResult.records.map((rec) => {
|
|
80
|
+
const targetLabels = rec.get("targetLabels");
|
|
81
|
+
const targetLabel = targetLabels[0] ?? "Unknown";
|
|
82
|
+
const targetId = rec.get("targetId");
|
|
83
|
+
const targetName = rec.get("targetName") ??
|
|
84
|
+
rec.get("targetGivenName") ??
|
|
85
|
+
targetId;
|
|
86
|
+
return { type: rec.get("relType"), targetLabel, targetId, targetName };
|
|
87
|
+
});
|
|
88
|
+
const detail = {
|
|
89
|
+
projectId: p.taskId,
|
|
90
|
+
name: p.name,
|
|
91
|
+
description: p.description,
|
|
92
|
+
tier: p.tier,
|
|
93
|
+
phase: p.phase,
|
|
94
|
+
status: p.status,
|
|
95
|
+
createdAt: p.createdAt,
|
|
96
|
+
updatedAt: p.updatedAt,
|
|
97
|
+
health,
|
|
98
|
+
children,
|
|
99
|
+
relationships,
|
|
100
|
+
};
|
|
101
|
+
if (p.clientRef)
|
|
102
|
+
detail.clientRef = p.clientRef;
|
|
103
|
+
if (p.targetDate)
|
|
104
|
+
detail.targetDate = p.targetDate;
|
|
105
|
+
if (p.dueDate)
|
|
106
|
+
detail.dueDate = p.dueDate;
|
|
107
|
+
if (p.notes)
|
|
108
|
+
detail.notes = p.notes;
|
|
109
|
+
console.error(`project-get: returned ${projectId} with ${children.length} children`);
|
|
110
|
+
return detail;
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err instanceof Error && err.message.startsWith("ProjectNotFound:")) {
|
|
114
|
+
console.error(`project-get: failed — ${err.message}`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.error(`project-get: failed — ${err instanceof Error ? err.message : String(err)}`);
|
|
118
|
+
}
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
await session.close();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=project-get.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-get.js","sourceRoot":"","sources":["../../src/tools/project-get.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ProjectHealth {
|
|
2
|
+
signal: "green" | "amber" | "red" | "grey";
|
|
3
|
+
totalTasks: number;
|
|
4
|
+
completedTasks: number;
|
|
5
|
+
overdueTasks: number;
|
|
6
|
+
blockedTasks: number;
|
|
7
|
+
daysSinceLastProgress: number | null;
|
|
8
|
+
}
|
|
9
|
+
export interface ProjectSummary {
|
|
10
|
+
projectId: string;
|
|
11
|
+
name: string;
|
|
12
|
+
tier: string;
|
|
13
|
+
phase: string;
|
|
14
|
+
status: string;
|
|
15
|
+
clientRef?: string;
|
|
16
|
+
targetDate?: string;
|
|
17
|
+
health: ProjectHealth;
|
|
18
|
+
nextAction?: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function projectList(params: {
|
|
22
|
+
accountId: string;
|
|
23
|
+
status?: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
}): Promise<ProjectSummary[]>;
|
|
26
|
+
//# sourceMappingURL=project-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-list.d.ts","sourceRoot":"","sources":["../../src/tools/project-list.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqBD,wBAAsB,WAAW,CAAC,MAAM,EAAE;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAsE5B"}
|