@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cliangdev/flux-plugin",
3
- "version": "0.4.0-dev.17634ed",
3
+ "version": "0.4.0-dev.236e9f1",
4
4
  "description": "Claude Code plugin for AI-first workflow orchestration with MCP server",
5
5
  "type": "module",
6
6
  "main": "./dist/server/index.js",
@@ -223,7 +223,14 @@ describe("prd status mappers", () => {
223
223
  expect(prdStatusToLabel("ARCHIVED")).toBeNull();
224
224
  });
225
225
 
226
- test("labelToPrdStatus detects ARCHIVED from closed state", async () => {
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",
@@ -362,7 +362,7 @@ export class GitHubAdapter implements BackendAdapter {
362
362
  updateParams.title = input.title;
363
363
  }
364
364
 
365
- if (newStatus === "ARCHIVED") {
365
+ if (newStatus === "COMPLETED" || newStatus === "ARCHIVED") {
366
366
  updateParams.state = "closed";
367
367
  }
368
368
 
@@ -23,7 +23,10 @@ export function labelToPrdStatus(
23
23
  labels: string[],
24
24
  isClosed: boolean,
25
25
  ): PrdStatus {
26
- if (isClosed) return "ARCHIVED";
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))
@@ -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";