今日已更新 88 条资讯 | 累计 40862 条内容
关于我们

标签:#dev

找到 4739 篇相关文章

AI 资讯

A Brick, a Post-it, and admin/admin — How I Learned OT Security by Building a Factory in My Bedroom

THE BRICK AND THE POST-IT My chemical plant's first vulnerability wasn't a bug, a piece of malware, or a port left open to the internet. It was a brick. In the computer room — the one with a door held open by a brick — I found a sticky note with credentials on it. They weren't even the right credentials for the system I wanted to break into. But they made me think the way whoever wrote them thinks, so I tried the most obvious pair in the world: admin / admin . And I was in. A brick propping open a door that should be locked. A sticky note guarding a password. A factory-default admin/admin. Three layers of security, three layers defeated — not by a genius hacker, but by a student on day one, carrying no tools at all. If that happens in the IT office, it's a problem. When it happens on a factory floor, where that same computer commands real pumps and valves, it's a different planet. The problem: learning OT without a factory I study computer security. Lately I've been drawn to OT — operational technology, the security of factories, power plants and industrial systems. The problem is simple: you can't learn to defend a factory from a book, and nobody will lend you theirs. Then I realized the answer was already inside the question: if you don't have one, you build one. The build: three commands and a lot of patience The lab is called GRFICSv3: an open source project that simulates an entire chemical plant — the PLC, the operator interface, the network, even the server rooms — inside Docker, on a home computer. Three commands and done: curl -O https://raw.githubusercontent.com/Fortiphyd/GRFICSv3/main/docker-compose.yml docker compose pull docker compose up -d "Three commands and done" is the story version. The real version includes my first error, arriving right on schedule at command number two: permission denied while trying to connect to the docker API at unix:///var/run/docker.sock If you hit this — and you will — here's the diagnosis: the Docker daemon is running fi

2026-09-04 原文 →
AI 资讯

I Built a Binaural Beat Generator — Then Proved It With a Live FFT Spectrum Analyzer

The "frequency healing" corner of the internet runs on faith. Apps ship MP3s labeled "40Hz gamma" and ask you to believe it. I'm a life scientist who builds web tools, and I couldn't ship that. So I built SereneSynth, a browser-based binaural beat and noise generator — and then I built a live spectrum analyzer into the page so anyone can audit the output in their own browser. This is the engineering write-up: the Web Audio graph, the FFT gotcha that almost made me publish wrong numbers, and how I cross-verified everything in Audacity. The honesty constraint first A binaural beat is not a tone in the air. Play 200 Hz into the left ear and 240 Hz into the right, and the listener's superior olivary complex computes the 40 Hz difference. A microphone — or a mono spectrum analyzer — will never show a 40 Hz peak. So the only honest thing a generator can prove is its carriers and its spectral slope. That is exactly what we measure. The synthesis graph Two sine oscillators, hard-panned with StereoPannerNode, summed into a master GainNode, tapped by an AnalyserNode before the destination — the analyzer observes exactly what the headphones receive. Settings that matter: fftSize 16384, smoothingTimeConstant 0.8. The FFT gotcha that almost made me ship garbage My first version used fftSize 1024: one fat bump near 220 Hz instead of two peaks. Bin width = 44100 / 1024 ≈ 43 Hz, and my carriers are 40 Hz apart — same bin, merged. At fftSize 16384 the bin width drops to ≈ 2.7 Hz and the carriers resolve as razor-sharp spikes at 200.0 and 240.0 Hz. Lesson: FFT size is the magnifying glass. If a "frequency proof" doesn't state its FFT size, ask. The widget renders a log axis (20–1000 Hz) because a linear axis wastes 90% of the canvas, and peak detection labels the top bins in the 100–500 Hz range live. Bit-exact, downloadable verification The page also renders 10-second stereo WAVs via OfflineAudioContext (16-bit PCM, 44.1 kHz): same graph, offline render, RIFF encode. No lossy compre

