@programinglive/dev-workflow-mcp-server 1.8.1 → 1.10.0

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.
Files changed (114) hide show
  1. package/.env.example +21 -1
  2. package/AGENTS.md +25 -0
  3. package/README.md +372 -649
  4. package/factory-client.js +554 -0
  5. package/git-facade.js +35 -0
  6. package/index.js +9 -34
  7. package/package.json +21 -20
  8. package/scripts/bootstrap-unix.sh +55 -0
  9. package/scripts/bootstrap-windows.ps1 +75 -0
  10. package/scripts/install-husky.js +43 -0
  11. package/scripts/setup-stack.js +436 -0
  12. package/scripts/setup-test-dbs.sh +61 -0
  13. package/scripts/test-db-adapters.sh +71 -0
  14. package/scripts/verify-bundle.mjs +92 -0
  15. package/tools/definitions.js +143 -0
  16. package/tools/handler-modules/commit-handlers.js +2 -1
  17. package/tools/handler-modules/factory-handlers.js +276 -0
  18. package/tools/handler-modules/index.js +24 -7
  19. package/tools/handler-modules/shared.js +7 -41
  20. package/tools/handler-modules/status-handlers.js +25 -3
  21. package/tools/handler-modules/workflow-handlers.js +57 -10
  22. package/vite.config.js +6 -0
  23. package/workflow-state.js +176 -2
  24. package/.agent/workflows/dev-workflow-bugfix.md +0 -250
  25. package/.agent/workflows/dev-workflow-feature.md +0 -201
  26. package/.agent/workflows/dev-workflow-full-cycle.md +0 -400
  27. package/.agent/workflows/dev-workflow-refactor.md +0 -238
  28. package/.env.production +0 -16
  29. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -34
  30. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -25
  31. package/.github/pull_request_template.md +0 -22
  32. package/.github/workflows/github-release.yml +0 -131
  33. package/.husky/commit-msg +0 -3
  34. package/.husky/pre-commit +0 -2
  35. package/CHANGELOG.md +0 -1145
  36. package/docs/GCP_DEPLOYMENT.md +0 -298
  37. package/docs/NETLIFY_DEPLOYMENT.md +0 -125
  38. package/docs/PLESK_DEPLOYMENT.md +0 -170
  39. package/docs/PRD.md +0 -86
  40. package/docs/WORKFLOW-BEST-PRACTICES.md +0 -58
  41. package/docs/antigravity/EXAMPLES.md +0 -535
  42. package/docs/antigravity/GETTING-STARTED.md +0 -292
  43. package/docs/antigravity/TROUBLESHOOTING.md +0 -742
  44. package/docs/antigravity/WALKTHROUGH.md +0 -25
  45. package/docs/antigravity/WORKFLOW-TEMPLATES.md +0 -670
  46. package/docs/release-notes/RELEASE_NOTES.md +0 -524
  47. package/docs/web-dashboard.md +0 -175
  48. package/scripts/test-auth-flow.js +0 -75
  49. package/tailwind.config.js +0 -8
  50. package/tests/build.test.js +0 -74
  51. package/tests/db-adapters.test.js +0 -108
  52. package/tests/env-support.test.js +0 -46
  53. package/tests/exec.test.js +0 -35
  54. package/tests/handlers-commit.test.js +0 -174
  55. package/tests/handlers-release.test.js +0 -212
  56. package/tests/handlers-workflow.test.js +0 -68
  57. package/tests/handlers.test.js +0 -1142
  58. package/tests/hello-world.test.js +0 -13
  59. package/tests/mcpRegistry.test.js +0 -65
  60. package/tests/patch-release.test.js +0 -7
  61. package/tests/release-wrapper.test.js +0 -107
  62. package/tests/startup-resilience.test.js +0 -73
  63. package/tests/test-helpers.js +0 -50
  64. package/tests/workflowState.test.js +0 -520
  65. package/web/Dockerfile.api +0 -25
  66. package/web/README.md +0 -133
  67. package/web/__tests__/api/workflow-history.test.js +0 -63
  68. package/web/api-server.js +0 -211
  69. package/web/app/docs/page.tsx +0 -202
  70. package/web/app/favicon.ico +0 -0
  71. package/web/app/globals.css +0 -91
  72. package/web/app/history/page.tsx +0 -220
  73. package/web/app/layout.tsx +0 -39
  74. package/web/app/login/page.tsx +0 -142
  75. package/web/app/page.tsx +0 -13
  76. package/web/components/ApiReference.tsx +0 -20
  77. package/web/components/Features.tsx +0 -61
  78. package/web/components/Footer.tsx +0 -9
  79. package/web/components/Hero.tsx +0 -96
  80. package/web/components/History.tsx +0 -175
  81. package/web/components/Navbar.tsx +0 -208
  82. package/web/components/Terminal.tsx +0 -114
  83. package/web/components/ThemeProvider.tsx +0 -58
  84. package/web/eslint.config.mjs +0 -18
  85. package/web/lib/api-client.ts +0 -123
  86. package/web/lib/auth.js +0 -75
  87. package/web/lib/db.js +0 -131
  88. package/web/lib/docs.js +0 -73
  89. package/web/middleware/auth.js +0 -26
  90. package/web/netlify.toml +0 -8
  91. package/web/next.config.ts +0 -19
  92. package/web/package-lock.json +0 -10911
  93. package/web/package.json +0 -42
  94. package/web/postcss.config.mjs +0 -9
  95. package/web/public/assets/android-chrome-192x192.png +0 -0
  96. package/web/public/assets/android-chrome-512x512.png +0 -0
  97. package/web/public/assets/apple-touch-icon.png +0 -0
  98. package/web/public/assets/favicon-16x16.png +0 -0
  99. package/web/public/assets/favicon-32x32.png +0 -0
  100. package/web/public/assets/favicon.ico +0 -0
  101. package/web/public/assets/favicon.png +0 -0
  102. package/web/public/assets/logo.png +0 -0
  103. package/web/public/assets/og-preview.png +0 -0
  104. package/web/public/assets/site.webmanifest +0 -1
  105. package/web/public/file.svg +0 -1
  106. package/web/public/globe.svg +0 -1
  107. package/web/public/next.svg +0 -1
  108. package/web/public/vercel.svg +0 -1
  109. package/web/public/window.svg +0 -1
  110. package/web/scripts/db-query-history.js +0 -120
  111. package/web/scripts/smoke-test.js +0 -30
  112. package/web/server.js +0 -184
  113. package/web/tailwind.config.ts +0 -20
  114. package/web/tsconfig.json +0 -42
