@cliangdev/flux-plugin 0.4.0-dev.17634ed → 0.4.0-dev.236e9f1
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/package.json +1 -1
- package/src/server/adapters/github/__tests__/prd-crud.test.ts +8 -1
- package/src/server/adapters/github/adapter.ts +1 -1
- package/src/server/adapters/github/mappers/prd.ts +4 -1
- package/src/server/index.ts +2 -0
- package/src/server/tools/__tests__/get-project-context.test.ts +81 -0
- package/src/server/tools/get-project-context.ts +28 -0
- package/src/server/tools/index.ts +1 -0
package/package.json
CHANGED
|
@@ -223,7 +223,14 @@ describe("prd status mappers", () => {
|
|
|
223
223
|
expect(prdStatusToLabel("ARCHIVED")).toBeNull();
|
|
224
224
|
});
|
|
225
225
|
|
|
226
|
-
test("labelToPrdStatus detects
|
|
226
|
+
test("labelToPrdStatus detects COMPLETED from closed state with completed label", async () => {
|
|
227
|
+
const { labelToPrdStatus } = await import("../mappers/prd.js");
|
|
228
|
+
expect(labelToPrdStatus(["flux:prd", "status:completed"], true)).toBe(
|
|
229
|
+
"COMPLETED",
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("labelToPrdStatus detects ARCHIVED from closed state without completed label", async () => {
|
|
227
234
|
const { labelToPrdStatus } = await import("../mappers/prd.js");
|
|
228
235
|
expect(labelToPrdStatus(["flux:prd", "status:draft"], true)).toBe(
|
|
229
236
|
"ARCHIVED",
|
|
@@ -23,7 +23,10 @@ export function labelToPrdStatus(
|
|
|
23
23
|
labels: string[],
|
|
24
24
|
isClosed: boolean,
|
|
25
25
|
): PrdStatus {
|
|
26
|
-
if (isClosed)
|
|
26
|
+
if (isClosed) {
|
|
27
|
+
if (labels.includes(GITHUB_LABELS.STATUS_COMPLETED)) return "COMPLETED";
|
|
28
|
+
return "ARCHIVED";
|
|
29
|
+
}
|
|
27
30
|
|
|
28
31
|
if (labels.includes(GITHUB_LABELS.STATUS_COMPLETED)) return "COMPLETED";
|
|
29
32
|
if (labels.includes(GITHUB_LABELS.STATUS_BREAKDOWN_READY))
|
package/src/server/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
createTaskTool,
|
|
13
13
|
deleteEntityTool,
|
|
14
14
|
getEntityTool,
|
|
15
|
+
getProjectContextTool,
|
|
15
16
|
getStatsTool,
|
|
16
17
|
getVersionTool,
|
|
17
18
|
initProjectTool,
|
|
@@ -48,6 +49,7 @@ const tools: ToolDefinition[] = [
|
|
|
48
49
|
getEntityTool,
|
|
49
50
|
queryEntitiesTool,
|
|
50
51
|
initProjectTool,
|
|
52
|
+
getProjectContextTool,
|
|
51
53
|
getStatsTool,
|
|
52
54
|
getVersionTool,
|
|
53
55
|
// Configuration tools
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
const TEST_DIR = `/tmp/flux-test-project-context-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
6
|
+
const FLUX_DIR = join(TEST_DIR, ".flux");
|
|
7
|
+
process.env.FLUX_PROJECT_ROOT = TEST_DIR;
|
|
8
|
+
|
|
9
|
+
import { config } from "../../config.js";
|
|
10
|
+
import { getProjectContextTool } from "../get-project-context.js";
|
|
11
|
+
|
|
12
|
+
describe("get_project_context", () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
config.clearCache();
|
|
15
|
+
process.env.FLUX_PROJECT_ROOT = TEST_DIR;
|
|
16
|
+
mkdirSync(FLUX_DIR, { recursive: true });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("returns local adapter when no adapter configured", async () => {
|
|
24
|
+
writeFileSync(
|
|
25
|
+
join(FLUX_DIR, "project.json"),
|
|
26
|
+
JSON.stringify({ name: "test-project", vision: "A test project" }),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const result = (await getProjectContextTool.handler({})) as any;
|
|
30
|
+
|
|
31
|
+
expect(result.name).toBe("test-project");
|
|
32
|
+
expect(result.vision).toBe("A test project");
|
|
33
|
+
expect(result.adapter.type).toBe("local");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("returns github adapter type when configured", async () => {
|
|
37
|
+
writeFileSync(
|
|
38
|
+
join(FLUX_DIR, "project.json"),
|
|
39
|
+
JSON.stringify({
|
|
40
|
+
name: "gh-project",
|
|
41
|
+
vision: "GitHub project",
|
|
42
|
+
refPrefix: "GH",
|
|
43
|
+
adapter: { type: "github" },
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const result = (await getProjectContextTool.handler({})) as any;
|
|
48
|
+
|
|
49
|
+
expect(result.name).toBe("gh-project");
|
|
50
|
+
expect(result.vision).toBe("GitHub project");
|
|
51
|
+
expect(result.ref_prefix).toBe("GH");
|
|
52
|
+
expect(result.adapter.type).toBe("github");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("returns linear adapter type when configured", async () => {
|
|
56
|
+
writeFileSync(
|
|
57
|
+
join(FLUX_DIR, "project.json"),
|
|
58
|
+
JSON.stringify({
|
|
59
|
+
name: "linear-project",
|
|
60
|
+
adapter: { type: "linear" },
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const result = (await getProjectContextTool.handler({})) as any;
|
|
65
|
+
|
|
66
|
+
expect(result.name).toBe("linear-project");
|
|
67
|
+
expect(result.adapter.type).toBe("linear");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("has correct tool definition", () => {
|
|
71
|
+
expect(getProjectContextTool.name).toBe("get_project_context");
|
|
72
|
+
expect(getProjectContextTool.description).toContain("adapter");
|
|
73
|
+
expect(getProjectContextTool.inputSchema).toBeDefined();
|
|
74
|
+
expect(getProjectContextTool.handler).toBeDefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("throws when project.json does not exist", async () => {
|
|
78
|
+
// No project.json written
|
|
79
|
+
expect(getProjectContextTool.handler({})).rejects.toThrow();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { config } from "../config.js";
|
|
4
|
+
import type { ToolDefinition } from "./index.js";
|
|
5
|
+
|
|
6
|
+
const inputSchema = z.object({});
|
|
7
|
+
|
|
8
|
+
async function handler(_input: unknown) {
|
|
9
|
+
const content = readFileSync(config.projectJsonPath, "utf-8");
|
|
10
|
+
const project = JSON.parse(content);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
name: project.name ?? null,
|
|
14
|
+
vision: project.vision ?? null,
|
|
15
|
+
ref_prefix: project.refPrefix ?? null,
|
|
16
|
+
adapter: {
|
|
17
|
+
type: project.adapter?.type ?? "local",
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getProjectContextTool: ToolDefinition = {
|
|
23
|
+
name: "get_project_context",
|
|
24
|
+
description:
|
|
25
|
+
"Get project context including adapter type, project name, vision, and ref prefix. No parameters required. Returns {name, vision, ref_prefix, adapter: {type: 'local' | 'github' | 'linear'}}. Use this to detect which adapter is configured before performing adapter-specific operations.",
|
|
26
|
+
inputSchema,
|
|
27
|
+
handler,
|
|
28
|
+
};
|
|
@@ -150,6 +150,7 @@ export { deleteEntityTool } from "./delete-entity.js";
|
|
|
150
150
|
export { addDependencyTool, removeDependencyTool } from "./dependencies.js";
|
|
151
151
|
export { getEntityTool } from "./get-entity.js";
|
|
152
152
|
export { getLinearUrlTool } from "./get-linear-url.js";
|
|
153
|
+
export { getProjectContextTool } from "./get-project-context.js";
|
|
153
154
|
export { getStatsTool } from "./get-stats.js";
|
|
154
155
|
export { getVersionTool } from "./get-version.js";
|
|
155
156
|
export { initProjectTool } from "./init-project.js";
|