2026-09-04 原文 →
AI 资讯

# How enabling cross-origin isolation silently broke our multi-threaded WASM image compressor

A production postmortem. We shipped browser-side image compression (Rust → WASM + WebGPU), turned on cross-origin isolation for speed, and watched every format crash with compression worker crashed . Here's the root cause and the fix. The setup We built an image compressor that runs 100% in the browser — Rust compiled to WASM for the codec work, WebGPU for the heavy ML passes (background removal, denoise, watermark). No upload, so users' pixels never leave the device. Privacy is the whole selling point. For the multi-threaded code paths we rely on shared memory + atomics , which in the browser requires crossOriginIsolated . So we served the document with: Cross-Origin-Embedder-Policy: require-corp Cross-Origin-Opener-Policy: same-origin That gives us crossOriginIsolated === true , unlocks SharedArrayBuffer , and lets the *‑threaded WASM builds actually spawn workers. The build uses a nightly toolchain ( nightly-2025-06-01 + -Z build-std ) with: RUSTFLAGS = "--cfg=... +atomics,+bulk-memory --shared-memory --import-memory" and a custom rayon handle pool ( with_turbo_pool ) instead of build_global , so we control worker lifecycle and can abort/self-heal. The incident After flipping COEP to require-corp in production, every format started crashing with the same message: compression worker crashed Not one codec — JPG, PNG, WebP, AVIF, all of them. It was a P0: the core feature was dead for every user. What made it nasty: it only reproduced under real cross-origin isolation . Local dev without COEP was fine. Staging without the header was fine. So the bug hid until it hit production traffic. Root cause The *‑threaded WASM packages spin up nested rayon workers to parallelize the codec. Under COI + COEP require-corp , those nested workers get blocked by Cross-Origin-Resource-Policy / COEP — the spawned worker script is treated as a cross-origin response without the right CORP header, so the browser refuses it. No worker → the rayon pool never initializes → the compression c

2026-09-04 原文 →
AI 资讯

Re-Organized configuration in Rails

A while back I wrote about organizing configuration in Rails . The idea was simple: drop YAML files into config/configurations/ and get namespaced constants like Config::Bot.api_key instead of the clunky Rails.application.config.bot.api_key . It worked well. But every YAML file needed manual wiring: <%= ENV.fetch("BOT_API_KEY", Rails.application.credentials.dig(:bot, :api_key)) %> . For every key. Across every file. Ugh! So I rebuilt it. Same clean Config::Namespace.key API, but now it chains through all three sources automatically. Before (old module’s YAML): # config/bot.yml shared : api_key : <%= ENV.fetch("BOT_API_KEY", Rails.application.credentials.dig(:bot, :api_key)) %> user_agent : " MyAwesomeBot/1.0" timeout : 10 After (new module’s YAML): # config/bot.yml shared : # Config::Bot.api_key is still available and will check environment variables and then check credentials user_agent : " MyAwesomeBot/1.0" timeout : 10 One API. Three sources. No more guessing where a value lives. You can find the full code on GitHub . What follows are the parts I find most interesting. Lazy namespaces with const_missing The old version scanned a directory at boot and called const_set for every YAML file. That works, but it means every namespace is loaded whether you use it or not. This version uses const_missing instead. Reference Config::Bot for the first time and a Namespace object is created lazily: def self . const_missing ( name ) MUTEX . synchronize do @namespaces ||= {} @namespaces [ name ] ||= Namespace . new ( name ) end end The Mutex isn’t there by accident. In threaded environments (Puma, Solid Queue), two threads could hit const_missing simultaneously. Mutex makes sure only one namespace object gets created. The three source chain Each Namespace uses method_missing to resolve a key: def method_missing ( method , ... ) key = method . to_s . delete_suffix ( "!" ) bang = method . to_s . end_with? ( "!" ) environment_key = " #{ @prefix } _ #{ key . upcase } " return @envi

2026-09-04 原文 →
AI 资讯