@@ -1,13 +0,0 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert';
3
- import { execSync } from 'node:child_process';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
-
9
- test('hello world script runs successfully', (t) => {
10
- const scriptPath = path.join(__dirname, '../scripts/hello-world.js');
11
- const output = execSync(`node ${scriptPath}`).toString();
12
- assert.match(output, /Hello from Antigravity!/);
13
- });
@@ -1,65 +0,0 @@
1
- import { test } from "node:test";
2
- import assert from "node:assert";
3
- import { readFile } from "node:fs/promises";
4
- import path from "node:path";
5
-
6
- const projectRoot = process.cwd();
7
-
8
- async function readJson(relativePath) {
9
- const fullPath = path.join(projectRoot, relativePath);
10
- const content = await readFile(fullPath, "utf-8");
11
- return JSON.parse(content);
12
- }
13
-
14
- test("package.json includes mcpName for MCP registry", async () => {
15
- const pkg = await readJson("package.json");
16
-
17
- assert.strictEqual(
18
- pkg.mcpName,
19
- "io.github.programinglive/dev-workflow-mcp-server",
20
- "package.json should declare mcpName matching the MCP server namespace",
21
- );
22
- });
23
-
24
- test("server.json is configured for npm package deployment", async () => {
25
- const server = await readJson("server.json");
26
-
27
- assert.strictEqual(
28
- server.name,
29
- "io.github.programinglive/dev-workflow-mcp-server",
30
- "server.json name should match the MCP server namespace",
31
- );
32
- assert.ok(Array.isArray(server.packages) && server.packages.length > 0,
33
- "server.json should declare at least one package entry",
34
- );
35
-
36
- const npmPkg = server.packages[0];
37
-
38
- assert.strictEqual(
39
- npmPkg.registryType,
40
- "npm",
41
- "First server.json package entry should use npm registryType",
42
- );
43
-
44
- assert.strictEqual(
45
- npmPkg.registryBaseUrl,
46
- "https://registry.npmjs.org",
47
- "server.json npm registryBaseUrl should point at the public npm registry",
48
- );
49
-
50
- assert.strictEqual(
51
- npmPkg.identifier,
52
- "@programinglive/dev-workflow-mcp-server",
53
- "server.json npm identifier should match the published npm package name",
54
- );
55
-
56
- assert.ok(
57
- typeof npmPkg.version === "string" && npmPkg.version.length > 0,
58
- "server.json npm package version should be a non-empty string",
59
- );
60
-
61
- assert.ok(
62
- npmPkg.transport && npmPkg.transport.type === "stdio",
63
- "server.json npm package transport should be stdio",
64
- );
65
- });
@@ -1,7 +0,0 @@
1
- import { test } from 'node:test'
2
- import { strict as assert } from 'node:assert'
3
-
4
- test('patch release preparation', () => {
5
- // Verify we can prepare a patch release
6
- assert.ok(true, 'Patch release 1.5.3 preparation completed')
7
- })
@@ -1,107 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtemp, rm, writeFile, readFile, mkdir } from "node:fs/promises";
4
- import { tmpdir } from "node:os";
5
- import path from "node:path";
6
- import { fileURLToPath } from "node:url";
7
- import { spawn } from "node:child_process";
8
-
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = path.dirname(__filename);
11
- const releaseWrapperUrl = new URL("../release-wrapper.js", import.meta.url);
12
- const RELEASE_WRAPPER = fileURLToPath(releaseWrapperUrl);
13
- const PROJECT_ROOT = path.dirname(RELEASE_WRAPPER);
14
-
15
- async function runWrapper({ state, args = ["patch"], env = {} }) {
16
- const dir = await mkdtemp(path.join(tmpdir(), "release-wrapper-test-"));
17
- const stateDir = path.join(dir, ".state");
18
- const statePath = path.join(stateDir, "workflow-state.json");
19
- await mkdir(stateDir, { recursive: true });
20
- await writeFile(statePath, JSON.stringify(state, null, 2));
21
- // Create package.json so resolveStateFile recognizes this as a project root
22
- await writeFile(path.join(dir, "package.json"), JSON.stringify({ name: "test-project" }));
23
-
24
- const childEnv = {
25
- ...process.env,
26
- INIT_CWD: dir,
27
- DEV_WORKFLOW_SKIP_RELEASE: "1",
28
- DEV_WORKFLOW_FORCE_RELEASE: undefined,
29
- ...env,
30
- };
31
-
32
- const nodeBinary = process.platform === "win32" ? "node" : process.execPath || "node";
33
- const spawnShell = process.platform === "win32";
34
-
35
- return await new Promise((resolve) => {
36
- const child = spawn(
37
- nodeBinary,
38
- [RELEASE_WRAPPER, ...args],
39
- {
40
- cwd: PROJECT_ROOT,
41
- env: childEnv,
42
- stdio: ["ignore", "pipe", "pipe"],
43
- shell: spawnShell,
44
- }
45
- );
46
-
47
- let stdout = "";
48
- let stderr = "";
49
-
50
- child.stdout.on("data", (chunk) => {
51
- stdout += chunk;
52
- });
53
- child.stderr.on("data", (chunk) => {
54
- stderr += chunk;
55
- });
56
-
57
- child.on("close", async (code) => {
58
- let updatedState = null;
59
- try {
60
- const rawState = await readFile(statePath, "utf8");
61
- updatedState = JSON.parse(rawState);
62
- } catch {
63
- // ignore
64
- }
65
-
66
- await rm(dir, { recursive: true, force: true });
67
- resolve({ code, stdout, stderr, updatedState });
68
- });
69
- });
70
- }
71
-
72
- test("release-wrapper blocks when workflow phase is not release", async () => {
73
- const result = await runWrapper({
74
- state: {
75
- currentPhase: "commit",
76
- readyCheckCompleted: true,
77
- commitAndPushCompleted: true,
78
- released: false,
79
- },
80
- });
81
-
82
- assert.equal(result.code, 1);
83
- assert.ok(result.stderr.includes("Release guard blocked the release"));
84
- assert.ok(result.stderr.includes("Current workflow phase"));
85
- assert.equal(result.updatedState.released, false);
86
- });
87
-
88
- test("release-wrapper marks release after validation passes", async () => {
89
- const result = await runWrapper({
90
- state: {
91
- currentPhase: "release",
92
- readyCheckCompleted: true,
93
- commitAndPushCompleted: true,
94
- released: false,
95
- releaseCommand: "",
96
- },
97
- });
98
-
99
- assert.equal(result.code, 0);
100
- assert.ok(result.stdout.includes("Release recorded"));
101
- assert.equal(result.updatedState.released, true);
102
- assert.equal(result.updatedState.currentPhase, "ready_to_complete");
103
- assert.equal(
104
- result.updatedState.releaseCommand,
105
- "node node_modules/@programinglive/commiter/scripts/release.js patch"
106
- );
107
- });
@@ -1,73 +0,0 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert';
3
- import { spawn } from 'node:child_process';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- const ROOT = path.join(__dirname, '..');
10
-
11
- test('Server startup performance and resilience', async (t) => {
12
- await t.test('Server starts in under 2 seconds (Studio timeout safety)', async () => {
13
- const start = Date.now();
14
- const server = spawn('node', [path.join(ROOT, 'index.js')], {
15
- env: { ...process.env, DEV_WORKFLOW_DB_TYPE: 'sqlite' },
16
- stdio: ['pipe', 'pipe', 'pipe']
17
- });
18
-
19
- return new Promise((resolve, reject) => {
20
- let output = '';
21
- const timeout = setTimeout(() => {
22
- server.kill();
23
- reject(new Error('Server timed out starting'));
24
- }, 5000);
25
-
26
- server.stderr.on('data', (data) => {
27
- output += data.toString();
28
- if (output.includes('running on stdio')) {
29
- const duration = Date.now() - start;
30
- console.log(`Verified startup duration: ${duration}ms`);
31
- assert.ok(duration < 2000, `Startup should be fast (took ${duration}ms)`);
32
- clearTimeout(timeout);
33
- server.kill();
34
- resolve();
35
- }
36
- });
37
-
38
- server.on('error', (err) => {
39
- clearTimeout(timeout);
40
- reject(err);
41
- });
42
- });
43
- });
44
-
45
- await t.test('Resilience: Server starts even with unreachable database', async () => {
46
- const server = spawn('node', [path.join(ROOT, 'index.js')], {
47
- env: {
48
- ...process.env,
49
- DEV_WORKFLOW_DB_TYPE: 'postgres',
50
- DEV_WORKFLOW_DB_URL: 'postgres://user:pass@1.2.3.4:5432/invalid'
51
- },
52
- stdio: ['pipe', 'pipe', 'pipe']
53
- });
54
-
55
- return new Promise((resolve, reject) => {
56
- let output = '';
57
- const timeout = setTimeout(() => {
58
- server.kill();
59
- reject(new Error('Server hung on unreachable DB'));
60
- }, 15000); // Allow time for the 5s DB timeout + startup
61
-
62
- server.stderr.on('data', (data) => {
63
- output += data.toString();
64
- if (output.includes('running on stdio')) {
65
- assert.ok(true, 'Server started despite invalid DB');
66
- clearTimeout(timeout);
67
- server.kill();
68
- resolve();
69
- }
70
- });
71
- });
72
- });
73
- });
@@ -1,50 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import path from "node:path";
4
- import { WorkflowState } from "../workflow-state.js";
5
- import { shellEscape } from "../utils.js";
6
- import { determineReleaseTypeFromCommit, createCommitMessageParts } from "../commit-helpers.js";
7
-
8
- export async function withWorkflowState(callback) {
9
- const tempDir = await mkdtemp(path.join(tmpdir(), "workflow-handlers-"));
10
- const stateFile = path.join(tempDir, "state.json");
11
- const state = new WorkflowState(stateFile);
12
- await state.load();
13
-
14
- try {
15
- await callback(state);
16
- } finally {
17
- await rm(tempDir, { recursive: true, force: true });
18
- }
19
- }
20
-
21
- export const testUtils = {
22
- shellEscape,
23
- determineReleaseTypeFromCommit,
24
- createCommitMessageParts,
25
- };
26
-
27
- export function createRequest(name, args) {
28
- return {
29
- params: {
30
- name,
31
- arguments: args,
32
- },
33
- };
34
- }
35
-
36
- export function createGitMock(overrides = {}) {
37
- return {
38
- hasWorkingChanges: async () => false,
39
- hasStagedChanges: async () => false,
40
- hasTestChanges: async () => true,
41
- getStagedChanges: async () => [],
42
- getCurrentBranch: async () => "main",
43
- getPrimaryBranch: async () => "main",
44
- getLastCommitMessage: async () => "",
45
- getStatusOutput: async () => "",
46
- containsTestFilesInStatus: (statusOutput) => statusOutput.includes("tests/"),
47
- workingTreeSummary: () => ({ hasChanges: false, lines: [] }),
48
- ...overrides,
49
- };
50
- }