@olegkuibar/plunk 0.5.1 → 0.6.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.
package/README.md CHANGED
@@ -4,9 +4,12 @@
4
4
 
5
5
  <p align="center">
6
6
  <a href="https://plunk.olegkuibar.dev/"><img src="https://img.shields.io/badge/Try_in_Browser-Playground-58a6ff?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0tMiAxNWwtNS01IDEuNDEtMS40MUwxMCAxNC4xN2w3LjU5LTcuNTlMMTkgOGwtOSA5eiIvPjwvc3ZnPg==" alt="Playground" /></a>
7
+ <br>
7
8
  <a href="https://www.npmjs.com/package/@olegkuibar/plunk"><img src="https://img.shields.io/npm/v/@olegkuibar/plunk?color=blue" alt="npm version" /></a>
8
9
  <a href="https://www.npmjs.com/package/@olegkuibar/plunk"><img src="https://img.shields.io/npm/dm/@olegkuibar/plunk" alt="npm downloads" /></a>
9
- <a href="https://www.npmjs.com/package/@olegkuibar/plunk"><img src="https://img.shields.io/npm/unpacked-size/%40olegkuibar%2Fplunk" alt="npm package size" /></a>
10
+ <a href="https://www.npmjs.com/package/@olegkuibar/plunk"><img src="https://img.shields.io/npm/unpacked-size/%40olegkuibar%2Fplunk" alt="unpacked size" /></a>
11
+ <a href="https://bundlephobia.com/package/@olegkuibar/plunk"><img src="https://badgen.net/bundlephobia/minzip/%40olegkuibar%2Fplunk" alt="minzipped size" /></a>
12
+ <br>
10
13
  <a href="https://github.com/oleg-kuibar/plunk/actions/workflows/ci.yml"><img src="https://github.com/oleg-kuibar/plunk/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
11
14
  <a href="https://github.com/oleg-kuibar/plunk/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="license" /></a>
12
15
  <img src="https://img.shields.io/badge/node-%3E%3D22.12-brightgreen" alt="node version" />
@@ -72,16 +75,16 @@ plunk push --watch --build "pnpm build"
72
75
 
73
76
  ## At a glance
74
77
 
75
- | | npm link | yalc | plunk |
76
- |---|---|---|---|
77
- | Mechanism | Symlinks | Copy + package.json rewrite | Copy only |
78
- | Module resolution | Broken (dual instances) | Works | Works |
79
- | Git contamination | None | package.json + .yalc/ | None |
80
- | Bundler HMR | Often broken | Varies | Works |
81
- | pnpm support | Fragile | Limited | Full |
82
- | Watch mode | None | External | Built-in |
83
- | Survives `npm install` | No | No | `plunk restore` |
84
- | Incremental sync | N/A | Full copy each time | mtime + xxhash diff |
78
+ | | npm link | yalc | plunk |
79
+ | ---------------------- | ----------------------- | --------------------------- | ------------------- |
80
+ | Mechanism | Symlinks | Copy + package.json rewrite | Copy only |
81
+ | Module resolution | Broken (dual instances) | Works | Works |
82
+ | Git contamination | None | package.json + .yalc/ | None |
83
+ | Bundler HMR | Often broken | Varies | Works |
84
+ | pnpm support | Fragile | Limited | Full |
85
+ | Watch mode | None | External | Built-in |
86
+ | Survives `npm install` | No | No | `plunk restore` |
87
+ | Incremental sync | N/A | Full copy each time | mtime + xxhash diff |
85
88
 
86
89
  See [detailed comparison](docs/comparison.md) for a deeper breakdown.
87
90
 
@@ -100,23 +103,23 @@ Experience plunk directly in your browser with our interactive playground:
100
103
 
101
104
  ## Documentation
102
105
 
103
- | | |
104
- | --- | --- |
105
- | [Getting Started](docs/getting-started.md) | Install, first publish/add cycle, watch mode |
106
- | [Commands](docs/commands.md) | Every command, every flag |
107
- | [How It Works](docs/how-it-works.md) | Store format, injection, CoW copies |
108
- | [Bundler Guide](docs/bundlers.md) | Vite, Webpack, esbuild, Turbopack setup |
109
- | [Comparison](docs/comparison.md) | npm link vs yalc vs plunk |
110
- | [CI/CD](docs/ci-cd.md) | Using plunk in CI pipelines |
111
- | [Monorepo Guide](docs/monorepo.md) | Workspace setup and recursive publish |
112
- | [Troubleshooting](docs/troubleshooting.md) | Common issues and fixes |
113
- | [FAQ](docs/faq.md) | Frequently asked questions |
114
- | [Migrating from yalc](docs/migrating-from-yalc.md) | Step-by-step migration guide |
115
- | [Architecture](docs/architecture.md) | Internals for contributors |
116
- | [API Reference](docs/api.md) | Programmatic API (TypeScript) |
117
- | [Examples](examples/) | Try it yourself with real packages |
118
- | [Playground](playground/) | Interactive browser-based playground |
119
- | [Contributing](CONTRIBUTING.md) | Dev setup and guidelines |
106
+ | | |
107
+ | -------------------------------------------------- | -------------------------------------------- |
108
+ | [Getting Started](docs/getting-started.md) | Install, first publish/add cycle, watch mode |
109
+ | [Commands](docs/commands.md) | Every command, every flag |
110
+ | [How It Works](docs/how-it-works.md) | Store format, injection, CoW copies |
111
+ | [Bundler Guide](docs/bundlers.md) | Vite, Webpack, esbuild, Turbopack setup |
112
+ | [Comparison](docs/comparison.md) | npm link vs yalc vs plunk |
113
+ | [CI/CD](docs/ci-cd.md) | Using plunk in CI pipelines |
114
+ | [Monorepo Guide](docs/monorepo.md) | Workspace setup and recursive publish |
115
+ | [Troubleshooting](docs/troubleshooting.md) | Common issues and fixes |
116
+ | [FAQ](docs/faq.md) | Frequently asked questions |
117
+ | [Migrating from yalc](docs/migrating-from-yalc.md) | Step-by-step migration guide |
118
+ | [Architecture](docs/architecture.md) | Internals for contributors |
119
+ | [API Reference](docs/api.md) | Programmatic API (TypeScript) |
120
+ | [Examples](examples/) | Try it yourself with real packages |
121
+ | [Playground](playground/) | Interactive browser-based playground |
122
+ | [Contributing](CONTRIBUTING.md) | Dev setup and guidelines |
120
123
 
121
124
  ## License