Does That "Free Online PDF" Tool Upload Your File? How to Tell.

Most free online PDF tools work by uploading your document to a server, processing it there, and sending it back. For a lot of files that's fine. For a signed contract, a payslip, a medical form, or a scanned ID, it's the entire privacy problem: your document now lives on someone else's machine, subject to their logging, retention, and breach exposure. It doesn't have to work that way. A modern browser can split, merge, compress, sign, and even OCR a PDF without the file ever leaving your device — using libraries like pdf-lib , pdf.js , jsPDF and SheetJS that run entirely in JavaScript. How to tell an uploader from a client-side tool You don't have to trust a marketing claim. Two checks settle it: Watch the network. Open your browser's DevTools → Network tab, then run the tool on a file. If you see your file leave in a POST/PUT request, it uploaded. A client-side tool shows no upload of the document itself. Pull the plug. Load the page, then turn off Wi-Fi and try the tool again. A client-side tool keeps working offline. An uploader breaks the moment the network is gone. The honest tools pass both tests. If a site can't work offline, your file is going somewhere. The trade-offs, stated honestly Client-side processing isn't a free lunch, and any tool that pretends it is should make you suspicious: Memory. Very large PDFs are held in browser memory, so there's a ceiling a server wouldn't have. Speed. OCR in WebAssembly is slower than a server GPU. It's private, not fast. Fidelity. Converting PDF → Word transfers the text , not the layout — the same is true of every converter, but a client-side one can't hide it behind a server. Compression limits. A PDF shrinks by downsampling embedded images or rasterizing pages; a small or text-only PDF may not shrink at all, and rasterizing removes selectable text. We built 24 client-side PDF tools on exactly this principle and wrote down where each limit is, rather than papering over them. If you're evaluating any online PDF tool

2026-09-04 原文 →
AI 资讯

AI Engineering Is Easy. Changing How We Work Is Hard

AI engineering sounds fancy. New terms are everywhere: agentic development, AI-native engineering, spec-driven development, and now AI harness engineering. Underneath all the terminology, though, something genuinely useful is happening. AI can now help with requirements, challenge a PRD, explore UX ideas, reason about architecture, create implementation plans, write code and validate the result. The obvious question is what AI can do. The more interesting question is whether the way we build software is ready for it. The workflow is changing A workflow we've been exploring breaks development into five stages: requirements, refinement, planning, build and validation . The stages themselves aren't new, but AI can now participate in each one. It can take existing product inputs, help clarify the problem, question assumptions, identify gaps in a PRD and then turn a well-defined requirement into a plan and eventually implementation tasks. This puts more emphasis on the quality of the requirements. A human involved in a project might understand what “improve the experience” means because they've had several conversations about it. An agent doesn't have that shared history. It needs the problem, scope, constraints, edge cases and expected outcome to be explicit. That doesn't mean writing enormous specifications; it means using AI to help make the requirements precise before we start building. AI can actually be a useful, slightly annoying reviewer here, asking what happens when something fails, whether a requirement is testable, whether two parts of the document contradict each other and what we haven't considered yet. It can also help compare different versions of a PRD or have one model review another's output, making gaps easier to spot. The important part is that AI is helping us uncover ambiguity, not making the decisions for us. Maybe coding isn't the bottleneck This becomes more interesting when we look at where teams actually spend their time. Complex work can invo

2026-09-04 原文 →
AI 资讯

What I Learned Building a Diabetes Management Website

