@guanlin4924/devflow-pi 0.1.94 → 0.1.96
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 +34 -4
- package/node_modules/@playwright/test/LICENSE +202 -0
- package/node_modules/@playwright/test/NOTICE +5 -0
- package/node_modules/@playwright/test/README.md +318 -0
- package/node_modules/@playwright/test/cli.js +19 -0
- package/node_modules/@playwright/test/index.d.ts +18 -0
- package/node_modules/@playwright/test/index.js +17 -0
- package/node_modules/@playwright/test/index.mjs +18 -0
- package/node_modules/@playwright/test/package.json +35 -0
- package/node_modules/@playwright/test/reporter.d.ts +17 -0
- package/node_modules/@playwright/test/reporter.js +17 -0
- package/node_modules/@playwright/test/reporter.mjs +17 -0
- package/node_modules/playwright/LICENSE +202 -0
- package/node_modules/playwright/NOTICE +5 -0
- package/node_modules/playwright/README.md +318 -0
- package/node_modules/playwright/ThirdPartyNotices.txt +14 -0
- package/node_modules/playwright/cli.js +19 -0
- package/node_modules/playwright/index.d.ts +17 -0
- package/node_modules/playwright/index.js +17 -0
- package/node_modules/playwright/index.mjs +18 -0
- package/node_modules/playwright/jsx-runtime.js +42 -0
- package/node_modules/playwright/jsx-runtime.mjs +21 -0
- package/node_modules/playwright/lib/agents/agentParser.js +89 -0
- package/node_modules/playwright/lib/agents/copilot-setup-steps.yml +34 -0
- package/node_modules/playwright/lib/agents/generateAgents.js +395 -0
- package/node_modules/playwright/lib/agents/playwright-test-coverage.prompt.md +31 -0
- package/node_modules/playwright/lib/agents/playwright-test-generate.prompt.md +8 -0
- package/node_modules/playwright/lib/agents/playwright-test-generator.agent.md +88 -0
- package/node_modules/playwright/lib/agents/playwright-test-heal.prompt.md +6 -0
- package/node_modules/playwright/lib/agents/playwright-test-healer.agent.md +56 -0
- package/node_modules/playwright/lib/agents/playwright-test-plan.prompt.md +9 -0
- package/node_modules/playwright/lib/agents/playwright-test-planner.agent.md +74 -0
- package/node_modules/playwright/lib/cli/reportActions.js +78 -0
- package/node_modules/playwright/lib/cli/testActions.js +214 -0
- package/node_modules/playwright/lib/common/index.js +2923 -0
- package/node_modules/playwright/lib/common/index.js.txt +34 -0
- package/node_modules/playwright/lib/errorContext.js +129 -0
- package/node_modules/playwright/lib/globals.js +58 -0
- package/node_modules/playwright/lib/index.js +815 -0
- package/node_modules/playwright/lib/isomorphic.js +260 -0
- package/node_modules/playwright/lib/isomorphic.js.txt +9 -0
- package/node_modules/playwright/lib/loader/loaderProcessEntry.js +34 -0
- package/node_modules/playwright/lib/loader/loaderProcessEntry.js.txt +9 -0
- package/node_modules/playwright/lib/matchers/expect.js +13490 -0
- package/node_modules/playwright/lib/matchers/expect.js.LICENSE +640 -0
- package/node_modules/playwright/lib/matchers/expect.js.txt +67 -0
- package/node_modules/playwright/lib/mcp/test/browserBackend.js +135 -0
- package/node_modules/playwright/lib/mcp/test/generatorTools.js +122 -0
- package/node_modules/playwright/lib/mcp/test/plannerTools.js +150 -0
- package/node_modules/playwright/lib/mcp/test/seed.js +82 -0
- package/node_modules/playwright/lib/mcp/test/streams.js +44 -0
- package/node_modules/playwright/lib/mcp/test/testBackend.js +99 -0
- package/node_modules/playwright/lib/mcp/test/testContext.js +306 -0
- package/node_modules/playwright/lib/mcp/test/testTool.js +30 -0
- package/node_modules/playwright/lib/mcp/test/testTools.js +98 -0
- package/node_modules/playwright/lib/package.js +47 -0
- package/node_modules/playwright/lib/program.js +241 -0
- package/node_modules/playwright/lib/runner/index.js +8527 -0
- package/node_modules/playwright/lib/runner/index.js.txt +61 -0
- package/node_modules/playwright/lib/transform/babelBundle.js +72274 -0
- package/node_modules/playwright/lib/transform/babelBundle.js.LICENSE +2384 -0
- package/node_modules/playwright/lib/transform/babelBundle.js.txt +325 -0
- package/node_modules/playwright/lib/transform/esmLoader.js +8054 -0
- package/node_modules/playwright/lib/transform/esmLoader.js.LICENSE +355 -0
- package/node_modules/playwright/lib/transform/esmLoader.js.txt +60 -0
- package/node_modules/playwright/lib/util.js +373 -0
- package/node_modules/playwright/lib/worker/workerProcessEntry.js +1861 -0
- package/node_modules/playwright/lib/worker/workerProcessEntry.js.txt +19 -0
- package/node_modules/playwright/package.json +55 -0
- package/node_modules/playwright/test.d.ts +18 -0
- package/node_modules/playwright/test.js +24 -0
- package/node_modules/playwright/test.mjs +35 -0
- package/node_modules/playwright/types/test.d.ts +11074 -0
- package/node_modules/playwright/types/testReporter.d.ts +950 -0
- package/node_modules/playwright-core/LICENSE +202 -0
- package/node_modules/playwright-core/NOTICE +5 -0
- package/node_modules/playwright-core/README.md +3 -0
- package/node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
- package/node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
- package/node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/browsers.json +52 -0
- package/node_modules/playwright-core/cli.js +21 -0
- package/node_modules/playwright-core/index.d.ts +17 -0
- package/node_modules/playwright-core/index.js +17 -0
- package/node_modules/playwright-core/index.mjs +28 -0
- package/node_modules/playwright-core/lib/bootstrap.js +88 -0
- package/node_modules/playwright-core/lib/coreBundle.js +75813 -0
- package/node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
- package/node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
- package/node_modules/playwright-core/lib/entry/mcp.js +10 -0
- package/node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
- package/node_modules/playwright-core/lib/package.js +50 -0
- package/node_modules/playwright-core/lib/server/chromium/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/server/electron/loader.js +116 -0
- package/node_modules/playwright-core/lib/serverRegistry.js +1939 -0
- package/node_modules/playwright-core/lib/serverRegistry.js.LICENSE +65 -0
- package/node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
- package/node_modules/playwright-core/lib/tools/cli-client/cli.js +6 -0
- package/node_modules/playwright-core/lib/tools/cli-client/help.json +721 -0
- package/node_modules/playwright-core/lib/tools/cli-client/minimist.js +128 -0
- package/node_modules/playwright-core/lib/tools/cli-client/output.js +351 -0
- package/node_modules/playwright-core/lib/tools/cli-client/program.js +418 -0
- package/node_modules/playwright-core/lib/tools/cli-client/registry.js +180 -0
- package/node_modules/playwright-core/lib/tools/cli-client/session.js +259 -0
- package/node_modules/playwright-core/lib/tools/dashboard/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/SKILL.md +425 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/SKILL.md +136 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/migration.md +89 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/react.md +69 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/typing.md +173 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/vue.md +77 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-trace/SKILL.md +174 -0
- package/node_modules/playwright-core/lib/tools/utils/extension.js +112 -0
- package/node_modules/playwright-core/lib/tools/utils/socketConnection.js +108 -0
- package/node_modules/playwright-core/lib/utilsBundle.js +85357 -0
- package/node_modules/playwright-core/lib/utilsBundle.js.LICENSE +1890 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg +24 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/index.html +16 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.css +2 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-CVQWJZAA.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-hrlLqLtq.js +129 -0
- package/node_modules/playwright-core/lib/vite/recorder/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BbkfBe3n.js +32 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Ds6CBOo0.js +182 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-DywYcAf8.js +7 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.Bqk9acqE.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B4cLoZK3.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.html +44 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest +16 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.html +10 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js +4 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CU5KtEkS.js +5 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +18 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
- package/node_modules/playwright-core/lib/webp_codec.LICENSE +173 -0
- package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
- package/node_modules/playwright-core/lib/xdg-open +1267 -0
- package/node_modules/playwright-core/package.json +34 -0
- package/node_modules/playwright-core/types/protocol.d.ts +24645 -0
- package/node_modules/playwright-core/types/structs.d.ts +52 -0
- package/node_modules/playwright-core/types/types.d.ts +26632 -0
- package/package.json +13 -2
- package/plugins/devflow-core/extensions/devflow-core.ts +432 -7
- package/plugins/devflow-core/runtime/hooks/hook_common.py +514 -0
- package/plugins/devflow-core/runtime/hooks/index_gate.py +47 -16
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/acceptance_test_runner.py +488 -71
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +51 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_pins.py +433 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_store.py +137 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_coverage.py +87 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_draft.py +53 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_v1.py +318 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/environment_profile.py +134 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_contract.rb +1 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_surface.py +138 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/playwright_adapter.py +515 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tc_hash.py +132 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_command_policy.py +102 -8
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +13 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +13 -34
- package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +3 -1
- package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +68 -140
- package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization_database.py +1 -1
- package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +3 -1
- package/plugins/devflow-intel/extensions/devflow-intel.ts +1 -1
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +23 -4
- package/plugins/devflow-quality/runtime/playwright/devflow-test-dsl-v1.schema.json +872 -0
- package/plugins/devflow-quality/runtime/playwright/playwright.config.mjs +46 -0
- package/plugins/devflow-quality/runtime/playwright/reporter.mjs +311 -0
- package/plugins/devflow-quality/runtime/playwright/runner.spec.mjs +1308 -0
- package/plugins/devflow-quality/runtime/playwright/runtime-manifest.json +11 -0
- package/plugins/devflow-quality/skills/workflow-acceptance-test-design/SKILL.md +3 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +71 -58
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/api-mainflow-rules.md +20 -15
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +3 -1
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/intermediate-format.md +115 -192
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/mainflow-selection.md +27 -23
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +78 -153
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/ui-mainflow-rules.md +36 -83
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +497 -556
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/export_legacy_testagent.py +647 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/normalize_case_payloads.py +10 -3
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/validate_case_payloads.py +165 -275
- package/plugins/devflow-quality/skills/workflow-human-acceptance/SKILL.md +63 -0
- package/plugins/devflow-quality/skills/workflow-release-closeout/SKILL.md +4 -4
- package/plugins/devflow-quality/skills/workflow-run-acceptance-tests/SKILL.md +17 -9
- package/src/approval-store.ts +340 -0
- package/src/cli.ts +10 -0
- package/src/constants.ts +1 -1
- package/src/doctor.ts +268 -2
- package/src/initialization-store.ts +48 -1
- package/src/mcp/auth.ts +103 -0
- package/src/mcp/core.ts +102 -0
- package/src/mcp/server.ts +193 -0
- package/src/mcp/types.ts +5 -0
- package/src/paths.ts +12 -1
- package/src/project-context.ts +24 -1
- package/templates/omp/hook-config.json +6 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
import { devflowHome } from "../paths.ts";
|
|
9
|
+
import { authorize, FEATURE_RE, loadAuthorization, MAX_DSL_BYTES, McpError, requestHash } from "./auth.ts";
|
|
10
|
+
import { dslScript, invokeCore, runPython } from "./core.ts";
|
|
11
|
+
import type { CoreRunner, McpServerOptions, McpToolName } from "./types.ts";
|
|
12
|
+
|
|
13
|
+
const RESPONSE_LIMIT = 64 * 1024;
|
|
14
|
+
|
|
15
|
+
type ProgressCallback = () => void | Promise<void>;
|
|
16
|
+
|
|
17
|
+
function bounded(value: unknown): string {
|
|
18
|
+
const text = JSON.stringify(value);
|
|
19
|
+
if (text.length <= RESPONSE_LIMIT) return text;
|
|
20
|
+
return JSON.stringify({
|
|
21
|
+
ok: false,
|
|
22
|
+
reason: "response_truncated",
|
|
23
|
+
truncated: true,
|
|
24
|
+
output: text.slice(0, RESPONSE_LIMIT - 80),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function toolResult(value: unknown) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text" as const, text: bounded(value) }],
|
|
31
|
+
isError: Boolean(value && typeof value === "object" && (value as { ok?: unknown }).ok === false),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function audit(home: string, row: Record<string, unknown>): Promise<void> {
|
|
36
|
+
const directory = path.join(home, "mcp-audit");
|
|
37
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
38
|
+
const file = path.join(directory, `${new Date().toISOString().slice(0, 7)}.jsonl`);
|
|
39
|
+
await appendFile(file, `${JSON.stringify(row)}\n`, { mode: 0o600 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function collectEnvironmentProfiles(value: unknown): Set<string> {
|
|
43
|
+
const profiles = new Set<string>();
|
|
44
|
+
const visit = (current: unknown): void => {
|
|
45
|
+
if (Array.isArray(current)) {
|
|
46
|
+
current.forEach(visit);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!current || typeof current !== "object") return;
|
|
50
|
+
const record = current as Record<string, unknown>;
|
|
51
|
+
if ((record.kind === "devflow_playwright" || record.adapter_kind === "devflow_playwright") && typeof record.environment_profile === "string") {
|
|
52
|
+
profiles.add(record.environment_profile);
|
|
53
|
+
}
|
|
54
|
+
Object.values(record).forEach(visit);
|
|
55
|
+
};
|
|
56
|
+
visit(value);
|
|
57
|
+
return profiles;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const MAX_FAILURE_ERRORS = 50;
|
|
61
|
+
const MAX_FAILURE_ERROR_CHARS = 500;
|
|
62
|
+
|
|
63
|
+
// Failure details must not expose project or run locations (same rule as the Core report).
|
|
64
|
+
function scrubPaths(text: string): string {
|
|
65
|
+
return text
|
|
66
|
+
.replace(/(?:[A-Za-z]:)?[^\s,;()"']+[\/][^\s,;()"']+/g, "<path>")
|
|
67
|
+
.slice(0, MAX_FAILURE_ERROR_CHARS);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// A run that executed TCs always answers with the Core report, even when TCs failed or are
|
|
71
|
+
// blocked: the report's gate says whether acceptance passed. Only runs that never produced
|
|
72
|
+
// results (lock held, invalid bindings/approvals, Core crash) short-circuit with an error.
|
|
73
|
+
function runFailure(value: Record<string, unknown>): Record<string, unknown> {
|
|
74
|
+
const code = typeof value.error_code === "string" ? value.error_code
|
|
75
|
+
: typeof value.reason === "string" && value.reason ? value.reason
|
|
76
|
+
: Array.isArray(value.errors) && value.errors.length > 0 ? "acceptance_validation_failed"
|
|
77
|
+
: "core_failed";
|
|
78
|
+
const errors = Array.isArray(value.errors) ? value.errors.slice(0, MAX_FAILURE_ERRORS).map(item => scrubPaths(String(item))) : [];
|
|
79
|
+
return { ok: false, error_code: code, reason: code, errors };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function createMcpServer(options: McpServerOptions) {
|
|
83
|
+
const home = options.home ?? devflowHome();
|
|
84
|
+
const config = await loadAuthorization(options.client, home);
|
|
85
|
+
const runner: CoreRunner = options.runner ?? runPython;
|
|
86
|
+
let running = false;
|
|
87
|
+
|
|
88
|
+
const server = new McpServer({ name: "devflow-acceptance", version: "1.0.0" });
|
|
89
|
+
|
|
90
|
+
const call = async (tool: McpToolName, args: Record<string, unknown>, onProgress?: ProgressCallback): Promise<Record<string, unknown>> => {
|
|
91
|
+
const started = Date.now();
|
|
92
|
+
let ok = false;
|
|
93
|
+
let reason: string | null = null;
|
|
94
|
+
try {
|
|
95
|
+
if (tool === "dsl_draft_validate") {
|
|
96
|
+
const dslText = JSON.stringify(args.dsl);
|
|
97
|
+
if (typeof dslText !== "string" || Buffer.byteLength(dslText) > MAX_DSL_BYTES) {
|
|
98
|
+
throw new McpError("mcp_input_invalid", "DSL exceeds 2 MiB or is not JSON");
|
|
99
|
+
}
|
|
100
|
+
const auth = await authorize(config, options.client, tool, args.project ?? process.cwd());
|
|
101
|
+
const raw = await runner(dslScript, [], auth.project, JSON.stringify({ dsl: args.dsl, tc_data: args.tc_data }));
|
|
102
|
+
if (raw.timedOut) return { ok: false, error_code: "core_failed", reason: "core_failed" };
|
|
103
|
+
try {
|
|
104
|
+
const parsed = JSON.parse(raw.stdout) as Record<string, unknown>;
|
|
105
|
+
ok = parsed.ok === true;
|
|
106
|
+
return parsed;
|
|
107
|
+
} catch {
|
|
108
|
+
return { ok: false, error_code: "core_failed", reason: raw.stderr || raw.stdout };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const feature = args.feature;
|
|
113
|
+
const auth = await authorize(config, options.client, tool, args.project, feature);
|
|
114
|
+
if (tool === "run_feature" && running) throw new McpError("mcp_busy", "another run_feature is in progress");
|
|
115
|
+
|
|
116
|
+
if (tool === "run_feature") {
|
|
117
|
+
const bindingFile = path.join(auth.project, ".devflow/planning/features", String(feature), "acceptance-test-bindings.json");
|
|
118
|
+
let bindings: unknown;
|
|
119
|
+
try {
|
|
120
|
+
bindings = JSON.parse(await readFile(bindingFile, "utf8"));
|
|
121
|
+
} catch {
|
|
122
|
+
throw new McpError("mcp_input_invalid", "acceptance-test-bindings.json is missing or invalid");
|
|
123
|
+
}
|
|
124
|
+
const profiles = collectEnvironmentProfiles(bindings);
|
|
125
|
+
if ([...profiles].some(profile => !auth.grant.environment_profiles.includes(profile))) {
|
|
126
|
+
throw new McpError("mcp_environment_not_allowed", "environment profile is not authorized");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
running = true;
|
|
130
|
+
try {
|
|
131
|
+
const runResult = await invokeCore(
|
|
132
|
+
runner,
|
|
133
|
+
"run",
|
|
134
|
+
auth.project,
|
|
135
|
+
String(feature),
|
|
136
|
+
Math.min(7_200_000, Math.max(1, options.runTimeoutSeconds ?? 7200) * 1000),
|
|
137
|
+
onProgress,
|
|
138
|
+
);
|
|
139
|
+
if (!Array.isArray(runResult.results)) return runFailure(runResult);
|
|
140
|
+
const report = await invokeCore(runner, "report", auth.project, String(feature));
|
|
141
|
+
ok = report.ok === true;
|
|
142
|
+
return report;
|
|
143
|
+
} finally {
|
|
144
|
+
running = false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const coreResult = await invokeCore(runner, tool === "validate_feature" ? "validate" : "report", auth.project, String(feature));
|
|
149
|
+
ok = coreResult.ok === true;
|
|
150
|
+
return coreResult;
|
|
151
|
+
} catch (error) {
|
|
152
|
+
const mcpError = error instanceof McpError
|
|
153
|
+
? error
|
|
154
|
+
: new McpError("core_failed", error instanceof Error ? error.message : String(error));
|
|
155
|
+
reason = mcpError.code;
|
|
156
|
+
return { ok: false, error_code: mcpError.code, reason: mcpError.message };
|
|
157
|
+
} finally {
|
|
158
|
+
await audit(home, {
|
|
159
|
+
ts: new Date().toISOString(),
|
|
160
|
+
client: options.client,
|
|
161
|
+
project_id: typeof args.project === "string" ? requestHash(path.resolve(args.project)) : null,
|
|
162
|
+
tool,
|
|
163
|
+
feature: args.feature ?? null,
|
|
164
|
+
ok,
|
|
165
|
+
reason,
|
|
166
|
+
duration_ms: Date.now() - started,
|
|
167
|
+
request_sha256: requestHash(args),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const input = z.object({ project: z.string(), feature: z.string().regex(FEATURE_RE) });
|
|
173
|
+
const withProgress = (tool: McpToolName) => (args: any, extra: any) => {
|
|
174
|
+
const token = extra._meta?.progressToken;
|
|
175
|
+
const progress = token === undefined
|
|
176
|
+
? undefined
|
|
177
|
+
: () => extra.sendNotification({ method: "notifications/progress", params: { progressToken: token, progress: Date.now(), message: "run_feature is still running" } });
|
|
178
|
+
return call(tool, args, progress).then(toolResult);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
server.registerTool("validate_feature", { description: "Validate a feature; no artifacts are returned.", inputSchema: input.shape }, withProgress("validate_feature"));
|
|
182
|
+
server.registerTool("run_feature", { description: "Run a feature, then return only the Core report. Approval is never confirmed here; blocked tests require /devflow.", inputSchema: input.shape }, withProgress("run_feature"));
|
|
183
|
+
server.registerTool("get_feature_report", { description: "Get the Core feature report; no artifacts are returned.", inputSchema: input.shape }, withProgress("get_feature_report"));
|
|
184
|
+
server.registerTool("dsl_draft_validate", { description: "Validate DSL schema and coverage only; this does not make the draft executable and does not check approvals or manifests.", inputSchema: { project: z.string(), dsl: z.unknown(), tc_data: z.unknown() } }, withProgress("dsl_draft_validate"));
|
|
185
|
+
|
|
186
|
+
Object.assign(server, { invoke: call, boundedForTest: bounded });
|
|
187
|
+
return server;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function startMcpServer(options: McpServerOptions): Promise<void> {
|
|
191
|
+
const server = await createMcpServer(options);
|
|
192
|
+
await server.connect(new StdioServerTransport());
|
|
193
|
+
}
|
package/src/mcp/types.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type McpToolName = "validate_feature" | "run_feature" | "get_feature_report" | "dsl_draft_validate";
|
|
2
|
+
export type CoreResult = { ok: boolean; [key: string]: unknown };
|
|
3
|
+
export type CoreRunnerResult = { exitCode: number | null; stdout: string; stderr: string; timedOut?: boolean };
|
|
4
|
+
export type CoreRunner = (script: string, args: string[], cwd: string, stdin?: string, timeoutMs?: number, onProgress?: () => void | Promise<void>) => Promise<CoreRunnerResult>;
|
|
5
|
+
export type McpServerOptions = { client: string; runTimeoutSeconds?: number; runner?: CoreRunner; home?: string };
|
package/src/paths.ts
CHANGED
|
@@ -8,8 +8,19 @@ export function packageRoot(): string {
|
|
|
8
8
|
return path.resolve(import.meta.dir, "..");
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* DEVFLOW_HOME rule (shared with the Python readers and hooks): unset, empty or whitespace-only
|
|
13
|
+
* falls back to ~/.devflow-pi; otherwise a leading `~` is expanded and the path made absolute
|
|
14
|
+
* (path.resolve semantics, existence not required).
|
|
15
|
+
*/
|
|
16
|
+
export function normalizeDevflowHome(value: string | undefined): string {
|
|
17
|
+
if (value === undefined || value.trim() === "") return path.resolve(path.join(os.homedir(), ".devflow-pi"));
|
|
18
|
+
const expanded = value === "~" || value.startsWith("~/") ? os.homedir() + value.slice(1) : value;
|
|
19
|
+
return path.resolve(expanded);
|
|
20
|
+
}
|
|
21
|
+
|
|
11
22
|
export function devflowHome(): string {
|
|
12
|
-
return
|
|
23
|
+
return normalizeDevflowHome(process.env.DEVFLOW_HOME);
|
|
13
24
|
}
|
|
14
25
|
|
|
15
26
|
export function devflowAgentDir(): string {
|
package/src/project-context.ts
CHANGED
|
@@ -172,13 +172,35 @@ async function atomicWriteJson(target: string, value: unknown): Promise<void> {
|
|
|
172
172
|
await rename(temporary, target);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
async function ensureTestRuntimeLayout(root: string, planningRoot: string): Promise<void> {
|
|
176
|
+
const environments = path.join(planningRoot, "test-environments");
|
|
177
|
+
const runs = path.join(root, ".devflow", "runs");
|
|
178
|
+
await mkdir(environments, { recursive: true });
|
|
179
|
+
await mkdir(runs, { recursive: true });
|
|
180
|
+
const example = path.join(environments, "local.example.json");
|
|
181
|
+
if (!(await exists(example))) {
|
|
182
|
+
await atomicWriteJson(example, {
|
|
183
|
+
profile: "local",
|
|
184
|
+
base_url: "http://127.0.0.1:3000",
|
|
185
|
+
navigation_origins: ["http://127.0.0.1:3000"],
|
|
186
|
+
api_origins: ["http://127.0.0.1:3000"],
|
|
187
|
+
subresources: { policy: "same-site-plus-declared", allowed_origins: [] },
|
|
188
|
+
secret_env: {},
|
|
189
|
+
trace: "on_failure",
|
|
190
|
+
screenshots: "on_failure",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
175
195
|
export async function initializeProject(root: string): Promise<{ context: ProjectContext; created: boolean }> {
|
|
176
196
|
const canonicalRoot = await canonicalDirectory(root);
|
|
177
197
|
const { devflowRoot: devflowDir, manifestPath, planningRoot } = projectLayout(canonicalRoot);
|
|
178
198
|
await mkdir(devflowDir, { recursive: true });
|
|
179
199
|
await assertPlanningBoundary(canonicalRoot);
|
|
180
200
|
if (await exists(manifestPath)) {
|
|
181
|
-
|
|
201
|
+
const context = await loadProjectContext(canonicalRoot);
|
|
202
|
+
await ensureTestRuntimeLayout(canonicalRoot, context.planningRoot);
|
|
203
|
+
return { context, created: false };
|
|
182
204
|
}
|
|
183
205
|
const manifest: ProjectManifest = {
|
|
184
206
|
schemaVersion: PROJECT_SCHEMA_VERSION,
|
|
@@ -198,6 +220,7 @@ export async function initializeProject(root: string): Promise<{ context: Projec
|
|
|
198
220
|
manifest.layoutVersion = PROJECT_LAYOUT_VERSION;
|
|
199
221
|
await atomicWriteJson(manifestPath, manifest);
|
|
200
222
|
await mkdir(planningRoot, { recursive: true });
|
|
223
|
+
await ensureTestRuntimeLayout(canonicalRoot, planningRoot);
|
|
201
224
|
const bootstrapStore = await InitializationStore.open({ root: canonicalRoot, manifest });
|
|
202
225
|
try { await bootstrapStore.registerWorkspace(); } finally { bootstrapStore.close(); }
|
|
203
226
|
return {
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
"gates": {
|
|
14
14
|
"index_first": {
|
|
15
15
|
"policy": ".agent-gates/index-first.json"
|
|
16
|
+
},
|
|
17
|
+
"control_store": {
|
|
18
|
+
"hook": "index_gate.py",
|
|
19
|
+
"enforcement": "always",
|
|
20
|
+
"protected": ["control.db* (all access)", "$DEVFLOW_HOME/projects/** (all access)", "SQL writes to approval_proposals/approvals/authority_state", "acceptance-results*.json under .devflow/planning/test-runs (write-only; Read tools allowed)"],
|
|
21
|
+
"extra_protected_paths": []
|
|
16
22
|
}
|
|
17
23
|
}
|
|
18
24
|
}
|