From 73007ea7d2c84a58257e47f875d9de75a388a36b Mon Sep 17 00:00:00 2001 From: Jamie Sinn Date: Wed, 15 Oct 2025 10:10:53 -0400 Subject: [PATCH 1/2] Use OIDC flow for publishing CLI --- .github/actions/release/action.yml | 5 ----- .github/workflows/cli-release.yml | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml index 7a1b90fc5..0e268709f 100644 --- a/.github/actions/release/action.yml +++ b/.github/actions/release/action.yml @@ -16,9 +16,6 @@ inputs: required: false description: 'Whether to create a prerelease release' default: 'true' - node-auth-token: - required: true - description: 'The NPM token to use for authentication' runs: using: 'composite' @@ -44,6 +41,4 @@ runs: - name: Publish to NPM shell: bash - env: - NODE_AUTH_TOKEN: ${{ inputs.node-auth-token }} run: npm publish --access public diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 01d6be925..2d81b4023 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -42,7 +42,7 @@ jobs: - name: Set Secrets uses: DevCycleHQ/aws-secrets-action@main with: - secrets_map: '{"CLI_NPMJS_TOKEN": "DEVCYCLE_GITHUB_CLI_NPM_TOKEN", "MCP_KEY": "DEVCYCLE_GITHUB_cli_MCP_REGISTRY_PKEY"}' + secrets_map: '{"MCP_KEY": "DEVCYCLE_GITHUB_cli_MCP_REGISTRY_PKEY"}' aws_account_id: '134377926370' - name: Set Git author run: | @@ -97,7 +97,6 @@ jobs: release-tag: ${{ env.LATEST_TAG }} draft: ${{ inputs.draft-release }} prerelease: ${{ inputs.prerelease }} - node-auth-token: ${{ env.CLI_NPMJS_TOKEN }} # --- Official MCP Registry (registry.modelcontextprotocol.io) Publish --- - name: Install MCP Publisher (registry.modelcontextprotocol.io) From 4ca50409df6f76b2ad349c5a8900cefb5c22663f Mon Sep 17 00:00:00 2001 From: Jamie Sinn Date: Fri, 17 Oct 2025 09:47:26 -0400 Subject: [PATCH 2/2] Prettier --- eslint.config.mjs | 134 +++++++++++++-------------- mcp-worker/package.json | 56 +++++------ mcp-worker/tsconfig.json | 7 +- mcp-worker/worker-configuration.d.ts | 50 ++++++---- scripts/fetch-install-prompts.js | 14 ++- 5 files changed, 140 insertions(+), 121 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 4e7212833..5222db175 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,74 +1,74 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; -import eslintConfigPrettier from 'eslint-config-prettier'; +import js from '@eslint/js' +import tseslint from 'typescript-eslint' +import eslintConfigPrettier from 'eslint-config-prettier' export default tseslint.config( - js.configs.recommended, - ...tseslint.configs.recommended, - eslintConfigPrettier, - { - files: ['**/*.ts', '**/*.tsx'], - languageOptions: { - parser: tseslint.parser, - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - }, - plugins: { - '@typescript-eslint': tseslint.plugin, - }, - rules: { - 'no-param-reassign': 'error', - 'no-case-declarations': 'off', - '@typescript-eslint/no-this-alias': [ - 'error', - { - allowDestructuring: true, - allowedNames: ['engine'], + js.configs.recommended, + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + rules: { + 'no-param-reassign': 'error', + 'no-case-declarations': 'off', + '@typescript-eslint/no-this-alias': [ + 'error', + { + allowDestructuring: true, + allowedNames: ['engine'], + }, + ], + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-non-null-assertion': 'warn', + '@typescript-eslint/no-unused-expressions': 'error', }, - ], - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-unused-vars': 'warn', - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-non-null-assertion': 'warn', - '@typescript-eslint/no-unused-expressions': 'error', }, - }, - { - files: ['**/*.test.ts', '**/*.test.tsx'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/no-unused-expressions': 'off', + { + files: ['**/*.test.ts', '**/*.test.tsx'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + }, }, - }, - { - files: ['**/*.js', '**/*.mjs'], - languageOptions: { - globals: { - require: 'readonly', - process: 'readonly', - global: 'readonly', - __dirname: 'readonly', - __filename: 'readonly', - module: 'readonly', - exports: 'readonly', - Buffer: 'readonly', - }, + { + files: ['**/*.js', '**/*.mjs'], + languageOptions: { + globals: { + require: 'readonly', + process: 'readonly', + global: 'readonly', + __dirname: 'readonly', + __filename: 'readonly', + module: 'readonly', + exports: 'readonly', + Buffer: 'readonly', + }, + }, + rules: { + '@typescript-eslint/no-require-imports': 'off', + }, }, - rules: { - '@typescript-eslint/no-require-imports': 'off', + { + ignores: [ + 'dist/**', + 'node_modules/**', + '.yarn/**', + 'oclif.manifest.json', + 'test-utils/fixtures/**/*.js', + 'bin/**', + ], }, - }, - { - ignores: [ - 'dist/**', - 'node_modules/**', - '.yarn/**', - 'oclif.manifest.json', - 'test-utils/fixtures/**/*.js', - 'bin/**', - ], - } -); \ No newline at end of file +) diff --git a/mcp-worker/package.json b/mcp-worker/package.json index 448f0a05a..051570730 100644 --- a/mcp-worker/package.json +++ b/mcp-worker/package.json @@ -1,30 +1,30 @@ { - "name": "@devcycle/mcp-worker", - "version": "1.0.0", - "private": true, - "type": "module", - "scripts": { - "dev": "wrangler dev --env dev", - "deploy:prod": "wrangler deploy --env prod", - "deploy:dev": "wrangler deploy --env dev", - "build": "tsc", - "type-check": "tsc --noEmit", - "cf-typegen": "wrangler types", - "test": "vitest run", - "test:watch": "vitest" - }, - "dependencies": { - "@cloudflare/workers-oauth-provider": "^0.0.10", - "ably": "^1.2.48", - "agents": "^0.1.4", - "hono": "^4.9.8", - "jose": "^6.1.0", - "oauth4webapi": "^3.8.1" - }, - "devDependencies": { - "@types/node": "^24.5.2", - "vitest": "^3.2.4", - "wrangler": "^4.38.0" - }, - "packageManager": "yarn@4.9.2" + "name": "@devcycle/mcp-worker", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "wrangler dev --env dev", + "deploy:prod": "wrangler deploy --env prod", + "deploy:dev": "wrangler deploy --env dev", + "build": "tsc", + "type-check": "tsc --noEmit", + "cf-typegen": "wrangler types", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "@cloudflare/workers-oauth-provider": "^0.0.10", + "ably": "^1.2.48", + "agents": "^0.1.4", + "hono": "^4.9.8", + "jose": "^6.1.0", + "oauth4webapi": "^3.8.1" + }, + "devDependencies": { + "@types/node": "^24.5.2", + "vitest": "^3.2.4", + "wrangler": "^4.38.0" + }, + "packageManager": "yarn@4.9.2" } diff --git a/mcp-worker/tsconfig.json b/mcp-worker/tsconfig.json index dab3805c9..0f0ec87ec 100644 --- a/mcp-worker/tsconfig.json +++ b/mcp-worker/tsconfig.json @@ -4,10 +4,7 @@ "outDir": "./dist", "rootDir": "../", "noEmit": true, - "types": [ - "vitest/globals", - "node" - ], + "types": ["vitest/globals", "node"], "lib": ["ES2022"], "module": "ESNext", "target": "ES2022", @@ -33,4 +30,4 @@ "../src/**/__snapshots__/**", "src/**/*.test.ts" ] -} \ No newline at end of file +} diff --git a/mcp-worker/worker-configuration.d.ts b/mcp-worker/worker-configuration.d.ts index 7a970528b..98fed77d0 100644 --- a/mcp-worker/worker-configuration.d.ts +++ b/mcp-worker/worker-configuration.d.ts @@ -2,27 +2,43 @@ // Generated by Wrangler by running `wrangler types` (hash: 03094dcd0f8a91995e2ac7310c959ef5) // Runtime types generated with workerd@1.20250803.0 2025-06-28 nodejs_compat declare namespace Cloudflare { - interface Env { - OAUTH_KV: KVNamespace; - NODE_ENV: "production" | "development"; - API_BASE_URL: "https://api.devcycle.com"; - AUTH0_DOMAIN: "auth.devcycle.com"; - AUTH0_AUDIENCE: "https://api.devcycle.com/"; - AUTH0_SCOPE: "openid profile email offline_access"; - ENABLE_OUTPUT_SCHEMAS: "false"; - AUTH0_CLIENT_ID: string; - AUTH0_CLIENT_SECRET: string; - ABLY_API_KEY: string; - MCP_OBJECT: DurableObjectNamespace; - AI: Ai; - } + interface Env { + OAUTH_KV: KVNamespace + NODE_ENV: 'production' | 'development' + API_BASE_URL: 'https://api.devcycle.com' + AUTH0_DOMAIN: 'auth.devcycle.com' + AUTH0_AUDIENCE: 'https://api.devcycle.com/' + AUTH0_SCOPE: 'openid profile email offline_access' + ENABLE_OUTPUT_SCHEMAS: 'false' + AUTH0_CLIENT_ID: string + AUTH0_CLIENT_SECRET: string + ABLY_API_KEY: string + MCP_OBJECT: DurableObjectNamespace + AI: Ai + } } interface Env extends Cloudflare.Env {} type StringifyValues> = { - [Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string; -}; + [Binding in keyof EnvType]: EnvType[Binding] extends string + ? EnvType[Binding] + : string +} declare namespace NodeJS { - interface ProcessEnv extends StringifyValues> {} + interface ProcessEnv + extends StringifyValues< + Pick< + Cloudflare.Env, + | 'NODE_ENV' + | 'API_BASE_URL' + | 'AUTH0_DOMAIN' + | 'AUTH0_AUDIENCE' + | 'AUTH0_SCOPE' + | 'ENABLE_OUTPUT_SCHEMAS' + | 'AUTH0_CLIENT_ID' + | 'AUTH0_CLIENT_SECRET' + | 'ABLY_API_KEY' + > + > {} } // Begin runtime types diff --git a/scripts/fetch-install-prompts.js b/scripts/fetch-install-prompts.js index bb2f730a6..9d150bbf0 100644 --- a/scripts/fetch-install-prompts.js +++ b/scripts/fetch-install-prompts.js @@ -13,7 +13,8 @@ const fs = require('fs') const path = require('path') // Keep a single constant for clarity and reuse -const TREE_URL = 'https://api.github.com/repos/DevCycleHQ/AI-Prompts-And-Rules/git/trees/main?recursive=1' +const TREE_URL = + 'https://api.github.com/repos/DevCycleHQ/AI-Prompts-And-Rules/git/trees/main?recursive=1' function fetchJson(url, headers = {}) { const requestHeaders = { @@ -26,7 +27,11 @@ function fetchJson(url, headers = {}) { let data = '' res.on('data', (chunk) => (data += chunk)) res.on('end', () => { - if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { + if ( + res.statusCode && + res.statusCode >= 200 && + res.statusCode < 300 + ) { try { resolve(JSON.parse(data)) } catch (err) { @@ -80,7 +85,9 @@ async function main() { // Build safe slugs (relative paths within install-prompts without extension) const slugSet = new Set() for (const p of mdFiles) { - const raw = p.replace(/^install-prompts\//, '').replace(/\.md$/i, '') + const raw = p + .replace(/^install-prompts\//, '') + .replace(/\.md$/i, '') // extra guards on the slug if (!raw || raw.includes('..') || raw.startsWith('/')) continue const cleaned = raw @@ -133,4 +140,3 @@ main().catch((err) => { console.error(err) process.exit(1) }) -