A few months ago I started building [reversemydiabetes.co]a small health platform focused on helping people manage type 2 diabetes through diet and lifestyle changes. I'm not a doctor — I'm a builder — but the project turned into a genuinely interesting technical challenge, and I wanted to share some of what I learned along the way. Why I started this Type 2 diabetes affects a huge number of people, and a lot of the advice online is either paywalled, badly organized, or written in a way that's hard to act on. I wanted to build something simple: a site that gives people practical, easy-to-follow guidance on blood sugar management, diet planning, and day-to-day habits — without needing a login, a subscription, or a medical degree to understand it. The technical side A few decisions shaped how the site turned out: Content structure over cleverness. Early on I over-engineered the information architecture — trying to build dynamic filtering for every possible diet preference. I scrapped most of it. What actually mattered was clear, well-organized static content: a diabetes diet plan page, a blood sugar basics guide, and a meal-planning section. Simple beats clever when the audience isn't tech-savvy. SEO became a first-class concern, not an afterthought. Health content lives or dies on whether people can actually find it. I spent real time on keyword research — things like "diabetes diet plan," "blood sugar levels," and "type 2 diabetes management" — and restructured pages around what people were actually searching for, rather than what sounded good internally. Performance mattered more than I expected. A lot of the target audience is older, on slower connections, or on older devices. I ended up stripping out a bunch of client-side JavaScript I didn't need and leaned on plain HTML/CSS wherever possible. Lighthouse scores went from "fine" to "actually fast," and bounce rate dropped noticeably. Trust signals are a real UX problem for health content. Unlike a SaaS landing pa

2026-09-04 原文 →
AI 资讯

Three ways your dashboard can be correct and still lie