122
125
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {a as a$6}from'./chunk-HHV6VEYA.mjs';import {b as b$5,a as a$5,e}from'./chunk-IZRTKGYZ.mjs';import {c as c$1}from'./chunk-4ZGIZZSF.mjs';import {a as a$4,b as b$4,c as c$2,d as d$2}from'./chunk-AC5FETT7.mjs';import {f,d,h}from'./chunk-LLVBXPQN.mjs';import {a as a$3}from'./chunk-PVMVWPLG.mjs';import {a as a$2}from'./chunk-HPF6K6WO.mjs';import {b as b$3,c}from'./chunk-EMRPZYLU.mjs';import {a as a$1}from'./chunk-MBKCCWSD.mjs';import {i}from'./chunk-22YCXJTS.mjs';import {b as b$2,a as a$7}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import {k}from'./chunk-TMH7HIJ2.mjs';import {c as c$3,d as d$1}from'./chunk-R3RSOZXN.mjs';import {b as b$1}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {readFile}from'fs/promises';import {spawn}from'child_process';import {platform}from'os';import {join,resolve,basename}from'path';globalThis.require=createRequire(import.meta.url);
2
+ import {createRequire}from'node:module';import {a as a$6}from'./chunk-HHV6VEYA.mjs';import {b as b$5,a as a$5,e}from'./chunk-SMIGYQFG.mjs';import {c as c$1}from'./chunk-4ZGIZZSF.mjs';import {a as a$4,b as b$4,c as c$2,d as d$2}from'./chunk-AC5FETT7.mjs';import {f,d,h}from'./chunk-LLVBXPQN.mjs';import {a as a$3}from'./chunk-PVMVWPLG.mjs';import {a as a$2}from'./chunk-HPF6K6WO.mjs';import {b as b$3,c}from'./chunk-EMRPZYLU.mjs';import {a as a$1}from'./chunk-MBKCCWSD.mjs';import {i}from'./chunk-22YCXJTS.mjs';import {b as b$2,a as a$7}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import {k}from'./chunk-TMH7HIJ2.mjs';import {c as c$3,d as d$1}from'./chunk-R3RSOZXN.mjs';import {b as b$1}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {readFile}from'fs/promises';import {spawn}from'child_process';import {platform}from'os';import {join,resolve,basename}from'path';globalThis.require=createRequire(import.meta.url);
3
3
  var Pn={meta:{name:"add",description:"Link a package from the plunk store into this project"},args:{package:{type:"positional",description:"Package name to add",required:true},from:{type:"string",description:"Path to package source (will publish first)"},yes:{type:"boolean",alias:"y",description:"Auto-accept prompts (install missing deps, etc.)",default:false}},async run({args:t}){b$2();let s=new a$1,n=resolve("."),{name:e$1,version:c$4}=nn(t.package);if((!e$1||e$1==="@"||e$1.startsWith("@")&&!e$1.includes("/"))&&(a$2(`Invalid package name "${t.package}". Use format: package-name or @scope/package-name`),process.exit(1)),t.from){let o=resolve(t.from);b$1.info(`Publishing from ${o}...`),await a$3(o);}let a=c$4?await b$3(e$1,c$4):await c(e$1);if(!a){let o=c$4?`@${c$4} `:"";a$2(`Package "${e$1}"${o?" "+o:""} not found in store. Run 'plunk publish' in the package directory first, or use --from <path>.`),process.exit(1);}let p=!await k(i(n)),r=await a$4(n);if(p&&(await c$1(n,r),b$1.success("Auto-initialized plunk (consumer mode)")),b$1.info(`Detected package manager: ${r}`),r==="yarn"){let o=await b$4(n);(o==="pnp"||o===null&&await c$2(n))&&(b$1.error(`Yarn PnP mode is not compatible with plunk.
4
4
 
5
5
  plunk works by copying files into node_modules/, but PnP eliminates
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {createRequire}from'node:module';import {e,b as b$1}from'./chunk-AC5FETT7.mjs';import {j,k as k$1}from'./chunk-22YCXJTS.mjs';import {c,k,h,i,f,m}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {mkdir,writeFile,rm,symlink,chmod,readdir,stat,realpath,readFile}from'fs/promises';import {join,resolve,sep,relative}from'path';import {platform}from'os';globalThis.require=createRequire(import.meta.url);
3
+ function J(e){return e.bin?typeof e.bin=="string"?{[e.name.startsWith("@")?e.name.split("/")[1]:e.name]:e.bin}:e.bin:{}}a(J,"resolveBinEntries");async function L(e,t,i){let r=J(i);if(Object.keys(r).length===0)return 0;let n=join(e,"node_modules",".bin");await mkdir(n,{recursive:true});let c$1=platform()==="win32",a=0;for(let[o,g]of Object.entries(r)){let p=join(e,"node_modules",t),l=join(p,g),B=resolve(l);if(!B.startsWith(resolve(p)+sep)&&B!==resolve(p)){b.warn(`bin "${o}" points outside package directory, skipping`);continue}let v=relative(n,l).replace(/\\/g,"/");if(c$1){let w=join(n,`${o}.cmd`),j=`@ECHO off\r
4
+ GOTO start\r
5
+ :find_dp0\r
6
+ SET dp0=%~dp0\r
7
+ EXIT /b\r
8
+ :start\r
9
+ CALL :find_dp0\r
10
+ "%dp0%\\${v.replace(/\//g,"\\")}" %*\r
11
+ `;await writeFile(w,j);let G=join(n,o),X=`#!/bin/sh
12
+ exec node "${v}" "$@"
13
+ `;await writeFile(G,X);}else {let w=join(n,o);try{await rm(w,{force:!0});}catch{}try{await symlink(v,w),await chmod(l,493);}catch(b){if(c(b)&&(b.code==="EPERM"||b.code==="EACCES")){d(`[bin-linker] Symlink failed (${b.code}), using shell wrapper for ${o}`);let j=`#!/bin/sh
14
+ exec node "${v}" "$@"
15
+ `;await writeFile(w,j),await chmod(w,493);}else throw b}}a++;}return a}a(L,"createBinLinks");async function W(e,t){let i=J(t),r=join(e,"node_modules",".bin"),n=platform()==="win32";for(let c of Object.keys(i))try{await rm(join(r,c),{force:!0}),n&&await rm(join(r,`${c}.cmd`),{force:!0});}catch{}}a(W,"removeBinLinks");var U={next:[".next/cache"],webpack:["node_modules/.cache"]},A=new Map;async function F(e$1){let t=A.get(e$1);t||(t=await e(e$1),A.set(e$1,t));for(let i of t){if(!i.type)continue;let r=U[i.type];if(r)for(let n of r){let c=join(e$1,n);if(await k(c))try{await h(c),d(`[inject] Invalidated ${i.type} cache: ${n}`);}catch{d(`[inject] Could not clear ${i.type} cache: ${n} (locked?)`);}}}}a(F,"invalidateBundlerCache");async function Ee(e,t,i$1,r={}){let n=await $(t,e.name,i$1,e.version);d(`[inject] ${e.name}@${e.version} \u2192 ${n}`),await i(n);let{copied:c,removed:a,skipped:o}=await f(e.packageDir,n,{force:r.force});d(`[inject] ${c} copied, ${a} removed, ${o} skipped`),(c>0||a>0)&&await F(t);let g=await O(e.packageDir),p=g?await L(t,e.name,g):0;return p>0&&d(`[inject] Created ${p} bin link(s)`),{copied:c,removed:a,skipped:o,binLinks:p}}a(Ee,"inject");async function Ce(e,t,i){let r=await $(e,t,i);if(!await k(r))return false;let n=j(e,t);return await h(n),await m(r,n),true}a(Ce,"backupExisting");async function Oe(e,t,i){let r=j(e,t);if(!await k(r))return false;let n=await $(e,t,i);return await h(n),await m(r,n),await h(r),true}a(Oe,"restoreBackup");async function Be(e,t,i){let r=await $(e,t,i),n=await O(r);n&&await W(e,n),await h(r);}a(Be,"removeInjected");async function Ne(e,t){let i=await O(e.packageDir);if(!i)return [];let r={...i.dependencies,...Object.fromEntries(Object.entries(i.peerDependencies??{}).filter(([a])=>!i.peerDependenciesMeta?.[a]?.optional))};if(Object.keys(r).length===0)return [];let n=Object.keys(r);return (await Promise.all(n.map(async a=>({dep:a,installed:await k(join(t,"node_modules",a))})))).filter(a=>!a.installed).map(a=>a.dep)}a(Ne,"checkMissingDeps");async function $(e,t,i,r){let n=k$1(e,t);if(!(i==="pnpm"||i==="yarn"&&await b$1(e)==="pnpm"))return n;try{let o=await ne(n);if(o!==resolve(n))return d(`[inject] pnpm: resolved symlink \u2192 ${o}`),o}catch(o){c(o)&&o.code!=="ENOENT"&&b.debug(`pnpm symlink resolution error: ${o instanceof Error?o.message:String(o)}`);}let a=join(e,"node_modules",".pnpm");if(await k(a)){d(`[inject] pnpm: scanning .pnpm/ for ${t}`);let o=t.replaceAll("/","+");if(r){let p=`${o}@${r}`,l=join(a,p,"node_modules",t);if(await k(l))return d(`[inject] pnpm: exact version match in .pnpm/ \u2192 ${l}`),l}let g=await readdir(a);for(let p of g)if(p.startsWith(o+"@")){let l=join(a,p,"node_modules",t);if(await k(l))return d(`[inject] pnpm: found in .pnpm/ \u2192 ${l}`),l}}return b.warn(`pnpm: Could not find ${t} in .pnpm/ virtual store, using direct node_modules path. If this causes issues, run 'pnpm install' to rebuild the virtual store, then 'plunk add' again.`),n}a($,"resolveTargetDir");async function ne(e){try{return await stat(e),await realpath(e)}catch(t){if(c(t)&&t.code==="ENOENT")return resolve(e);throw t}}a(ne,"resolveRealPath");async function O(e){try{let t=await readFile(join(e,"package.json"),"utf-8");return JSON.parse(t)}catch(t){return c(t)&&t.code!=="ENOENT"&&b.warn(`Failed to read package.json in ${e}: ${t instanceof Error?t.message:String(t)}`),null}}a(O,"readPackageJson");export{Ee as a,Ce as b,Oe as c,Be as d,Ne as e};
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {a as a$6}from'./chunk-IZRTKGYZ.mjs';import {a as a$8}from'./chunk-7JG555TZ.mjs';import {a as a$7}from'./chunk-AC5FETT7.mjs';import {j,f,d as d$1}from'./chunk-LLVBXPQN.mjs';import {a as a$3}from'./chunk-PVMVWPLG.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {b as b$1}from'./chunk-EMRPZYLU.mjs';import {a as a$2}from'./chunk-MBKCCWSD.mjs';import {a as a$5}from'./chunk-OJJZ7CLB.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a as a$1}from'./chunk-2VCW5RWI.mjs';import {readFile}from'fs/promises';import {join}from'path';globalThis.require=createRequire(import.meta.url);
3
- var E=a(4);async function X(n,i={}){let a=new a$2,e=await a$3(n,{runScripts:i.runScripts,force:i.force});if(e.skipped){b.info("No changes to push");return}let t=await b$1(e.name,e.version);if(!t){a$4(`Failed to read store entry for ${e.name}@${e.version} after publish`);return}let r=await j(e.name);if(r.length===0){b.success(`Published ${e.name}@${e.version} to store`),b.info("No consumers registered yet. Run 'plunk add "+e.name+"' in a consumer project to start receiving pushes."),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:0,failedConsumers:0,copied:0,skipped:0,elapsed:a.elapsedMs()});return}let d$2=0,o=0,l=0,b$2=0,N=await Promise.all(r.map(c=>E(async()=>{let f$1=await f(c,e.name);if(!f$1)return d(`[push] No link found for ${e.name} in ${c}, skipping`),null;try{let m=await a$6(t,c,f$1.packageManager,{force:i.force});return await d$1(c,e.name,{...f$1,contentHash:t.meta.contentHash,linkedAt:new Date().toISOString(),buildId:t.meta.buildId??""}),m}catch(m){return b.warn(`Failed to push to ${c}: ${m instanceof Error?m.message:String(m)}`),null}})));for(let c of N)c?(d$2+=c.copied,o+=c.skipped,l++):b$2++;let M=e.buildId?` [${e.buildId}]`:"";b.success(`Pushed ${e.name}@${e.version}${M} to ${l} consumer(s) in ${a.elapsed()} (${d$2} files changed, ${o} unchanged)`),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:l,failedConsumers:b$2,copied:d$2,skipped:o,elapsed:a.elapsedMs()});}a$1(X,"doPush");function W(n){if(!n)return;let i=parseInt(n,10);return Number.isFinite(i)?i:void 0}a$1(W,"parseMs");async function Y(n,i,a){let{startWatcher:e}=await import('./watcher-J4T66EOT.mjs'),{buildCmd:t,patterns:r}=await F(n,i),d=await e(n,{patterns:r,buildCmd:t,debounce:W(i.debounce),cooldown:W(i.cooldown)},a);await new Promise(o=>{let l=a$1(async()=>{b.info("Stopping watcher..."),await d.close(),o();},"cleanup");process.once("SIGINT",l),process.once("SIGTERM",l);});}a$1(Y,"startWatchMode");async function F(n,i){let a=i.build,e;if(!i.build){if(!i["skip-build"]){let t=await a$7(n),r=await a$8(n,t);r&&(a=r,b.info(`Auto-detected build command: ${r}`));}}if(a){let{exists:t}=await import('./fs-BUNURH4P.mjs'),r=["src","lib","source","app","pages","components"],d$1=(await Promise.all(r.map(async o=>({dir:o,exists:await t(join(n,o))})))).filter(o=>o.exists).map(o=>o.dir);e=d$1.length>0?d$1:["src","lib"],d(`[watch] Using source patterns with build command: ${e.join(", ")}`);}else {b.info("No build command detected \u2014 watching output directories directly");try{let t=JSON.parse(await readFile(join(n,"package.json"),"utf-8"));t.files&&t.files.length>0?(e=t.files,b.info(`Watching from package.json "files": ${e.join(", ")}`)):b.warn('No "files" field in package.json \u2014 falling back to watching src/ and lib/. Add a "files" field or use --build to specify a build command.');}catch(t){d(`[watch] Could not read package.json: ${t instanceof Error?t.message:String(t)}`);}}return {buildCmd:a,patterns:e}}a$1(F,"resolveWatchConfig");export{X as a,Y as b};
2
+ import {createRequire}from'node:module';import {a as a$6}from'./chunk-SMIGYQFG.mjs';import {a as a$8}from'./chunk-7JG555TZ.mjs';import {a as a$7}from'./chunk-AC5FETT7.mjs';import {j,f,d as d$1}from'./chunk-LLVBXPQN.mjs';import {a as a$3}from'./chunk-PVMVWPLG.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {b as b$1}from'./chunk-EMRPZYLU.mjs';import {a as a$2}from'./chunk-MBKCCWSD.mjs';import {a as a$5}from'./chunk-OJJZ7CLB.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a as a$1}from'./chunk-2VCW5RWI.mjs';import {readFile}from'fs/promises';import {join}from'path';globalThis.require=createRequire(import.meta.url);
3
+ var E=a(4);async function X(n,i={}){let a=new a$2,e=await a$3(n,{runScripts:i.runScripts,force:i.force});if(e.skipped){b.info("No changes to push");return}let t=await b$1(e.name,e.version);if(!t){a$4(`Failed to read store entry for ${e.name}@${e.version} after publish`);return}let r=await j(e.name);if(r.length===0){b.success(`Published ${e.name}@${e.version} to store`),b.info("No consumers registered yet. Run 'plunk add "+e.name+"' in a consumer project to start receiving pushes."),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:0,failedConsumers:0,copied:0,skipped:0,elapsed:a.elapsedMs()});return}let d$2=0,o=0,l=0,b$2=0,N=await Promise.all(r.map(c=>E(async()=>{let f$1=await f(c,e.name);if(!f$1)return d(`[push] No link found for ${e.name} in ${c}, skipping`),null;try{let m=await a$6(t,c,f$1.packageManager,{force:i.force});return await d$1(c,e.name,{...f$1,contentHash:t.meta.contentHash,linkedAt:new Date().toISOString(),buildId:t.meta.buildId??""}),m}catch(m){return b.warn(`Failed to push to ${c}: ${m instanceof Error?m.message:String(m)}`),null}})));for(let c of N)c?(d$2+=c.copied,o+=c.skipped,l++):b$2++;let M=e.buildId?` [${e.buildId}]`:"";b.success(`Pushed ${e.name}@${e.version}${M} to ${l} consumer(s) in ${a.elapsed()} (${d$2} files changed, ${o} unchanged)`),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:l,failedConsumers:b$2,copied:d$2,skipped:o,elapsed:a.elapsedMs()});}a$1(X,"doPush");function W(n){if(!n)return;let i=parseInt(n,10);return Number.isFinite(i)?i:void 0}a$1(W,"parseMs");async function Y(n,i,a){let{startWatcher:e}=await import('./watcher-JAR4XGGM.mjs'),{buildCmd:t,patterns:r}=await F(n,i),d=await e(n,{patterns:r,buildCmd:t,debounce:W(i.debounce),cooldown:W(i.cooldown)},a);await new Promise(o=>{let l=a$1(async()=>{b.info("Stopping watcher..."),await d.close(),o();},"cleanup");process.once("SIGINT",l),process.once("SIGTERM",l);});}a$1(Y,"startWatchMode");async function F(n,i){let a=i.build,e;if(!i.build){if(!i["skip-build"]){let t=await a$7(n),r=await a$8(n,t);r&&(a=r,b.info(`Auto-detected build command: ${r}`));}}if(a){let{exists:t}=await import('./fs-BUNURH4P.mjs'),r=["src","lib","source","app","pages","components"],d$1=(await Promise.all(r.map(async o=>({dir:o,exists:await t(join(n,o))})))).filter(o=>o.exists).map(o=>o.dir);e=d$1.length>0?d$1:["src","lib"],d(`[watch] Using source patterns with build command: ${e.join(", ")}`);}else {b.info("No build command detected \u2014 watching output directories directly");try{let t=JSON.parse(await readFile(join(n,"package.json"),"utf-8"));t.files&&t.files.length>0?(e=t.files,b.info(`Watching from package.json "files": ${e.join(", ")}`)):b.warn('No "files" field in package.json \u2014 falling back to watching src/ and lib/. Add a "files" field or use --build to specify a build command.');}catch(t){d(`[watch] Could not read package.json: ${t instanceof Error?t.message:String(t)}`);}}return {buildCmd:a,patterns:e}}a$1(F,"resolveWatchConfig");export{X as a,Y as b};
package/dist/cli.mjs CHANGED
@@ -8,4 +8,4 @@ var o=c(a$1(),1);var r=`
8
8
  \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557
9
9
  \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
10
10
  `;function a(){console.log(o.default.yellow(r)),console.log(o.default.cyan(" \u{1F4E6} Local npm package development without symlinks")),console.log(o.default.dim(` Copies built files into consumer node_modules with incremental sync
11
- `));}a$2(a,"showBanner");process.env.UV_THREADPOOL_SIZE??=String(Math.max(availableParallelism(),8));a$3();var d=process.argv.slice(2),p=d.some(e=>!e.startsWith("-")&&["init","publish","add","remove","push","dev","restore","list","status","update","clean","gc","doctor","migrate"].includes(e));p||a();var u={meta:{name:"plunk",version:"0.5.1",description:"Local npm package development \u2014 copies built files into consumer node_modules"},args:{verbose:{type:"boolean",alias:"v",description:"Enable verbose debug logging",default:false},"dry-run":{type:"boolean",description:"Preview changes without writing files",default:false},json:{type:"boolean",description:"Output machine-readable JSON",default:false}},subCommands:{init:a$2(()=>import('./init-C6XCSFCU.mjs').then(e=>e.default),"init"),publish:a$2(()=>import('./publish-6A7PX5IH.mjs').then(e=>e.default),"publish"),add:a$2(()=>import('./add-32QF7GZO.mjs').then(e=>e.default),"add"),remove:a$2(()=>import('./remove-V3T3XXOY.mjs').then(e=>e.default),"remove"),push:a$2(()=>import('./push-GUFND2MN.mjs').then(e=>e.default),"push"),dev:a$2(()=>import('./dev-ZBELDIBF.mjs').then(e=>e.default),"dev"),restore:a$2(()=>import('./restore-I5W7PTSI.mjs').then(e=>e.default),"restore"),list:a$2(()=>import('./list-QSPN7FE5.mjs').then(e=>e.default),"list"),status:a$2(()=>import('./status-22YV26A3.mjs').then(e=>e.default),"status"),update:a$2(()=>import('./update-NK2BQY7K.mjs').then(e=>e.default),"update"),clean:a$2(()=>import('./clean-F2IWAVRP.mjs').then(e=>e.default),"clean"),gc:a$2(()=>import('./clean-F2IWAVRP.mjs').then(e=>e.default),"gc"),doctor:a$2(()=>import('./doctor-GJGAAT6J.mjs').then(e=>e.default),"doctor"),migrate:a$2(()=>import('./migrate-4TFDXO4G.mjs').then(e=>e.default),"migrate")}};a$4(u);
11
+ `));}a$2(a,"showBanner");process.env.UV_THREADPOOL_SIZE??=String(Math.max(availableParallelism(),8));a$3();var d=process.argv.slice(2),p=d.some(e=>!e.startsWith("-")&&["init","publish","add","remove","push","dev","restore","list","status","update","clean","gc","doctor","migrate"].includes(e));p||a();var u={meta:{name:"plunk",version:"0.6.0",description:"Local npm package development \u2014 copies built files into consumer node_modules"},args:{verbose:{type:"boolean",alias:"v",description:"Enable verbose debug logging",default:false},"dry-run":{type:"boolean",description:"Preview changes without writing files",default:false},json:{type:"boolean",description:"Output machine-readable JSON",default:false}},subCommands:{init:a$2(()=>import('./init-C6XCSFCU.mjs').then(e=>e.default),"init"),publish:a$2(()=>import('./publish-6A7PX5IH.mjs').then(e=>e.default),"publish"),add:a$2(()=>import('./add-GYBX4VAZ.mjs').then(e=>e.default),"add"),remove:a$2(()=>import('./remove-5DAQD627.mjs').then(e=>e.default),"remove"),push:a$2(()=>import('./push-AM6JDGUN.mjs').then(e=>e.default),"push"),dev:a$2(()=>import('./dev-QMDH32K7.mjs').then(e=>e.default),"dev"),restore:a$2(()=>import('./restore-JVH6INAG.mjs').then(e=>e.default),"restore"),list:a$2(()=>import('./list-QSPN7FE5.mjs').then(e=>e.default),"list"),status:a$2(()=>import('./status-22YV26A3.mjs').then(e=>e.default),"status"),update:a$2(()=>import('./update-33ICRFYZ.mjs').then(e=>e.default),"update"),clean:a$2(()=>import('./clean-F2IWAVRP.mjs').then(e=>e.default),"clean"),gc:a$2(()=>import('./clean-F2IWAVRP.mjs').then(e=>e.default),"gc"),doctor:a$2(()=>import('./doctor-GJGAAT6J.mjs').then(e=>e.default),"doctor"),migrate:a$2(()=>import('./migrate-4TFDXO4G.mjs').then(e=>e.default),"migrate")}};a$4(u);
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-BRC4A5PJ.mjs';import'./chunk-IZRTKGYZ.mjs';import'./chunk-7JG555TZ.mjs';import'./chunk-AC5FETT7.mjs';import'./chunk-LLVBXPQN.mjs';import'./chunk-PVMVWPLG.mjs';import'./chunk-HPF6K6WO.mjs';import'./chunk-EMRPZYLU.mjs';import'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import'./chunk-TMH7HIJ2.mjs';import'./chunk-R3RSOZXN.mjs';import'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
2
+ import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-XAVMCPKI.mjs';import'./chunk-SMIGYQFG.mjs';import'./chunk-7JG555TZ.mjs';import'./chunk-AC5FETT7.mjs';import'./chunk-LLVBXPQN.mjs';import'./chunk-PVMVWPLG.mjs';import'./chunk-HPF6K6WO.mjs';import'./chunk-EMRPZYLU.mjs';import'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import'./chunk-TMH7HIJ2.mjs';import'./chunk-R3RSOZXN.mjs';import'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
3
3
  var u={meta:{name:"dev",description:"Watch, rebuild, and push to all consumers. Auto-detects build command."},args:{build:{type:"string",description:"Override build command (default: auto-detect from package.json)"},"skip-build":{type:"boolean",description:"Watch output dirs directly, skip build command detection",default:false},debounce:{type:"string",description:"Debounce delay in ms (default: 500)"},cooldown:{type:"string",description:"Minimum time between builds in ms (default: 500)"},"no-scripts":{type:"boolean",description:"Skip prepack/postpack lifecycle hooks",default:false}},async run({args:e}){b();let t=resolve("."),i=a(()=>a$1(t,{runScripts:!e["no-scripts"]}),"push");await i(),await b$1(t,e,i);}};export{u as default};
package/dist/index.mjs CHANGED
@@ -738,6 +738,7 @@ async function startWatcher(watchDir, options, onChange) {
738
738
  stabilityThreshold: 200,
739
739
  pollInterval: 50
740
740
  };
741
+ const usePolling = !!process.versions?.webcontainer;
741
742
  const watcher = watch(watchPaths, {
742
743
  ignoreInitial: true,
743
744
  ignored: [
@@ -745,7 +746,9 @@ async function startWatcher(watchDir, options, onChange) {
745
746
  "**/.git/**",
746
747
  "**/.plunk/**"
747
748
  ],
748
- awaitWriteFinish: awfOption
749
+ awaitWriteFinish: awfOption,
750
+ usePolling,
751
+ ...usePolling && { interval: 1e3 }
749
752
  });
750
753
  watcher.on("change", onFileEvent);
751
754
  watcher.on("add", onFileEvent);
@@ -1739,7 +1742,6 @@ async function detectAllBundlers(projectDir) {
1739
1742
  // src/utils/bundler-cache.ts
1740
1743
  init_logger();
1741
1744
  var CACHE_DIRS = {
1742
- vite: ["node_modules/.vite"],
1743
1745
  next: [".next/cache"],
1744
1746
  webpack: ["node_modules/.cache"]
1745
1747
  };
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-BRC4A5PJ.mjs';import'./chunk-IZRTKGYZ.mjs';import'./chunk-7JG555TZ.mjs';import'./chunk-AC5FETT7.mjs';import'./chunk-LLVBXPQN.mjs';import'./chunk-PVMVWPLG.mjs';import'./chunk-HPF6K6WO.mjs';import'./chunk-EMRPZYLU.mjs';import'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import'./chunk-TMH7HIJ2.mjs';import'./chunk-R3RSOZXN.mjs';import'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
2
+ import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-XAVMCPKI.mjs';import'./chunk-SMIGYQFG.mjs';import'./chunk-7JG555TZ.mjs';import'./chunk-AC5FETT7.mjs';import'./chunk-LLVBXPQN.mjs';import'./chunk-PVMVWPLG.mjs';import'./chunk-HPF6K6WO.mjs';import'./chunk-EMRPZYLU.mjs';import'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import'./chunk-TMH7HIJ2.mjs';import'./chunk-R3RSOZXN.mjs';import'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
3
3
  var u={meta:{name:"push",description:"Publish and push to all consumers. Use --watch for continuous mode."},args:{watch:{type:"boolean",description:"Watch for changes and auto-push",default:false},build:{type:"string",description:"Build command to run before publishing (watch mode)"},"skip-build":{type:"boolean",description:"Watch output dirs directly, skip build command detection",default:false},debounce:{type:"string",description:"Debounce delay in ms for watch mode (default: 500)"},cooldown:{type:"string",description:"Minimum time between builds in ms (default: 500)"},"no-scripts":{type:"boolean",description:"Skip prepack/postpack lifecycle hooks",default:false},force:{type:"boolean",alias:"f",description:"Force copy all files, bypassing hash comparison",default:false}},async run({args:e}){b();let o=resolve("."),t=a(()=>a$1(o,{runScripts:!e["no-scripts"],force:e.force}),"push");await t(),e.watch&&await b$1(o,e,t);}};export{u as default};
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {b as b$1}from'./chunk-HHV6VEYA.mjs';import {d as d$1,c}from'./chunk-IZRTKGYZ.mjs';import {d as d$2}from'./chunk-AC5FETT7.mjs';import {e,i,a as a$1,f}from'./chunk-LLVBXPQN.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {a as a$2}from'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b as b$2,a as a$3}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {basename,resolve}from'path';globalThis.require=createRequire(import.meta.url);
2
+ import {createRequire}from'node:module';import {b as b$1}from'./chunk-HHV6VEYA.mjs';import {d as d$1,c}from'./chunk-SMIGYQFG.mjs';import {d as d$2}from'./chunk-AC5FETT7.mjs';import {e,i,a as a$1,f}from'./chunk-LLVBXPQN.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {a as a$2}from'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b as b$2,a as a$3}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {basename,resolve}from'path';globalThis.require=createRequire(import.meta.url);
3
3
  var W={meta:{name:"remove",description:"Remove a plunk-linked package and restore the original"},args:{package:{type:"positional",description:"Package name to remove",required:false},all:{type:"boolean",description:"Remove all linked packages",default:false},force:{type:"boolean",description:"Skip error checking",default:false}},async run({args:r}){b$2();let e=new a$2,t=resolve(".");if(r.all){let f=await a$1(t),a=Object.entries(f.links);if(a.length===0){b.info("No linked packages to remove"),a$3({removed:0});return}let i=0,s=0;for(let[p,j]of a)try{await M(t,p,j),i++;}catch(d){s++,b.warn(`Failed to remove ${p}: ${d instanceof Error?d.message:String(d)}`);}b.success(`Removed ${i} plunk link(s)${s>0?`, ${s} failed`:""} in ${e.elapsed()}`),a$3({removed:i,failed:s,elapsed:e.elapsedMs()});return}let o=r.package;o||(a$4("Package name required. Use --all to remove all linked packages."),process.exit(1));let c=await f(t,o);if(!c){if(r.force){b.warn(`Package "${o}" is not linked, skipping`),a$3({removed:0});return}a$4(`Package "${o}" is not linked in this project`),process.exit(1);}await M(t,o,c),b.success(`Removed plunk link for ${o} in ${e.elapsed()}`),a$3({removed:1,package:o,elapsed:e.elapsedMs()});}};async function M(r,e$1,t){if(d(`[remove] Removing ${e$1}`),await d$1(r,e$1,t.packageManager),t.backupExists)try{await c(r,e$1,t.packageManager)&&b.success(`Restored original ${e$1} from backup`);}catch(i){b.warn(`Failed to restore backup for ${e$1}: ${i instanceof Error?i.message:String(i)}. Run your package manager's install command to restore it.`);}let o=await d$2(r);o.type==="next"&&o.configFile&&(await b$1(o.configFile,e$1)).modified&&d(`[remove] Removed ${e$1} from ${basename(o.configFile)}`);let{findTailwindCss:c$1,removeTailwindSource:f}=await import('./tailwind-source-YCRZUHUP.mjs'),a=await c$1(r);if(a&&(await f(a,e$1)).modified&&d(`[remove] Removed @source for ${e$1} from ${basename(a)}`),await e(r,e$1),await i(e$1,r),o.type==="vite"&&o.configFile){let i=await a$1(r);if(Object.keys(i.links).length===0){let{removeFromViteConfig:s}=await import('./vite-config-LXMLHR7V.mjs');(await s(o.configFile)).modified&&d(`[remove] Removed plunk plugin from ${basename(o.configFile)}`);}}}a(M,"removeSinglePackage");export{W as default};
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {a as a$5}from'./chunk-IZRTKGYZ.mjs';import {a as a$3,b as b$1,c}from'./chunk-AC5FETT7.mjs';import {a as a$2,d}from'./chunk-LLVBXPQN.mjs';import {b as b$3}from'./chunk-EMRPZYLU.mjs';import {a as a$1}from'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b,a as a$4}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d as d$1}from'./chunk-R3RSOZXN.mjs';import {b as b$2}from'./chunk-ICCM7US5.mjs';import'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
2
+ import {createRequire}from'node:module';import {a as a$5}from'./chunk-SMIGYQFG.mjs';import {a as a$3,b as b$1,c}from'./chunk-AC5FETT7.mjs';import {a as a$2,d}from'./chunk-LLVBXPQN.mjs';import {b as b$3}from'./chunk-EMRPZYLU.mjs';import {a as a$1}from'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b,a as a$4}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d as d$1}from'./chunk-R3RSOZXN.mjs';import {b as b$2}from'./chunk-ICCM7US5.mjs';import'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
3
3
  var j=a(4),B={meta:{name:"restore",description:"Re-inject all linked packages (use after npm install wipes overrides)"},args:{silent:{type:"boolean",description:"Suppress output when no packages are linked (for postinstall scripts)",default:false}},async run({args:S}){b();let c$1=new a$1,r=resolve("."),v=await a$2(r);if(await a$3(r)==="yarn"){let e=await b$1(r);(e==="pnp"||e===null&&await c(r))&&(b$2.error(`Yarn PnP mode is not compatible with plunk.
4
4
 
5
5
  plunk works by copying files into node_modules/, but PnP eliminates
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {a as a$5}from'./chunk-IZRTKGYZ.mjs';import'./chunk-AC5FETT7.mjs';import {a as a$2,d as d$1}from'./chunk-LLVBXPQN.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {c}from'./chunk-EMRPZYLU.mjs';import {a as a$1}from'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b,a as a$3}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b as b$1}from'./chunk-ICCM7US5.mjs';import'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
2
+ import {createRequire}from'node:module';import {a as a$5}from'./chunk-SMIGYQFG.mjs';import'./chunk-AC5FETT7.mjs';import {a as a$2,d as d$1}from'./chunk-LLVBXPQN.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {c}from'./chunk-EMRPZYLU.mjs';import {a as a$1}from'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b,a as a$3}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b as b$1}from'./chunk-ICCM7US5.mjs';import'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
3
3
  var I=a(4),W={meta:{name:"update",description:"Pull latest versions from the store for linked packages"},args:{package:{type:"positional",description:"Package name to update (default: all linked)",required:false}},async run({args:n}){b();let f=new a$1,a=resolve("."),b$2=await a$2(a),p=Object.entries(b$2.links);if(p.length===0){b$1.info("No linked packages in this project"),a$3({updated:0,skipped:0});return}let k=n.package?p.filter(([t])=>t===n.package):p;n.package&&k.length===0&&(a$4(`Package "${n.package}" is not linked in this project. Run 'plunk list' to see linked packages.`),process.exit(1));let d$2=0,c$1=0,o=0,r=0,E=await Promise.all(k.map(([t,m])=>I(async()=>{let e=await c(t);if(!e)return b$1.warn(`Store entry missing for ${t}. Re-publish it.`),"missing";if(e.meta.contentHash===m.contentHash)return d(`[update] ${t}@${e.version} already up to date`),"skipped";try{let s=await a$5(e,a,m.packageManager),H={...m,version:e.version,contentHash:e.meta.contentHash,buildId:e.meta.buildId??"",linkedAt:new Date().toISOString()};return await d$1(a,t,H),b$1.success(`Updated ${t}@${e.version} (${s.copied} files changed)`),"updated"}catch(s){return b$1.warn(`Failed to update ${t}: ${s instanceof Error?s.message:String(s)}`),"failed"}})));for(let t of E)t==="updated"?d$2++:t==="skipped"?c$1++:t==="missing"?o++:r++;let l=[`${d$2} updated`,`${c$1} unchanged`];o>0&&l.push(`${o} missing`),r>0&&l.push(`${r} failed`),b$1.info(`Update complete: ${l.join(", ")} in ${f.elapsed()}`),a$3({updated:d$2,skipped:c$1,missing:o,failed:r,elapsed:f.elapsedMs()});}};export{W as default};
@@ -127,14 +127,14 @@ function plunkPlugin() {
127
127
  syncPackageWatchers();
128
128
  server.watcher.on("change", async (changedPath) => {
129
129
  const normalizedChanged = normalize(changedPath);
130
- const isStateFile = normalizedChanged === plunkStateFile;
131
- const isLinkedPackage = [...watchedPackages].some(
132
- (pkg) => normalizedChanged.includes(normalize(join(nodeModulesDir, pkg)))
133
- );
134
- if (!isStateFile && !isLinkedPackage) return;
135
- scheduleRestart(
136
- `Detected ${isStateFile ? "state.json" : "package"} change via watcher`
137
- );
130
+ if (normalizedChanged !== plunkStateFile) return;
131
+ const currentPackages = readLinkedPackagesSync(plunkStateFile);
132
+ const hasNew = currentPackages.some((pkg) => !watchedPackages.has(pkg));
133
+ if (!hasNew) {
134
+ console.log("[plunk] state.json changed but no new packages, skipping restart");
135
+ return;
136
+ }
137
+ scheduleRestart("New package linked");
138
138
  });
139
139
  if (process.versions?.webcontainer) {
140
140
  if (pollTimer) clearInterval(pollTimer);
@@ -148,9 +148,13 @@ function plunkPlugin() {
148
148
  const content = readFileSync(plunkStateFile, "utf-8");
149
149
  if (lastStateContent && content !== lastStateContent) {
150
150
  lastStateContent = content;
151
- scheduleRestart(
152
- "Detected state.json change via polling fallback"
151
+ const currentPackages = readLinkedPackagesSync(plunkStateFile);
152
+ const hasNew = currentPackages.some(
153
+ (pkg) => !watchedPackages.has(pkg)
153
154
  );
155
+ if (hasNew) {
156
+ scheduleRestart("New package linked (polling fallback)");
157
+ }
154
158
  }
155
159
  if (!lastStateContent) lastStateContent = content;
156
160
  } catch {
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import {createRequire}from'node:module';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {spawn}from'child_process';import {platform}from'os';globalThis.require=createRequire(import.meta.url);
3
+ var r=null;function E(){r&&!r.killed&&(r.kill("SIGTERM"),r=null);}a(E,"killActiveBuild");async function O(c,n,u){let{watch:m}=await import('./chokidar-LVDD2IK4.mjs'),h=n.patterns??["src","lib"],P=h.map(t=>t.startsWith("/")||t.includes(":")?t:`${c}/${t}`),a$1=n.debounce??500,i=n.cooldown??500,e=null,g=false,w=false,d=0,p=false,T=a(async()=>{if(g||w)return;let t=Date.now()-d;if(!(d>0&&t<i)){w=true,p=false;try{if(n.buildCmd&&!await S(n.buildCmd,c)){b.warn("Build failed (see output above), skipping push");return}await u();}catch(l){b.error(`Push failed: ${l instanceof Error?l.message:String(l)}`);}finally{w=false,d=Date.now(),p&&!g&&(p=false,e=setTimeout(()=>{e=null,T();},i));}}},"doBuild"),b$1=a(t=>{if(g)return;if(w){p=true;return}let l=Date.now()-d;if(d>0&&l<i){e&&clearTimeout(e);let C=i-l;e=setTimeout(()=>{e=null,T();},C+a$1);return}e&&clearTimeout(e),e=setTimeout(()=>{e=null,T();},a$1);},"onFileEvent"),W=n.buildCmd?false:n.awaitWriteFinish??{stabilityThreshold:200,pollInterval:50},y=!!process.versions?.webcontainer,f=m(P,{ignoreInitial:true,ignored:["**/node_modules/**","**/.git/**","**/.plunk/**"],awaitWriteFinish:W,usePolling:y,...y&&{interval:1e3}});f.on("change",b$1),f.on("add",b$1),f.on("unlink",b$1),f.on("error",t=>{b.error(`Watcher error: ${t instanceof Error?t.message:String(t)}`);});let v={close:a(async()=>{g=true,e&&clearTimeout(e),E(),await f.close();},"close")};return b.info(`Watching for changes in: ${h.join(", ")}`),v}a(O,"startWatcher");function S(c,n){return new Promise(u=>{let m=platform()==="win32",h=m?"cmd":"sh",P=m?"/c":"-c";b.start(`Running: ${c}`);let a=spawn(h,[P,c],{cwd:n,stdio:"inherit"});r=a,a.on("close",i=>{r=null,i===0?(b.success("Build succeeded"),u(true)):(b.error(`Build failed with code ${i}`),u(false));}),a.on("error",i=>{r=null,b.error(`Build error: ${i.message}`),u(false);});})}a(S,"runBuildCommand");export{E as killActiveBuild,O as startWatcher};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olegkuibar/plunk",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Local npm package development without symlinks. Copies built files into consumer node_modules with incremental sync and watch mode.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {e,b as b$1}from'./chunk-AC5FETT7.mjs';import {j,k as k$1}from'./chunk-22YCXJTS.mjs';import {c,k,h,i,f,m}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {mkdir,writeFile,rm,symlink,chmod,readdir,stat,realpath,readFile}from'fs/promises';import {join,resolve,sep,relative}from'path';import {platform}from'os';globalThis.require=createRequire(import.meta.url);
3
- function J(e){return e.bin?typeof e.bin=="string"?{[e.name.startsWith("@")?e.name.split("/")[1]:e.name]:e.bin}:e.bin:{}}a(J,"resolveBinEntries");async function L(e,t,i){let r=J(i);if(Object.keys(r).length===0)return 0;let n=join(e,"node_modules",".bin");await mkdir(n,{recursive:true});let c$1=platform()==="win32",a=0;for(let[o,g]of Object.entries(r)){let p=join(e,"node_modules",t),l=join(p,g),B=resolve(l);if(!B.startsWith(resolve(p)+sep)&&B!==resolve(p)){b.warn(`bin "${o}" points outside package directory, skipping`);continue}let h=relative(n,l).replace(/\\/g,"/");if(c$1){let w=join(n,`${o}.cmd`),j=`@ECHO off\r
4
- GOTO start\r
5
- :find_dp0\r
6
- SET dp0=%~dp0\r
7
- EXIT /b\r
8
- :start\r
9
- CALL :find_dp0\r
10
- "%dp0%\\${h.replace(/\//g,"\\")}" %*\r
11
- `;await writeFile(w,j);let G=join(n,o),X=`#!/bin/sh
12
- exec node "${h}" "$@"
13
- `;await writeFile(G,X);}else {let w=join(n,o);try{await rm(w,{force:!0});}catch{}try{await symlink(h,w),await chmod(l,493);}catch(b){if(c(b)&&(b.code==="EPERM"||b.code==="EACCES")){d(`[bin-linker] Symlink failed (${b.code}), using shell wrapper for ${o}`);let j=`#!/bin/sh
14
- exec node "${h}" "$@"
15
- `;await writeFile(w,j),await chmod(w,493);}else throw b}}a++;}return a}a(L,"createBinLinks");async function W(e,t){let i=J(t),r=join(e,"node_modules",".bin"),n=platform()==="win32";for(let c of Object.keys(i))try{await rm(join(r,c),{force:!0}),n&&await rm(join(r,`${c}.cmd`),{force:!0});}catch{}}a(W,"removeBinLinks");var U={vite:["node_modules/.vite"],next:[".next/cache"],webpack:["node_modules/.cache"]},A=new Map;async function F(e$1){let t=A.get(e$1);t||(t=await e(e$1),A.set(e$1,t));for(let i of t){if(!i.type)continue;let r=U[i.type];if(r)for(let n of r){let c=join(e$1,n);if(await k(c))try{await h(c),d(`[inject] Invalidated ${i.type} cache: ${n}`);}catch{d(`[inject] Could not clear ${i.type} cache: ${n} (locked?)`);}}}}a(F,"invalidateBundlerCache");async function Ee(e,t,i$1,r={}){let n=await $(t,e.name,i$1,e.version);d(`[inject] ${e.name}@${e.version} \u2192 ${n}`),await i(n);let{copied:c,removed:a,skipped:o}=await f(e.packageDir,n,{force:r.force});d(`[inject] ${c} copied, ${a} removed, ${o} skipped`),(c>0||a>0)&&await F(t);let g=await O(e.packageDir),p=g?await L(t,e.name,g):0;return p>0&&d(`[inject] Created ${p} bin link(s)`),{copied:c,removed:a,skipped:o,binLinks:p}}a(Ee,"inject");async function Ce(e,t,i){let r=await $(e,t,i);if(!await k(r))return false;let n=j(e,t);return await h(n),await m(r,n),true}a(Ce,"backupExisting");async function Oe(e,t,i){let r=j(e,t);if(!await k(r))return false;let n=await $(e,t,i);return await h(n),await m(r,n),await h(r),true}a(Oe,"restoreBackup");async function Be(e,t,i){let r=await $(e,t,i),n=await O(r);n&&await W(e,n),await h(r);}a(Be,"removeInjected");async function _e(e,t){let i=await O(e.packageDir);if(!i)return [];let r={...i.dependencies,...Object.fromEntries(Object.entries(i.peerDependencies??{}).filter(([a])=>!i.peerDependenciesMeta?.[a]?.optional))};if(Object.keys(r).length===0)return [];let n=Object.keys(r);return (await Promise.all(n.map(async a=>({dep:a,installed:await k(join(t,"node_modules",a))})))).filter(a=>!a.installed).map(a=>a.dep)}a(_e,"checkMissingDeps");async function $(e,t,i,r){let n=k$1(e,t);if(!(i==="pnpm"||i==="yarn"&&await b$1(e)==="pnpm"))return n;try{let o=await ne(n);if(o!==resolve(n))return d(`[inject] pnpm: resolved symlink \u2192 ${o}`),o}catch(o){c(o)&&o.code!=="ENOENT"&&b.debug(`pnpm symlink resolution error: ${o instanceof Error?o.message:String(o)}`);}let a=join(e,"node_modules",".pnpm");if(await k(a)){d(`[inject] pnpm: scanning .pnpm/ for ${t}`);let o=t.replaceAll("/","+");if(r){let p=`${o}@${r}`,l=join(a,p,"node_modules",t);if(await k(l))return d(`[inject] pnpm: exact version match in .pnpm/ \u2192 ${l}`),l}let g=await readdir(a);for(let p of g)if(p.startsWith(o+"@")){let l=join(a,p,"node_modules",t);if(await k(l))return d(`[inject] pnpm: found in .pnpm/ \u2192 ${l}`),l}}return b.warn(`pnpm: Could not find ${t} in .pnpm/ virtual store, using direct node_modules path. If this causes issues, run 'pnpm install' to rebuild the virtual store, then 'plunk add' again.`),n}a($,"resolveTargetDir");async function ne(e){try{return await stat(e),await realpath(e)}catch(t){if(c(t)&&t.code==="ENOENT")return resolve(e);throw t}}a(ne,"resolveRealPath");async function O(e){try{let t=await readFile(join(e,"package.json"),"utf-8");return JSON.parse(t)}catch(t){return c(t)&&t.code!=="ENOENT"&&b.warn(`Failed to read package.json in ${e}: ${t instanceof Error?t.message:String(t)}`),null}}a(O,"readPackageJson");export{Ee as a,Ce as b,Oe as c,Be as d,_e as e};
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import {createRequire}from'node:module';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {spawn}from'child_process';import {platform}from'os';globalThis.require=createRequire(import.meta.url);
3
- var o=null;function k(){o&&!o.killed&&(o.kill("SIGTERM"),o=null);}a(k,"killActiveBuild");async function M(c,n,u){let{watch:m}=await import('./chokidar-LVDD2IK4.mjs'),h=n.patterns??["src","lib"],T=h.map(t=>t.startsWith("/")||t.includes(":")?t:`${c}/${t}`),a$1=n.debounce??500,i=n.cooldown??500,e=null,g=false,w=false,d=0,p=false,y=a(async()=>{if(g||w)return;let t=Date.now()-d;if(!(d>0&&t<i)){w=true,p=false;try{if(n.buildCmd&&!await E(n.buildCmd,c)){b.warn("Build failed (see output above), skipping push");return}await u();}catch(s){b.error(`Push failed: ${s instanceof Error?s.message:String(s)}`);}finally{w=false,d=Date.now(),p&&!g&&(p=false,e=setTimeout(()=>{e=null,y();},i));}}},"doBuild"),P=a(t=>{if(g)return;if(w){p=true;return}let s=Date.now()-d;if(d>0&&s<i){e&&clearTimeout(e);let C=i-s;e=setTimeout(()=>{e=null,y();},C+a$1);return}e&&clearTimeout(e),e=setTimeout(()=>{e=null,y();},a$1);},"onFileEvent"),W=n.buildCmd?false:n.awaitWriteFinish??{stabilityThreshold:200,pollInterval:50},f=m(T,{ignoreInitial:true,ignored:["**/node_modules/**","**/.git/**","**/.plunk/**"],awaitWriteFinish:W});f.on("change",P),f.on("add",P),f.on("unlink",P),f.on("error",t=>{b.error(`Watcher error: ${t instanceof Error?t.message:String(t)}`);});let b$1={close:a(async()=>{g=true,e&&clearTimeout(e),k(),await f.close();},"close")};return b.info(`Watching for changes in: ${h.join(", ")}`),b$1}a(M,"startWatcher");function E(c,n){return new Promise(u=>{let m=platform()==="win32",h=m?"cmd":"sh",T=m?"/c":"-c";b.start(`Running: ${c}`);let a=spawn(h,[T,c],{cwd:n,stdio:"inherit"});o=a,a.on("close",i=>{o=null,i===0?(b.success("Build succeeded"),u(true)):(b.error(`Build failed with code ${i}`),u(false));}),a.on("error",i=>{o=null,b.error(`Build error: ${i.message}`),u(false);});})}a(E,"runBuildCommand");export{k as killActiveBuild,M as startWatcher};