@projitive/mcp 1.0.4 → 1.0.6
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 +4 -4
- package/output/package.json +4 -5
- package/output/source/design-context.js +515 -0
- package/output/source/index.js +50 -41
- package/output/source/projitive.js +8 -9
- package/output/source/roadmap.js +2 -2
- package/output/source/tasks.js +5 -6
- package/package.json +4 -5
- package/output/designs.js +0 -38
- package/output/helpers/artifacts/artifacts.js +0 -10
- package/output/helpers/artifacts/artifacts.test.js +0 -18
- package/output/helpers/artifacts/index.js +0 -1
- package/output/helpers/catch/catch.js +0 -48
- package/output/helpers/catch/catch.test.js +0 -43
- package/output/helpers/catch/index.js +0 -1
- package/output/helpers/files/files.js +0 -62
- package/output/helpers/files/files.test.js +0 -32
- package/output/helpers/files/index.js +0 -1
- package/output/helpers/index.js +0 -6
- package/output/helpers/linter/codes.js +0 -25
- package/output/helpers/linter/index.js +0 -2
- package/output/helpers/linter/linter.js +0 -6
- package/output/helpers/linter/linter.test.js +0 -16
- package/output/helpers/markdown/index.js +0 -1
- package/output/helpers/markdown/markdown.js +0 -33
- package/output/helpers/markdown/markdown.test.js +0 -36
- package/output/helpers/response/index.js +0 -1
- package/output/helpers/response/response.js +0 -73
- package/output/helpers/response/response.test.js +0 -50
- package/output/hooks.js +0 -49
- package/output/hooks.test.js +0 -40
- package/output/index.js +0 -227
- package/output/projitive.js +0 -488
- package/output/projitive.test.js +0 -75
- package/output/prompts.js +0 -87
- package/output/readme.js +0 -26
- package/output/rendering-input-guard.test.js +0 -20
- package/output/reports.js +0 -36
- package/output/resources.js +0 -95
- package/output/roadmap.js +0 -165
- package/output/roadmap.test.js +0 -11
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/projectContext.md +0 -48
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/projectInit.md +0 -40
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/projectLocate.md +0 -22
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/projectNext.md +0 -31
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/projectScan.md +0 -28
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/roadmapContext.md +0 -33
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/roadmapList.md +0 -25
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/summary.json +0 -90
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/summary.md +0 -17
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/taskContext.md +0 -47
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/taskList.md +0 -27
- package/output/smoke-reports/2026-02-18T13-18-19-740Z/taskNext.md +0 -64
- package/output/tasks.js +0 -762
- package/output/tasks.test.js +0 -152
package/output/tasks.test.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { TASKS_END, TASKS_START, collectTaskLintSuggestions, isValidTaskId, normalizeTask, parseTasksBlock, rankActionableTaskCandidates, resolveNoTaskDiscoveryGuidance, renderTaskSeedTemplate, renderTasksMarkdown, taskPriority, toTaskUpdatedAtMs, validateTransition, } from "./tasks.js";
|
|
3
|
-
import fs from "node:fs/promises";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
function buildCandidate(partial) {
|
|
7
|
-
const task = normalizeTask({
|
|
8
|
-
id: partial.id,
|
|
9
|
-
title: partial.title,
|
|
10
|
-
status: partial.status,
|
|
11
|
-
updatedAt: partial.task?.updatedAt ?? "2026-01-01T00:00:00.000Z",
|
|
12
|
-
});
|
|
13
|
-
return {
|
|
14
|
-
governanceDir: partial.governanceDir ?? "/workspace/a",
|
|
15
|
-
tasksPath: partial.tasksPath ?? "/workspace/a/tasks.md",
|
|
16
|
-
task,
|
|
17
|
-
projectScore: partial.projectScore ?? 1,
|
|
18
|
-
projectLatestUpdatedAt: partial.projectLatestUpdatedAt ?? "2026-01-01T00:00:00.000Z",
|
|
19
|
-
taskUpdatedAtMs: partial.taskUpdatedAtMs ?? toTaskUpdatedAtMs(task.updatedAt),
|
|
20
|
-
taskPriority: partial.taskPriority ?? taskPriority(task.status),
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
describe("tasks module", () => {
|
|
24
|
-
it("parses markdown task block and normalizes task fields", async () => {
|
|
25
|
-
const markdown = [
|
|
26
|
-
"# Tasks",
|
|
27
|
-
TASKS_START,
|
|
28
|
-
"## TASK-0001 | TODO | hello",
|
|
29
|
-
"- owner: alice",
|
|
30
|
-
"- summary: first task",
|
|
31
|
-
"- updatedAt: 2026-02-17T00:00:00.000Z",
|
|
32
|
-
"- roadmapRefs: ROADMAP-0001",
|
|
33
|
-
"- links:",
|
|
34
|
-
" - ./designs/example.md",
|
|
35
|
-
TASKS_END,
|
|
36
|
-
].join("\n");
|
|
37
|
-
const tasks = await parseTasksBlock(markdown);
|
|
38
|
-
expect(tasks).toHaveLength(1);
|
|
39
|
-
expect(tasks[0].id).toBe("TASK-0001");
|
|
40
|
-
expect(tasks[0].status).toBe("TODO");
|
|
41
|
-
expect(tasks[0].roadmapRefs).toEqual(["ROADMAP-0001"]);
|
|
42
|
-
expect(tasks[0].links).toEqual(["./designs/example.md"]);
|
|
43
|
-
});
|
|
44
|
-
it("renders markdown containing markers", () => {
|
|
45
|
-
const task = normalizeTask({ id: "TASK-0002", title: "render", status: "IN_PROGRESS" });
|
|
46
|
-
const markdown = renderTasksMarkdown([task]);
|
|
47
|
-
expect(markdown.includes(TASKS_START)).toBe(true);
|
|
48
|
-
expect(markdown.includes(TASKS_END)).toBe(true);
|
|
49
|
-
expect(markdown.includes("## TASK-0002 | IN_PROGRESS | render")).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
it("validates task IDs", () => {
|
|
52
|
-
expect(isValidTaskId("TASK-0001")).toBe(true);
|
|
53
|
-
expect(isValidTaskId("TASK-001")).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
it("allows and rejects expected transitions", () => {
|
|
56
|
-
expect(validateTransition("TODO", "IN_PROGRESS")).toBe(true);
|
|
57
|
-
expect(validateTransition("IN_PROGRESS", "DONE")).toBe(true);
|
|
58
|
-
expect(validateTransition("DONE", "IN_PROGRESS")).toBe(false);
|
|
59
|
-
});
|
|
60
|
-
it("assigns priority for actionable statuses", () => {
|
|
61
|
-
expect(taskPriority("IN_PROGRESS")).toBe(2);
|
|
62
|
-
expect(taskPriority("TODO")).toBe(1);
|
|
63
|
-
expect(taskPriority("BLOCKED")).toBe(0);
|
|
64
|
-
});
|
|
65
|
-
it("returns zero timestamp for invalid date", () => {
|
|
66
|
-
expect(toTaskUpdatedAtMs("invalid")).toBe(0);
|
|
67
|
-
});
|
|
68
|
-
it("ranks by project score, then task priority, then recency", () => {
|
|
69
|
-
const candidates = [
|
|
70
|
-
buildCandidate({ id: "TASK-0001", title: "A", status: "TODO", projectScore: 2 }),
|
|
71
|
-
buildCandidate({ id: "TASK-0002", title: "B", status: "IN_PROGRESS", projectScore: 2 }),
|
|
72
|
-
buildCandidate({ id: "TASK-0003", title: "C", status: "IN_PROGRESS", projectScore: 3 }),
|
|
73
|
-
];
|
|
74
|
-
const ranked = rankActionableTaskCandidates(candidates);
|
|
75
|
-
expect(ranked[0].task.id).toBe("TASK-0003");
|
|
76
|
-
expect(ranked[1].task.id).toBe("TASK-0002");
|
|
77
|
-
expect(ranked[2].task.id).toBe("TASK-0001");
|
|
78
|
-
});
|
|
79
|
-
it("renders lint lines with stable code prefix", () => {
|
|
80
|
-
const task = normalizeTask({
|
|
81
|
-
id: "TASK-0001",
|
|
82
|
-
title: "lint",
|
|
83
|
-
status: "IN_PROGRESS",
|
|
84
|
-
owner: "",
|
|
85
|
-
roadmapRefs: [],
|
|
86
|
-
});
|
|
87
|
-
const lint = collectTaskLintSuggestions([task]);
|
|
88
|
-
expect(lint.some((line) => line.startsWith("- [TASK_IN_PROGRESS_OWNER_EMPTY]"))).toBe(true);
|
|
89
|
-
expect(lint.some((line) => line.startsWith("- [TASK_ROADMAP_REFS_EMPTY]"))).toBe(true);
|
|
90
|
-
});
|
|
91
|
-
it("scopes outside-marker lint to provided task IDs", () => {
|
|
92
|
-
const tasks = [
|
|
93
|
-
normalizeTask({ id: "TASK-0001", title: "A", status: "TODO", roadmapRefs: ["ROADMAP-0001"] }),
|
|
94
|
-
normalizeTask({ id: "TASK-0002", title: "B", status: "TODO", roadmapRefs: ["ROADMAP-0001"] }),
|
|
95
|
-
];
|
|
96
|
-
const markdown = [
|
|
97
|
-
"# Tasks",
|
|
98
|
-
"TASK-0002 outside",
|
|
99
|
-
"TASK-0003 outside",
|
|
100
|
-
TASKS_START,
|
|
101
|
-
"## TASK-0001 | TODO | A",
|
|
102
|
-
"- owner: (none)",
|
|
103
|
-
"- summary: (none)",
|
|
104
|
-
"- updatedAt: 2026-02-18T00:00:00.000Z",
|
|
105
|
-
"- roadmapRefs: ROADMAP-0001",
|
|
106
|
-
"- links:",
|
|
107
|
-
" - (none)",
|
|
108
|
-
"## TASK-0002 | TODO | B",
|
|
109
|
-
"- owner: (none)",
|
|
110
|
-
"- summary: (none)",
|
|
111
|
-
"- updatedAt: 2026-02-18T00:00:00.000Z",
|
|
112
|
-
"- roadmapRefs: ROADMAP-0001",
|
|
113
|
-
"- links:",
|
|
114
|
-
" - (none)",
|
|
115
|
-
TASKS_END,
|
|
116
|
-
].join("\n");
|
|
117
|
-
const scoped = collectTaskLintSuggestions(tasks, markdown, new Set(["TASK-0001"]));
|
|
118
|
-
const scopedOutside = scoped.find((line) => line.includes("TASK IDs found outside marker block"));
|
|
119
|
-
expect(scopedOutside).toBeUndefined();
|
|
120
|
-
const all = collectTaskLintSuggestions(tasks, markdown);
|
|
121
|
-
const allOutside = all.find((line) => line.includes("TASK IDs found outside marker block"));
|
|
122
|
-
expect(allOutside).toContain("TASK-0002");
|
|
123
|
-
expect(allOutside).toContain("TASK-0003");
|
|
124
|
-
});
|
|
125
|
-
it("renders seed task template with provided roadmap ref", () => {
|
|
126
|
-
const lines = renderTaskSeedTemplate("ROADMAP-0099");
|
|
127
|
-
const markdown = lines.join("\n");
|
|
128
|
-
expect(markdown).toContain("## TASK-0001 | TODO | Define initial executable objective");
|
|
129
|
-
expect(markdown).toContain("- roadmapRefs: ROADMAP-0099");
|
|
130
|
-
expect(markdown).toContain("- links:");
|
|
131
|
-
expect(markdown).not.toContain("- hooks:");
|
|
132
|
-
});
|
|
133
|
-
it("uses default no-task guidance when hook file is absent", async () => {
|
|
134
|
-
const guidance = await resolveNoTaskDiscoveryGuidance("/path/that/does/not/exist");
|
|
135
|
-
expect(guidance.length).toBeGreaterThan(3);
|
|
136
|
-
expect(guidance.some((line) => line.includes("TODO/FIXME/HACK"))).toBe(true);
|
|
137
|
-
});
|
|
138
|
-
it("uses hook checklist when task_no_actionable hook exists", async () => {
|
|
139
|
-
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "projitive-mcp-test-"));
|
|
140
|
-
const hooksDir = path.join(dir, "hooks");
|
|
141
|
-
await fs.mkdir(hooksDir, { recursive: true });
|
|
142
|
-
await fs.writeFile(path.join(hooksDir, "task_no_actionable.md"), [
|
|
143
|
-
"Objective:",
|
|
144
|
-
"- custom-item-1",
|
|
145
|
-
"- custom-item-2",
|
|
146
|
-
].join("\n"), "utf-8");
|
|
147
|
-
const guidance = await resolveNoTaskDiscoveryGuidance(dir);
|
|
148
|
-
expect(guidance).toContain("- custom-item-1");
|
|
149
|
-
expect(guidance).toContain("- custom-item-2");
|
|
150
|
-
await fs.rm(dir, { recursive: true, force: true });
|
|
151
|
-
});
|
|
152
|
-
});
|