Our dataset said the average loan was 2.3 million kroner. The number that actually mattered was 255,000. Both were correct. Only one of them was true. This is a writeup of three ways a dashboard can be arithmetically perfect and still lie, using real figures from an analysis of 1,000 Norwegian debt consolidation applications. If you build reporting for anyone, you have probably shipped at least one of these. 1. Summing a field that contains two different things A debt consolidation loan pays off your expensive credit card debt. It also, if you own property, rolls your existing mortgage into the same new loan. Same column in the database. Same loan_amount . Utterly different meaning. SELECT AVG ( loan_amount ) FROM applications ; -- 2,300,000 That query is right and the answer is useless. Of that 2.3 million, roughly 1.9 million is an existing mortgage being moved from one lender to another. The expensive debt, the part the customer actually has a problem with, averages 255,000 . So the headline figure overstates the thing you care about by a factor of nine. Nothing in the schema warns you. loan_amount is a number, AVG is a function, the result renders fine. The bug is that one column is holding two concepts and only a human who understands the domain will notice. -- what you actually wanted SELECT AVG ( unsecured_debt ) FROM applications ; -- 255,000 If a column can mean two things depending on another column, split it. Every time. 2. Reporting the mean when the distribution has a tail Income in this dataset runs from ordinary salaries up to about five million kroner. A handful of very high earners drag the mean upward: Mean income: ~635,000 Median income: 647,000 for homeowners, 550,000 for renters Look at what happens there. The mean sits between the two medians and describes neither group. Someone reading only the mean concludes the typical applicant earns 635,000. Nobody earns 635,000. It is an artefact. df . groupby ( ' housing ' )[ ' income ' ]. agg ([ ' mean

2026-09-04 原文 →
AI 资讯

Choosing the Right Real-Time Networking Stack for Unity in 2026

When building an online game in Unity, the question is often framed as: Should I use Photon, Netcode for GameObjects, FishNet, or Mirror? That question is too small. In 2026, there is still no single networking product that is optimal for every Unity game. The real decision is a stack : transport, netcode, authority model, session management, server hosting, and backend services. For a GameObject-based action game that needs client prediction, Photon Fusion 2.1 is a strong first PoC baseline . If your priorities are Unity Gaming Services, DOTS/ECS, self-hosting, source access, or deterministic simulation, the starting point changes. This article explains how to make that decision in production terms: latency, cheating, reconnection, hosting, bandwidth, operations, and total cost. This article uses official documentation checked on August 31, 2026 as its factual baseline. SDK versions, pricing, licensing, and service availability can change, so re-check them before committing a production project. What I mean by a real-time multiplayer game The target is roughly this class of game: 2–32 players in the same session continuously synchronized players, enemies, projectiles, or interactable objects input latency that directly affects game feel reconnects, host loss, and late joining that must be handled co-op action, FPS/TPS, racing, or competitive action If you only need turn-based play, leaderboards, chat, friends, or asynchronous PvP, you may not need a sophisticated state-synchronization netcode at all. A backend such as Nakama, PlayFab, or Unity Gaming Services may be the more important part of the architecture. Do not treat “networking” as one product A production multiplayer stack has at least five layers. Layer Responsibility Examples Transport Packet delivery, reliability, connection path, secure channel integration Unity Transport, Photon transport, UDP/WebSocket-based transports Netcode Replication, RPCs, input, prediction, interpolation, rollback Fusion, NGO,

2026-09-04 原文 →
开发者

How to Find What Is Filling Up Disk Space on a Linux Server

Disk full alerts at 2am? Learn the exact commands to find what's eating your Linux server's disk space and fix it fast. You get the alert: disk usage at 94%. Your app starts throwing errors, logs stop writing, and databases refuse to accept new rows. Finding the culprit fast matters — but on a server with millions of files, knowing where to look is half the battle. Here's a systematic approach to track down disk hogs in minutes, not hours. Start With the Big Picture: df Before you dig into directories, confirm which filesystem is actually full. Run: df -h — shows all mounted filesystems with human-readable sizes df -h / — focus on the root filesystem df -i — check inode usage (a filesystem can be 'full' even with free space if inodes are exhausted) Pay attention to the 'Use%' column. If you see 100% on /var or /home but not /, that tells you exactly which mount point to investigate. Inode exhaustion — df -i showing 100% — is easy to miss and causes the same symptoms as a full disk, so always check both. Drill Down With du Once you know which mount point is full, use du to find the largest directories. Start from the top of that mount point and work down: du -sh /* 2>/dev/null — sizes of every top-level directory, errors suppressed du -sh /var/* 2>/dev/null — drill into /var if that's the culprit du -ah /var | sort -rh | head -20 — list the 20 largest files and folders inside /var The pattern is always the same: run du -sh on the suspicious directory, find the largest subdirectory, repeat one level deeper. You'll usually hit the real culprit within three or four iterations. Common offenders are /var/log (runaway logs), /var/lib/docker (unused images and volumes), and /tmp (applications that don't clean up after themselves). Find Large Files Directly With find Sometimes a single enormous file is the problem — a core dump, a forgotten database export, or a log that rotated incorrectly. Use find to surface files above a size threshold: find / -xdev -size +500M -ls 2>/de

2026-09-04 原文 →
AI 资讯

uilding a Preview-First Background Noise Remover for Audio and Video

A background noise removal workflow is easy to describe and much harder to make trustworthy. The superficial version is: upload a file, run processing, download the result. The harder version is product design: what does a person need to know before committing to a result, paying for an export, or spending a limited processing allowance? A preview-first workflow answers that question by making uncertainty a first-class part of the system. Instead of asking people to trust a long-running operation, it gives them a bounded way to hear a representative outcome before they choose what happens next. This article lays out the design principles behind that approach for stored audio or video uploads. It is not a call-time or capture-time filter. The central workflow is: upload → compatibility check → preview → same segment before/after → export choice That sequence looks simple, but each boundary carries product and engineering consequences. Start with a decision, not a processing feature A preview should help a user make one specific decision: “Is this result useful enough for me to continue?” That framing prevents a common mistake: treating a preview as a small free version of the full product. A useful preview is not merely a shorter job. It needs to be comparable, understandable, and tied to the next action. For background noise removal, the most defensible comparison is a matched segment: The source and processed audio use the same time range. Playback controls make the comparison obvious. The user can choose whether to continue only after hearing that bounded example. If the before and after samples use different moments, the product is asking the user to infer too much. A quieter section in one clip can appear better even when the processing change was minor. Matching the segment removes that ambiguity and keeps the decision grounded in what the user actually heard. Put compatibility before expectation Compatibility belongs near the beginning of the workflow, before

2026-09-04 原文 →
AI 资讯

Twenty Years of jQuery: How a Little Library Rewired Web Development

jQuery, created by John Resig and released in 2006, is a JavaScript library that simplifies HTML manipulation, event handling, animation, and Ajax. It enabled easier web development by providing an accessible API across browsers. While its use has declined with the rise of modern frameworks, jQuery remains prevalent on a significant portion of websites today. By Daniel Curtis

2026-09-04 原文 →
AI 资讯

Muse Spark 1.3 - A Review

In this post I'll talk about my brief experience with muse , Meta's LLM harness for developers, as well as Muse Spark 1.3, their latest frontier-level model. The Bad I'll start with the bad, just because I like to end with the positive :) Skill Usage It's not that good following skills. If the skill has disable-model-invocation , sometimes it refuses to launch it, even if you manually call it. I think it happens when you call the skill mid-sentence, but it's not consistent. It's also not as good as other models at following skill instructions. It seems to get confused more often. For example, I have one skill that will address an issue from GitHub to PR. In Claude (Opus 5) and Cursor (Grok 4.6) it works perfectly. The first step is grilling the issue, after that's finished, the next step is autonomous, plan, implement with TDD, review and open PR. With Muse Spark 1.3, sometimes the skill will not continue and I have to nudge it for the next step, just saying something like "continue" is enough, but surely is annoying. Formatting The output is not great. Sometimes it will show me raw markdown, sometimes not. It's not consistent. Sandbox Having a sandbox is good, but in this case, it's a bit too restrictive. For example, I'm working with a Firebase project and I want to use the emulators. Well, too bad. The sandbox doesn't allow you to run files outside your workspace or use external ports. That would be great if I could add exceptions or some kind of configuration, but you can't. You are basically forced into --yolo mode if you don't want to be prompted on repeat for the same things over and over. What's sad is that even if you want to give them access, the models will just get stuck asking for permissions for the same thing over and over again and eventually they will just be stuck doing nothing. The Good Not everything is bad, of course. With a bit of effort I think it's actually quite usable. Price The main reason I decided to try the model. The subscription plan

2026-09-04 原文 →
AI 资讯

Protótipos: como a herança realmente funciona no JavaScript

Introdução Muitas linguagens como C#, Java, entre outras são descritas como orientadas a objeto, possibilitando o paradigma Programação Orientada a Objeto (POO). No entanto, quando falamos de JS, sabemos que por mais que existam objetos, ela é dita como uma linguagem orientada a protótipos, mas o que de fato isso significa, qual problema isso resolve e como muda a maneira como programamos? O problema Tanto a orientação a objeto quanto a orientação a protótipo lidam, entre outras coisas, com a questão de como a herança vai funcionar em determinada linguagem e é justamente nesse ponto que as duas abordagens mais se diferem. Em linguagens orientadas a objetos as classes de fato existem, contendo propriedades, métodos e servem como molde para a criação de objetos. Com isso, todo objeto criado a partir de uma classe herda suas propriedades e métodos ficando acessíveis para uso. Como não existem Classes de fato em JavaScript, a herança ocorre de maneira diferente, de objeto para objeto, ligados através da propriedade [[Prototype]] que possui uma referência ao seu protótipo, fazendo com que determinado objeto herde de seu protótipo propriedades e métodos que nunca foram definidos nele. Exemplo com array Quando criamos um array, seja de forma literal com [], ou de forma explícita com new Array(), o resultado final é o mesmo: um array cujo [[Prototype]] aponta para o Array.prototype. Essa propriedade .prototype possui um objeto contendo todas as propriedades e métodos que o [[Prototype]] referencia, possibilitando que todos os arrays possam usar métodos como push, pop, map, filter… Com isso, se irmos além e conferirmos o [[Prototype]] do Array.prototype vamos perceber que ele aponta para o Object.prototype que contém propriedades e métodos também disponível em todo essa cadeia que chamamos de prototype chain . Por fim, se tentarmos visualizar o protótipo do Object.prototype veremos que é null, pois ele representa o último elo dessa cadeia. Teste o código abaixo para ver na p

2026-09-04 原文 →
AI 资讯

What I learned building an enemy state machine in Godot 4

I wrote "just use a match statement, it's fine" three times before I stopped saying it. It is fine, right up until an enemy needs a fourth state and two of the transitions start depending on each other. Here is what actually cost time building enemy AI for a wave-based game, in the order it bit me. Lesson 1: the match statement is fine until state 4 A two-state enemy — chase, attack — is genuinely not worth a framework: func _physics_process ( delta : float ) -> void : match state : State . CHASE : velocity = ( player . global_position - global_position ) . normalized () * speed if global_position . distance_to ( player . global_position ) < attack_range : state = State . ATTACK State . ATTACK : attack_timer -= delta if attack_timer <= 0.0 : do_attack () state = State . CHASE The moment a third and fourth state show up — hurt, dead, stagger, windup — the match block stops being one enemy's logic and becomes a grid of every state times every other state it might transition to. That grid is where the bugs live, not in any single state. Lesson 2: the bug is never inside a state, it's in the transition Every state-machine bug I actually spent time on was the same shape: state A left some flag or timer set that state C didn't know to check. An enemy stuck mid-attack-animation forever, still receiving hits, was not a bug in the attack state — it was the hurt state interrupting attack without cleaning up attack_timer or resetting the animation. The fix that made these bugs findable is giving every state an explicit enter and exit , and never mutating another state's data directly: func change_state ( new_state : State ) -> void : if new_state == state : return _exit_state ( state ) state = new_state _enter_state ( new_state ) func _exit_state ( s : State ) -> void : match s : State . ATTACK : attack_timer = 0.0 sprite . stop () func _enter_state ( s : State ) -> void : match s : State . HURT : velocity = Vector2 . ZERO hurt_timer = HURT_DURATION sprite . play ( "hurt" ) On

2026-09-04 原文 →
AI 资讯

Stop Wasting API Tokens: How to Bridge ChatGPT Web to Your IDE Using MCP

If you are an active user of AI-powered IDEs like Cursor, VS Code with Copilot, or Windsurf, you already know the sinking feeling of seeing this notification: "You have used 100% of your fast premium requests for this billing cycle." Suddenly, your snappy, context-aware coding assistant slows to a crawl or starts racking up expensive pay-as-you-go API bills. At the same time, you are likely paying $20/month for a ChatGPT Plus or Team subscription that sits underutilized in a browser tab. You use it for general questions, but it lacks direct, real-time access to your local codebase, forcing you to engage in a tedious dance of copying and pasting code blocks. What if you could bridge this gap? What if you could let ChatGPT Web do the heavy reasoning and planning using your local context, while saving your premium IDE tokens for fast auto-completions ? In this article, we’ll explore a highly novel, intermediate-level setup that does exactly this. By leveraging the Model Context Protocol (MCP) , Node.js , and secure Cloudflare Tunnels , you can route heavy code-planning tasks directly to your web-based ChatGPT Plus subscription safely and completely free of extra token charges. The Philosophy: Let ChatGPT Think, Let Your IDE Work When building complex software with AI, your workflow generally splits into two distinct phases: Reasoning & Planning (High Token Usage): This is where you ask the AI to read 10 source files, understand the architecture, design a new feature, or find a subtle bug. This consumes massive amounts of context window tokens. Execution & Autocomplete (Low Latency): This is where the AI writes single lines of code, refactors a function, or autocompletes your imports. This requires fast, inline API queries. Paying premium API rates (per token) for Phase 1 is incredibly expensive. This is where this open-source MCP bridge project shines. It exposes a read-only view of your local project as an MCP server. Your web-based ChatGPT (via custom GPTs or MCP int

2026-09-04 原文 →